Skip to content

Commit f2a24af

Browse files
authored
Upgrade to Python 3 (#210)
* try to upgrade python 3 Signed-off-by: Niket <[email protected]> * remove login admin restriction to see if it works Signed-off-by: Niket <[email protected]> * add script auto Signed-off-by: Niket <[email protected]> * remove stringIO Signed-off-by: Niket <[email protected]> * use string IO in python 3 Signed-off-by: Niket <[email protected]> * fix syntax error Signed-off-by: Niket <[email protected]> * use BytesIO in python3 Signed-off-by: Niket <[email protected]> * Replace cStringIO import with io * Import gaerpytz directly, update it and move files to lib * Remove removal of _sass.so * Remove reports * Remove application_readable from app.yaml * Replace skip-files with gcloudignore file * Make app.yaml runtime Python 3.7 * Remove dot * Remove mail/weekly (test) * Use new VPC network Signed-off-by: Niket <[email protected]> * Merge branch 'python_3' of https://github.com/ocadotechnology/codeforlife-deploy-appengine into python_3 * require django Signed-off-by: Niket <[email protected]> * fix requirements.txt Signed-off-by: Niket <[email protected]> * put cfl apps in requirements file Signed-off-by: Niket <[email protected]> * install mysqlclient Signed-off-by: Niket <[email protected]> * change main.py to set django application variable to ‘app’ Signed-off-by: Niket <[email protected]> * use double quotes for secrets Signed-off-by: Niket <[email protected]> * no build sh Signed-off-by: Niket <[email protected]> * install aimmo Signed-off-by: Niket <[email protected]> * put back build.sh for now Signed-off-by: Niket <[email protected]> * rearrange things in app yaml tmpl Signed-off-by: Niket <[email protected]> * test if removing the secret makes the other env variables work Signed-off-by: Niket <[email protected]> * double quotes Signed-off-by: Niket <[email protected]> * formatting Signed-off-by: Niket <[email protected]> * go back to single quotes Signed-off-by: Niket <[email protected]> * use handlers in the demo app to see if they were the ast issue Signed-off-by: Niket Shah <[email protected]> * Revert to single quotes again * remove empty env variable Signed-off-by: Niket Shah <[email protected]> * use double quotes with single quotes with env var causing error * add django secret back Signed-off-by: Niket Shah <[email protected]> * fix the “if on google appengine” check Signed-off-by: Niket Shah <[email protected]> * disable email backend for now Signed-off-by: Niket Shah <[email protected]> * use redis for caching Signed-off-by: Niket Shah <[email protected]> * fix syntax error in settings.py Signed-off-by: Niket Shah <[email protected]> * use normal string for redis location Signed-off-by: Niket Shah <[email protected]> * use normal string for redix location Signed-off-by: Niket Shah <[email protected]> * remove explicit mentions of our app in the requirements folder use build.sh instead Signed-off-by: Niket Shah <[email protected]> * add apps in requirements back in Signed-off-by: Niket Shah <[email protected]> * remove quotes in the string Signed-off-by: Niket <[email protected]> * print module name env var Signed-off-by: Niket Shah <[email protected]> * use quotes again for ast.literal_eval Signed-off-by: Niket Shah <[email protected]> * Test removing lib-specific installs * use GAE_SERVICE instead of DJANGO_MODULE_NAME Signed-off-by: Niket <[email protected]> * Merge branch 'python_3' of https://github.com/ocadotechnology/codeforlife-deploy-appengine into python_3 * Revert back to lib installs * Merge branch 'python_3' of https://github.com/ocadotechnology/codeforlife-deploy-appengine into python_3 * Try single quotes on GAE_SERVICE * Remove requirements.txt to see what the error is * Try from lib import * Add __init__.py to lib folder * Bring back requirements * Test to see if requirements generation works * Trying lib again * Remove last new line * Add requirements.txt to .gitignore * Fix versions for other packages * Specify patch versions to test if fixes invalid argument * Fix syntax error * Remove echoes * Comment out gaerpytz step to see if deployment still works * Remove gaerpytz * Remove requirements.txt that was added to git before gitignore * Use Redis IP and PORT env vars * Remove Nones * Export env vars * Declare variables in app.yaml.tmpl * Setup Amazon SES * Add comma in INSTALLED_APPS * Add anymail to requirements * Put anymail back in lib * Add region to AWS config * Fix format of region setting * Move Anymail settings before email backend setting * Move credentials to anymail dict * Enable Debugger agents * Try adding credentials outside of dict too * Setup boto client with credentials * Add env vars to app.yaml.tmpl * Cleanup unnecessary code * Ignore files and folders starting with . * Remove EMAIL_QUEUE_NAME setting
1 parent f6bce51 commit f2a24af

12 files changed

+78
-127
lines changed

.gcloudignore

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.*
2+
*.scss
3+
*#
4+
*~
5+
*.pyc
6+
*.pyo
7+
lib/*info/**
8+
lib/PIL/**
9+
lib/setuptools/script (dev).tmpl
10+
lib/**/static/**

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
app.yaml
22
lib
33
static
4-
4+
requirements.txt
55
\.idea/

app.yaml.tmpl

+20-85
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,38 @@
1-
runtime: python27
1+
runtime: python37
22
instance_class: F4
3-
api_version: 1
4-
threadsafe: true
53
service: ${MODULE_NAME}
64

7-
handlers:
8-
- url: /favicon\.ico
9-
static_files: static/portal/img/favicon.ico
10-
upload: static/portal/img/favicon\.ico
11-
12-
- url: /robots\.txt
13-
static_files: static/robots.txt
14-
upload: static/robots\.txt
15-
16-
- url: /apple-touch-icon\.png
17-
static_files: static/apple-touch-icon.png
18-
upload: static/apple-touch-icon\.png
19-
20-
- url: /apple-touch-icon-76x76\.png
21-
static_files: static/apple-touch-icon-76x76.png
22-
upload: static/apple-touch-icon-76x76\.png
23-
24-
- url: /apple-touch-icon-120x120\.png
25-
static_files: static/apple-touch-icon-120x120.png
26-
upload: static/apple-touch-icon-120x120\.png
27-
28-
- url: /apple-touch-icon-152x152\.png
29-
static_files: static/apple-touch-icon-152x152.png
30-
upload: static/apple-touch-icon-152x152\.png
31-
32-
- url: /apple-touch-icon-180x180\.png
33-
static_files: static/apple-touch-icon-180x180.png
34-
upload: static/apple-touch-icon-180x180\.png
35-
36-
- url: /static
37-
static_dir: static
38-
application_readable: true
39-
secure: always
40-
41-
- url: /_ah/stats.*
42-
script: google.appengine.ext.appstats.ui.app
43-
secure: always
5+
vpc_access_connector:
6+
name: "projects/decent-digit-629/locations/europe-west1/connectors/cfl-connector"
447

45-
- url: /mail/weekly
46-
script: main.application
47-
login: admin
48-
secure: always
49-
50-
- url: /aimmo/api/.*
51-
script: main.application
52-
secure: always
8+
handlers:
9+
# This configures Google App Engine to serve the files in the app's static
10+
# directory.
11+
- url: /static
12+
static_dir: static/
5313

54-
- url: /api/.*
55-
script: main.application
56-
login: admin
57-
secure: always
14+
# This handler routes all requests not caught above to your main app. It is
15+
# required when static routes are defined, but can be omitted (along with
16+
# the entire handlers section) when there are no static files defined.
17+
- url: /.*
18+
script: auto
5819

59-
- url: /.*
60-
script: main.application
61-
secure: always
20+
inbound_services:
21+
- warmup
6222

6323
env_variables:
6424
DJANGO_SETTINGS_MODULE: 'django_site.settings'
6525
HTTPS: 'on'
6626
CACHE_PREFIX: '${CACHE_PREFIX}'
6727
DATABASE_NAME: '${DATABASE_NAME}'
68-
DJANGO_SECRET: '${DJANGO_SECRET}'
6928
RECAPTCHA_PRIVATE_KEY: '${RECAPTCHA_PRIVATE_KEY}'
7029
RECAPTCHA_PUBLIC_KEY: '${RECAPTCHA_PUBLIC_KEY}'
7130
DJANGO_PORTAL_CONTACT_FORM_EMAIL: '${DJANGO_PORTAL_CONTACT_FORM_EMAIL}'
72-
DJANGO_CREATOR_AUTH_TOKEN: '${DJANGO_CREATOR_AUTH_TOKEN}'
7331
DJANGO_SALESFORCE_URL: '${DJANGO_SALESFORCE_URL}'
7432
DJANGO_SALESFORCE_OID: '${DJANGO_SALESFORCE_OID}'
7533
DJANGO_SALESFORCE_RT: '${DJANGO_SALESFORCE_RT}'
76-
DJANGO_MODULE_NAME: '${MODULE_NAME}'
77-
78-
libraries:
79-
- name: MySQLdb
80-
version: latest
81-
- name: ssl
82-
version: latest
83-
- name: PIL
84-
version: latest
85-
86-
builtins:
87-
- appstats: on
88-
89-
inbound_services:
90-
- warmup
91-
92-
skip_files:
93-
- ^(.*/)?.*\.scss$
94-
- ^(.*/)?#.*#$
95-
- ^(.*/)?.*~$
96-
- ^(.*/)?.*\.py[co]$
97-
- ^(.*/)?.*unity\/Development\/.*$
98-
- ^(.*/)?.*/RCS/.*$
99-
- ^(.*/)?\..*$
100-
- ^lib\/.*info$
101-
- ^lib\/PIL
102-
- ^lib\/setuptools\/script.*dev.*.tmpl
103-
- ^lib\/.*/static/.*$
34+
DJANGO_SECRET: '"${DJANGO_SECRET}"'
35+
REDIS_IP: '${REDIS_IP}'
36+
REDIS_PORT: '${REDIS_PORT}'
37+
AWS_ACCESS_KEY_ID: '${AWS_ACCESS_KEY_ID}'
38+
AWS_SECRET_ACCESS_KEY: '${AWS_SECRET_ACCESS_KEY}'

build.sh

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,20 @@
33
export ENVIRONMENT="$1"
44

55
rbenv rehash
6-
pip install beautifulsoup4
76
pip install requests
87
pip install -t lib requests-toolbelt
98

109
pip install -t lib codeforlife-portal
10+
11+
pip install -t lib django-anymail[amazon_ses]
12+
1113
if [ "$ENVIRONMENT" = "default" ]
1214
then
1315
pip install -t lib --upgrade --no-deps aimmo
1416
else
1517
pip install -t lib --pre --upgrade --no-deps aimmo
1618
fi
1719

18-
python install_gaerpytz.py
20+
python generate_requirements.py
1921

2022
./manage.py collectstatic --noinput
21-
22-
rm ./lib/_sass.so

deploy.sh

+1-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export GOOGLE_APPLICATION_CREDENTIALS=/home/runner/codeforlife-deploy-appengine/
2323

2424
# Install the dependencies for the following deploy script.
2525
# Kubernetes is a TEMPORARY solution. See issue 68.
26-
pip install kubernetes==5.0.0
26+
pip install kubernetes
2727
pip install pyyaml
2828

2929
# Authenticate the cluster by updating kubeconfig.
@@ -51,7 +51,6 @@ envsubst <app.yaml.tmpl >app.yaml
5151
${GCLOUD} app --quiet deploy app.yaml --project ${APP_ID} --version ${VERSION} --no-promote
5252
${GCLOUD} app --quiet deploy cron.yaml --project ${APP_ID} --version ${VERSION} --no-promote
5353

54-
5554
# Test the site
5655
./test.sh ${MODULE_NAME} ${VERSION}
5756

django_site/settings.py

+17-10
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
https://docs.djangoproject.com/en/1.6/ref/settings/
99
"""
1010

11-
from django.core.urlresolvers import reverse_lazy
12-
1311
# Build paths inside the project like this: rel(rel_path)
1412
import os
1513

@@ -31,10 +29,10 @@
3129
# Application definition
3230

3331
INSTALLED_APPS = (
32+
"anymail",
3433
"deploy",
3534
"portal",
3635
"captcha",
37-
"reports",
3836
"game",
3937
#'djangocms_admin_style', # for the admin skin. You **must** add 'djangocms_admin_style' in the list **before** 'django.contrib.admin'.
4038
"django.contrib.admin",
@@ -116,20 +114,30 @@
116114

117115
ALLOWED_HOSTS = [".appspot.com", ".codeforlife.education"]
118116

119-
if os.getenv("SERVER_SOFTWARE", "").startswith("Google App Engine"):
117+
ANYMAIL = {
118+
"AMAZON_SES_CLIENT_PARAMS": {
119+
"aws_access_key_id": os.getenv("AWS_ACCESS_KEY_ID"),
120+
"aws_secret_access_key": os.getenv("AWS_SECRET_ACCESS_KEY"),
121+
"region_name": "eu-west-1",
122+
},
123+
}
124+
125+
if os.getenv("GAE_APPLICATION", None):
120126
# Running on production App Engine, so use a Google Cloud SQL database.
121127
DATABASES = {
122128
"default": {
123129
"ENGINE": "django.db.backends.mysql",
124-
"HOST": "/cloudsql/decent-digit-629:db",
130+
"HOST": "/cloudsql/decent-digit-629:europe-west1:db",
125131
"NAME": os.getenv("DATABASE_NAME"),
126132
"USER": "root",
127133
}
128134
}
129135
CACHES = {
130136
"default": {
131-
"BACKEND": "django.core.cache.backends.memcached.MemcachedCache",
137+
"BACKEND": "django_redis.cache.RedisCache",
138+
"LOCATION": f"redis://{os.getenv('REDIS_IP')}:{os.getenv('REDIS_PORT')}/0",
132139
"KEY_PREFIX": os.getenv("CACHE_PREFIX"),
140+
"OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient"},
133141
}
134142
}
135143
PIPELINE_ENABLED = True
@@ -140,9 +148,7 @@
140148
if lib_path not in sys.path:
141149
sys.path.append(lib_path)
142150
# setup email on app engine
143-
EMAIL_BACKEND = "deploy.mail.EmailBackend"
144-
# Specify a queue name for the async. email backend.
145-
EMAIL_QUEUE_NAME = "default"
151+
EMAIL_BACKEND = "anymail.backends.amazon_ses.EmailBackend"
146152

147153
SOCIAL_AUTH_PANDASSO_KEY = "code-for-life"
148154
SOCIAL_AUTH_PANDASSO_SECRET = os.getenv("PANDASSO_SECRET")
@@ -208,8 +214,9 @@
208214

209215
CMS_TEMPLATES = (("portal/base.html", "Template One"),)
210216

217+
211218
AIMMO_GAME_SERVER_URL_FUNCTION = lambda game: (
212-
os.getenv("DJANGO_MODULE_NAME") + "-aimmo.codeforlife.education",
219+
f"{os.getenv('GAE_SERVICE')}-aimmo.codeforlife.education",
213220
"/game-%s" % game,
214221
)
215222

django_site/urls.py

-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from portal import urls as portal_urls
66
from game import urls as game_urls
77
from aimmo import urls as aimmo_urls
8-
from reports import urls as reports_urls
98

109
js_info_dict = {"packages": ("conf.locale",)}
1110

@@ -15,7 +14,6 @@
1514
url(r"^", include(portal_urls)),
1615
url(r"^administration/", include(admin.site.urls)),
1716
url(r"^rapidrouter/", include(game_urls)),
18-
url(r"^reports/", include(reports_urls)),
1917
url(r"^kurono/", include(aimmo_urls)),
2018
url(r"^versions/$", versions, name="versions"),
2119
]

django_site/wsgi.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@
1010
import os
1111
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_site.settings")
1212

13-
from django.core.wsgi import get_wsgi_application
13+
from lib.django.core.wsgi import get_wsgi_application
1414
application = get_wsgi_application()

generate_requirements.py

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from lib.portal import __version__ as portal_version
2+
from lib.aimmo import __version__ as aimmo_version
3+
4+
requirements = (
5+
f"codeforlife-portal=={portal_version}\n"
6+
f"aimmo=={aimmo_version}\n"
7+
f"requests-toolbelt==0.9.*\n"
8+
f"mysqlclient==1.4.*\n"
9+
f"redis==3.3.*\n"
10+
f"django-redis==4.11.*\n"
11+
f"django-anymail[amazon_ses]==7.0.*"
12+
)
13+
14+
requirements_path = "requirements.txt"
15+
requirements_file = open(requirements_path, "w")
16+
requirements_file.write(requirements)
17+
requirements_file.close()

install_gaerpytz.py

+5-20
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,6 @@
1-
import StringIO
2-
import zipfile
1+
import os
2+
import shutil
33

4-
import requests
5-
from bs4 import BeautifulSoup
6-
7-
# Get HTML of the gaerpytz home page
8-
gaerpytz_url = "https://gaerpytz.appspot.com"
9-
gaerpytz_webpage = requests.get(gaerpytz_url)
10-
gaerpytz_html = gaerpytz_webpage.text
11-
12-
# Parse HTML to get the zipfile's download link
13-
soup = BeautifulSoup(gaerpytz_html, "html.parser")
14-
zip_href = soup.find(title="Download the latest build").get("href")
15-
zip_url = gaerpytz_url + zip_href
16-
17-
# Download the zipfile and extract it to the lib folder. The zipfile contains
18-
# the module folder for pytz and will overwrite the one currently in lib
19-
request = requests.get(zip_url, stream=True)
20-
zip_file = zipfile.ZipFile(StringIO.StringIO(request.content))
21-
zip_file.extractall("lib")
4+
# Copy over the files from gaerpytz directory to the one in the lib folder
5+
for pytz_file in os.listdir("gaerpytz"):
6+
shutil.copy("gaerpytz/" + pytz_file, "lib/pytz")

lib/__init__.py

Whitespace-only changes.

main.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
import django_site.wsgi
1+
from django_site.wsgi import application
22

3-
application = django_site.wsgi.application
3+
app = application

0 commit comments

Comments
 (0)