diff --git a/container_engine/django_tutorial/.dockerignore b/container_engine/django_tutorial/.dockerignore new file mode 100644 index 000000000000..721c69878d7d --- /dev/null +++ b/container_engine/django_tutorial/.dockerignore @@ -0,0 +1,20 @@ +.dockerignore +Dockerfile +db.sqlite3 +__pycache__ +*.pyc +*.pyo +*.pyd +.Python +env +pip-log.txt +pip-delete-this-directory.txt +.tox +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +*.log +.git diff --git a/container_engine/django_tutorial/.gitignore b/container_engine/django_tutorial/.gitignore new file mode 100644 index 000000000000..980c85122dba --- /dev/null +++ b/container_engine/django_tutorial/.gitignore @@ -0,0 +1 @@ +static/ diff --git a/container_engine/django_tutorial/Dockerfile b/container_engine/django_tutorial/Dockerfile new file mode 100644 index 000000000000..5d223d0bac17 --- /dev/null +++ b/container_engine/django_tutorial/Dockerfile @@ -0,0 +1,32 @@ +# Copyright 2015, Google, Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# [START docker] + +# The Google App Engine python runtime is Debian Jessie with Python installed +# and various os-level packages to allow installation of popular Python +# libraries. The source is on github at: +# https://github.com/GoogleCloudPlatform/python-docker +FROM gcr.io/google_appengine/python + +# Create a virtualenv for the application dependencies. +# # If you want to use Python 3, add the -p python3.4 flag. +RUN virtualenv /env +ENV PATH /env/bin:$PATH + +ADD requirements.txt /app/requirements.txt +RUN /env/bin/pip install -r /app/requirements.txt +ADD . /app + +CMD gunicorn -b :$PORT mysite.wsgi +# [END docker] diff --git a/container_engine/django_tutorial/Makefile b/container_engine/django_tutorial/Makefile new file mode 100644 index 000000000000..8941baa4d3b5 --- /dev/null +++ b/container_engine/django_tutorial/Makefile @@ -0,0 +1,39 @@ +GCLOUD_PROJECT:=$(shell gcloud config list project --format="value(core.project)") + +.PHONY: all +all: deploy + +.PHONY: create-cluster +create-cluster: + gcloud container clusters create polls \ + --scope "https://www.googleapis.com/auth/userinfo.email","cloud-platform" + +.PHONY: create-bucket +create-bucket: + gsutil mb gs://$(GCLOUD_PROJECT) + gsutil defacl set public-read gs://$(GCLOUD_PROJECT) + +.PHONY: build +build: + docker build -t gcr.io/$(GCLOUD_PROJECT)/polls . + +.PHONY: push +push: build + gcloud docker push gcr.io/$(GCLOUD_PROJECT)/polls + +.PHONY: template +template: + sed -i ".tmpl" "s/\$$GCLOUD_PROJECT/$(GCLOUD_PROJECT)/g" polls.yaml + +.PHONY: deploy +deploy: push template + kubectl create -f polls.yaml + +.PHONY: update +update: + kubectl rolling-update polls --image=gcr.io/${GCLOUD_PROJECT}/polls + +.PHONY: delete +delete: + kubectl delete rc polls + kubectl delete service polls diff --git a/container_engine/django_tutorial/README.md b/container_engine/django_tutorial/README.md new file mode 100644 index 000000000000..ccf151349282 --- /dev/null +++ b/container_engine/django_tutorial/README.md @@ -0,0 +1,197 @@ +# Getting started with Django on Google Container Engine + +This repository is an example of how to run a [Django](https://www.djangoproject.com/) +app on Google Container Engine. It uses the [Writing your first Django app](https://docs.djangoproject.com/en/1 +.9/intro/tutorial01/) Polls application as the example app to deploy. From here on out, we refer to this app as +the 'polls' application. + +## Pre-requisites + +1. Create a project in the [Google Cloud Platform Console](https://console.cloud.google.com). + +2. [Enable billing](https://console.cloud.google.com/project/_/settings) for your project. + +3. [Enable APIs](https://console.cloud.google.com/flows/enableapi?apiid=datastore,pubsub,storage_api,logging,plus) for your project. The provided link will enable all necessary APIs, but if you wish to do so manually you will need Datastore, Pub/Sub, Storage, and Logging. + +4. Install the [Google Cloud SDK](https://cloud.google.com/sdk) + + $ curl https://sdk.cloud.google.com | bash + $ gcloud init + +5. Install [Docker](https://www.docker.com/). + +## Makefile + +Several commands listed below are provided in simpler form via the Makefile. Many of them use the GCLOUD_PROJECT +environment variable, which will be picked up from your gcloud config. Make sure you set this to the correct project, + + gcloud config set project + +### Create a cluster + +Create a cluster for the bookshelf application: + + gcloud container clusters create bookshelf \ + --scope "https://www.googleapis.com/auth/userinfo.email","cloud-platform" \ + --num-nodes 2 + gcloud container clusters get-credentials bookshelf + +The scopes specified in the `--scope` argument allows nodes in the cluster to access Google Cloud Platform APIs, such as the Cloud Datastore API. + +### Create a Cloud Storage bucket + +The bookshelf application uses [Google Cloud Storage](https://cloud.google.com/storage) to store image files. Create a bucket for your project: + + gsutil mb gs:// + gsutil defacl set public-read gs:// + + +## Setup the database + +This tutorial assumes you are setting up Django using a SQL database, which is the easiest way to run Django. If you have an existing SQL database running, you can use that, but if not, these are the instructions for creating a managed MySQL instance using CloudSQL. + + +* Create a [CloudSQL instance](https://console.cloud.google.com/project/_/sql/create) + + * In the instances list, click your Cloud SQL instance. + + * Click Access Control. + + * In the IP address subsection, click Request an IPv4 address to enable access to the Cloud SQL instance through an + IPv4 address. It will take a moment to initialize the new IP address. + + * Also under Access Control, in the Authorization subsection, under Allowed Networks, click the add (+) button . + + * In the Networks field, enter 0.0.0.0/0. This value allows access by all IP addresses. + + * Click Save. + +Note: setting allowed networks to 0.0.0.0/0 opens your SQL instance to traffic from any computer. For production databases, it's highly recommended to limit the authorized networks to only IP ranges that need access. + +* Alternatively, the instance can be created with the gcloud command line tool as follows, substituting `your-root-pw + with a strong, unique password. + + `gcloud sql instances create --assign-ip --authorized-networks=0.0.0.0/0 set-root-password=your-root-pw` + +* Create a Database And User + + * Using the root password created in the last step to create a new database, user, and password using your preferred MySQL client. Alternatively, follow these instructions to create the database and user from the console. + * From the CloudSQL instance in the console, click New user. + * Enter a username and password for the application. For example, name the user "pythonapp" and give it a randomly + generated password. + * Click Add. + * Click Databases and then click New database. + * For Name, enter the name of your database (for example, "polls"), and click Add. + +Once you have a SQL host, configuring mysite/settings.py to point to your database. Change `your-database-name`, +`your-database-user`, `your-database-host` , and `your-database-password` to match the settings created above. Note the +instance name is not used in this configuration, and the host name is the IP address you created. + + +## Running locally + +First make sure you have Django installed. It's recommended you do so in a +[virtualenv](https://virtualenv.pypa.io/en/latest/). The requirements.txt +contains just the Django dependency. + + pip install -r requirements.txt + +Once the database is setup, run the migrations. + + python manage.py migrate + +If you'd like to use the admin console, create a superuser. + + python manage.py createsuperuser + +The app can be run locally the same way as any other Django app. + + python manage.py runserver + +Now you can view the admin panel of your local site at + + http://localhost:8080/admin + +# Deploying To Google Container Engine (Kubernetes) + +## Build the polls container + +Before the application can be deployed to Container Engine, you will need build and push the image to [Google Container Registry](https://cloud.google.com/container-registry/). + + docker build -t gcr.io/your-project-id/polls . + gcloud docker push gcr.io/your-project-id/polls + +Alternatively, this can be done using + + make push + + +## Deploy to the application + +### Serve the static content + +Collect all the static assets into the static/ folder. + + python manage.py collectstatic + +When DEBUG is enabled, Django can serve the files directly from that folder. For production purposes, you should +serve static assets from a CDN. Here are instructions for how to do this using Google Cloud Storage. + +Upload it to CloudStorage using the `gsutil rsync` command + + gsutil rsync -R static/ gs:///static + +Now your static content can be served from the following URL: + + http://storage.googleapis.com/` + +### Create the Kubernetes resources + +This application is represented in a single Kubernetes config, called `polls`. First, replace the +GCLOUD_PROJECT in `polls.yaml` with your project ID. Alternatively, run `make template` with your +GCLOUD_PROJECT environment variable set. + + kubectl create -f polls.yaml + +Alternatively this create set can be done using the Makefile + + make deploy + +Once the resources are created, there should be 3 `polls` pods on the cluster. To see the pods and ensure that +they are running: + + kubectl get pods + +If the pods are not ready or if you see restarts, you can get the logs for a particular pod to figure out the issue: + + kubectl logs pod-id + +Once the pods are ready, you can get the public IP address of the load balancer: + + kubectl get services polls + +You can then browse to the public IP address in your browser to see the bookshelf application. + +When you are ready to update the replication controller with a new image you built, the following command will do a +rolling update + + kubectl rolling-update polls --image=gcr.io/${GCLOUD_PROJECT}/polls + +which can also be done with the `make update` command. + + +## Issues + +Please use the Issue Tracker for any issues or questions. + +## Contributing changes + +* See [CONTRIBUTING.md](CONTRIBUTING.md) + + +## Licensing + +* See [LICENSE](LICENSE) diff --git a/container_engine/django_tutorial/__init__.py b/container_engine/django_tutorial/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/container_engine/django_tutorial/manage.py b/container_engine/django_tutorial/manage.py new file mode 100755 index 000000000000..2062ecd2666d --- /dev/null +++ b/container_engine/django_tutorial/manage.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python +# Copyright 2015 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") + + from django.core.management import execute_from_command_line + + execute_from_command_line(sys.argv) diff --git a/container_engine/django_tutorial/mysite/__init__.py b/container_engine/django_tutorial/mysite/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/container_engine/django_tutorial/mysite/settings.py b/container_engine/django_tutorial/mysite/settings.py new file mode 100644 index 000000000000..1a16d7693b53 --- /dev/null +++ b/container_engine/django_tutorial/mysite/settings.py @@ -0,0 +1,111 @@ +# Copyright 2015 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +import os + +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'pf-@jxtojga)z+4s*uwbgjrq$aep62-thd0q7f&o77xtpka!_m' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + +# Application definition + +INSTALLED_APPS = ( + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'polls' +) + +MIDDLEWARE_CLASSES = ( + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'django.middleware.security.SecurityMiddleware', +) + +ROOT_URLCONF = 'mysite.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'mysite.wsgi.application' + +# Database +# https://docs.djangoproject.com/en/1.8/ref/settings/#databases + +# [START dbconfig] +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'polls', + 'USER': 'django_user', + 'PASSWORD': 'django', + 'HOST': '173.194.104.255', + 'PORT': '3306', + } +} +# [END dbconfig] + +# Internationalization +# https://docs.djangoproject.com/en/1.8/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.8/howto/static-files/ + +# [START staticurl] +STATIC_URL = '/static/' +# STATIC_URL = 'https://storage.googleapis.com//static/' +# [END staticurl] + +STATIC_ROOT = 'static/' diff --git a/container_engine/django_tutorial/mysite/urls.py b/container_engine/django_tutorial/mysite/urls.py new file mode 100644 index 000000000000..a312d05bb091 --- /dev/null +++ b/container_engine/django_tutorial/mysite/urls.py @@ -0,0 +1,26 @@ +# Copyright 2015 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from django.conf import settings +from django.conf.urls import include, url +from django.contrib.staticfiles.urls import staticfiles_urlpatterns + +urlpatterns = [ + url(r'^', include('polls.urls')), +] + +# Only serve static files from Django during development +# Use Google Cloud Storage or an alternative CDN for production +if settings.DEBUG: + urlpatterns += staticfiles_urlpatterns() diff --git a/container_engine/django_tutorial/mysite/wsgi.py b/container_engine/django_tutorial/mysite/wsgi.py new file mode 100644 index 000000000000..bd3a0d0c2b71 --- /dev/null +++ b/container_engine/django_tutorial/mysite/wsgi.py @@ -0,0 +1,22 @@ +# Copyright 2015 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") + +application = get_wsgi_application() diff --git a/container_engine/django_tutorial/polls.yaml b/container_engine/django_tutorial/polls.yaml new file mode 100644 index 000000000000..5a19a02112f4 --- /dev/null +++ b/container_engine/django_tutorial/polls.yaml @@ -0,0 +1,74 @@ +# Copyright 2015 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License + +# This file configures the polls application . The frontend serves +# public web traffic. + +# The bookshelf frontend replication controller ensures that at least 3 +# instances of the bookshelf app are running on the cluster. +# For more info about Pods see: +# https://cloud.google.com/container-engine/docs/pods/ +# For more info about Replication Controllers: +# https://cloud.google.com/container-engine/docs/replicationcontrollers/ + +# [START replication_controller] +apiVersion: v1 +kind: ReplicationController +metadata: + name: polls + labels: + app: polls +spec: + replicas: 3 + template: + metadata: + labels: + app: polls + spec: + containers: + - name: polls-app + # Replace with your project ID or use `make template` + image: gcr.io/$GCLOUD_PROJECT/polls + # This setting makes nodes pull the docker image every time before + # starting the pod. This is useful when debugging, but should be turned + # off in production. + imagePullPolicy: Always + ports: + - containerPort: 8080 +# [END replication_controller] + +--- + +# [START service] +# The polls service provides a load-balancing proxy over the polls app +# pods. By specifying the type as a 'LoadBalancer', Container Engine will +# create an external HTTP load balancer. +# For more information about Services see: +# https://cloud.google.com/container-engine/docs/services/ +# For more information about external HTTP load balancing see: +# https://cloud.google.com/container-engine/docs/load-balancer +apiVersion: v1 +kind: Service +metadata: + name: polls + labels: + app: polls +spec: + type: LoadBalancer + ports: + - port: 80 + targetPort: 8080 + selector: + app: polls +# [END service] diff --git a/container_engine/django_tutorial/polls/__init__.py b/container_engine/django_tutorial/polls/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/container_engine/django_tutorial/polls/admin.py b/container_engine/django_tutorial/polls/admin.py new file mode 100644 index 000000000000..b826b162d14a --- /dev/null +++ b/container_engine/django_tutorial/polls/admin.py @@ -0,0 +1,18 @@ +# Copyright 2015 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from django.contrib import admin +from .models import Question + +admin.site.register(Question) diff --git a/container_engine/django_tutorial/polls/apps.py b/container_engine/django_tutorial/polls/apps.py new file mode 100644 index 000000000000..6f98d05c893f --- /dev/null +++ b/container_engine/django_tutorial/polls/apps.py @@ -0,0 +1,19 @@ +# Copyright 2015 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from django.apps import AppConfig + + +class PollsConfig(AppConfig): + name = 'polls' diff --git a/container_engine/django_tutorial/polls/migrations/0001_initial.py b/container_engine/django_tutorial/polls/migrations/0001_initial.py new file mode 100644 index 000000000000..2ae7f95ca7f5 --- /dev/null +++ b/container_engine/django_tutorial/polls/migrations/0001_initial.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2015-12-28 23:27 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Choice', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('choice_text', models.CharField(max_length=200)), + ('votes', models.IntegerField(default=0)), + ], + ), + migrations.CreateModel( + name='Question', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('question_text', models.CharField(max_length=200)), + ('pub_date', models.DateTimeField(verbose_name=b'date published')), + ], + ), + migrations.AddField( + model_name='choice', + name='question', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='polls.Question'), + ), + ] diff --git a/container_engine/django_tutorial/polls/migrations/__init__.py b/container_engine/django_tutorial/polls/migrations/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/container_engine/django_tutorial/polls/models.py b/container_engine/django_tutorial/polls/models.py new file mode 100644 index 000000000000..c38f6e55c06c --- /dev/null +++ b/container_engine/django_tutorial/polls/models.py @@ -0,0 +1,28 @@ +# Copyright 2015 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from django.db import models + + +class Question(models.Model): + question_text = models.CharField(max_length=200) + pub_date = models.DateTimeField('date published') + + +class Choice(models.Model): + question = models.ForeignKey(Question, on_delete=models.CASCADE) + choice_text = models.CharField(max_length=200) + votes = models.IntegerField(default=0) + +# Create your models here. diff --git a/container_engine/django_tutorial/polls/tests.py b/container_engine/django_tutorial/polls/tests.py new file mode 100644 index 000000000000..47c4805ea486 --- /dev/null +++ b/container_engine/django_tutorial/polls/tests.py @@ -0,0 +1,17 @@ +# Copyright 2015 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from django.test import TestCase + +# Create your tests here. diff --git a/container_engine/django_tutorial/polls/urls.py b/container_engine/django_tutorial/polls/urls.py new file mode 100644 index 000000000000..357f4610fb79 --- /dev/null +++ b/container_engine/django_tutorial/polls/urls.py @@ -0,0 +1,23 @@ +# Copyright 2015 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from django.conf.urls import url +from django.contrib import admin + +from . import views + +urlpatterns = [ + url(r'^$', views.index, name='index'), + url(r'^admin/', admin.site.urls) +] diff --git a/container_engine/django_tutorial/polls/views.py b/container_engine/django_tutorial/polls/views.py new file mode 100644 index 000000000000..acc5671ba625 --- /dev/null +++ b/container_engine/django_tutorial/polls/views.py @@ -0,0 +1,19 @@ +# Copyright 2015 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from django.http import HttpResponse + + +def index(request): + return HttpResponse("Hello, world. You're at the polls index.") diff --git a/container_engine/django_tutorial/requirements.txt b/container_engine/django_tutorial/requirements.txt new file mode 100644 index 000000000000..89beda5ab824 --- /dev/null +++ b/container_engine/django_tutorial/requirements.txt @@ -0,0 +1,4 @@ +Django==1.9 +MySQL-python==1.2.5 +wheel==0.24.0 +gunicorn==19.3.0