Skip to content

Commit 099a493

Browse files
authored
Updating to Django 5 and Ubuntu 24.04 (#65)
* Updating to Django 5 and Ubuntu 24.04 * Temporarily remove db version check to support mariadb server on EL8 without appstream enabled * Configurable workers and threads * Configuring Content Security Policy * Fix IDP-less debugging on django5 * Switching charset to utf8mb4
1 parent 871cffc commit 099a493

File tree

11 files changed

+137
-66
lines changed

11 files changed

+137
-66
lines changed

Containerfile

+11-6
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
1-
FROM ubuntu:22.04
1+
FROM ubuntu:24.04
22

33
ENV PYTHONDONTWRITEBYTECODE 1
44
ENV PYTHONUNBUFFERED 1
55

6-
RUN apt-get update && apt-get install -y tzdata && apt install -y python3.10 python3-pip python3-dev python3-numpy libpq-dev nginx libmysqlclient-dev build-essential libsasl2-dev libldap2-dev libssl-dev xmlsec1 gettext
6+
RUN apt-get update && apt-get install -y tzdata && apt install -y python3.12 python3-pip python3-dev python3.12-venv libpq-dev nginx libmysqlclient-dev pkg-config build-essential libsasl2-dev libldap2-dev libssl-dev xmlsec1 gettext git
77

88
WORKDIR /opt/userportal
99

1010
COPY requirements.txt ./
1111

12-
RUN pip3 install --upgrade pip && \
13-
pip3 install --no-cache-dir -r requirements.txt
12+
RUN python3 -m venv /opt/userportal-env && \
13+
/opt/userportal-env/bin/pip install --upgrade pip && \
14+
/opt/userportal-env/bin/pip install --no-cache-dir -r requirements.txt
1415

1516
COPY . .
1617

17-
RUN patch /usr/local/lib/python3.10/dist-packages/ldapdb/backends/ldap/base.py < /opt/userportal/ldapdb.patch
18-
RUN python3 manage.py collectstatic --noinput && python3 manage.py compilemessages
18+
RUN patch /opt/userportal-env/lib/python3.12/site-packages/ldapdb/backends/ldap/base.py < /opt/userportal/ldapdb.patch
19+
20+
# Temporarily remove db version check to support mariadb server on EL8 without appstream enabled
21+
RUN patch /opt/userportal-env/lib/python3.12/site-packages/django/db/backends/base/base.py < /opt/userportal/dbcheck.patch
22+
23+
RUN /opt/userportal-env/bin/python manage.py collectstatic --noinput && /opt/userportal-env/bin/python manage.py compilemessages
1924

2025
EXPOSE 8000
2126
CMD ["./run-django-production.sh"]

dbcheck.patch

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
--- /opt/userportal-env/lib/python3.12/site-packages/django/db/backends/base/base.py 2024-07-17 17:45:44.000000000 +0000
2+
+++ /opt/userportal-env/lib/python3.12/site-packages/django/db/backends/base/base.py.modified 2024-07-17 19:21:39.250937980 +0000
3+
@@ -222,7 +222,7 @@
4+
"""Initialize the database connection settings."""
5+
global RAN_DB_VERSION_CHECK
6+
if self.alias not in RAN_DB_VERSION_CHECK:
7+
- self.check_database_version_supported()
8+
+ #self.check_database_version_supported()
9+
RAN_DB_VERSION_CHECK.add(self.alias)
10+
11+
def create_cursor(self, name=None):

docs/install.md

+12-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,18 @@ Before installing in production, [a test environment should be set up to test th
55
The portal can be installed directly on a Rocky8 Apache web server or with Nginx and Gunicorn. The portal can also be deployed as a container with Podman or Kubernetes. Some scripts used to deploy both Nginx and Django containers inside the same pod are provided in the `podman` directory.
66
The various recommendations for any normal Django production deployment can be followed.
77

8-
[Deploying Django](https://docs.djangoproject.com/en/3.2/howto/deployment/)
8+
[Deploying Django](https://docs.djangoproject.com/en/5.0/howto/deployment/)
9+
10+
The database should support UTF8. With MariaDB, the default collation can be changed with the following command:
11+
12+
```
13+
ALTER DATABASE userportal CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
14+
```
15+
16+
Migration scripts will also ensure that the tables and columns are converted to the correct collation.
17+
18+
# Production with containers
19+
Using containers is the recommended way to deploy the portal. The container is automatically built in the CI pipeline and pushed to the Github registry. This container is handling the django application. The static files are served by a standard Nginx container. Both containers are deployed in the same pod with a shared volume containing the static files.
920

1021
# Production without containers on Rocky Linux 8
1122

jobstats/migrations/0002_utf8.py

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Generated by Django 5.0.7 on 2024-10-16 18:38
2+
3+
from django.db import migrations
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('jobstats', '0001_initial'),
10+
]
11+
12+
operations = [
13+
migrations.RunSQL('ALTER TABLE jobstats_jobscript CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'),
14+
migrations.RunSQL('ALTER TABLE jobstats_jobscript MODIFY submit_script LONGTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'),
15+
]

notes/migrations/0002_utf8.py

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Generated by Django 5.0.7 on 2024-10-16 18:03
2+
3+
from django.db import migrations
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('notes', '0001_initial'),
10+
]
11+
12+
operations = [
13+
migrations.RunSQL('ALTER TABLE notes_note CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'),
14+
migrations.RunSQL('ALTER TABLE notes_note MODIFY title VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'),
15+
migrations.RunSQL('ALTER TABLE notes_note MODIFY notes LONGTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'),
16+
]

podman/deploy.sh

+12
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,16 @@ if [ -z "$VERSION" ]; then
2020
VERSION=latest
2121
fi
2222

23+
if [ -z "$WORKERS" ]; then
24+
echo "WORKERS is not set in the config file, using 4"
25+
WORKERS=4
26+
fi
27+
28+
if [ -z "$THREADS" ]; then
29+
echo "THREADS is not set in the config file, using 4"
30+
THREADS=4
31+
fi
32+
2333
podman pod stop TT-$TT_ENV
2434
podman pod rm -f TT-$TT_ENV
2535
podman volume rm -f TT-$TT_ENV-static
@@ -28,6 +38,8 @@ podman pod create -p $PORT:80 --name TT-$TT_ENV
2838
podman volume create TT-$TT_ENV-static
2939

3040
podman run --detach --pod TT-$TT_ENV --name=TT-$TT_ENV-django \
41+
--env WORKERS=${WORKERS} \
42+
--env THREADS=${THREADS} \
3143
-v $TT_ENV_PATH/99-local.py:/secrets/settings/99-local.py:Z \
3244
-v $TT_ENV_PATH/private.key:/opt/userportal/private.key:Z \
3345
-v $TT_ENV_PATH/public.cert:/opt/userportal/public.cert:Z \

requirements.txt

+47-48
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,55 @@
1-
asgiref==3.4.1
2-
certifi==2024.07.04
3-
cffi==1.15.1
4-
chardet==4.0.0
5-
charset-normalizer==3.3.1
6-
cryptography==42.0.4
7-
dateparser==1.0.0
1+
asgiref==3.8.1
2+
certifi==2024.7.4
3+
cffi==1.16.0
4+
charset-normalizer==3.3.2
5+
contourpy==1.2.1
6+
cryptography==42.0.8
7+
cycler==0.12.1
8+
dateparser==1.2.0
89
defusedxml==0.7.1
9-
Django==3.2.25
10-
django-auth-ldap==2.3.0
11-
django-bootstrap-pagination==1.7.1
12-
django-debug-toolbar==3.2.4
13-
django-ldapdb==1.5.1
10+
Django==5.0.9
11+
django-bootstrap-pagination @ git+https://github.com/teejaydub/django-bootstrap-pagination@82ea7a213860a741890f324e025f6ec215f24a32
12+
django-crispy-forms==2.2
13+
django-debug-toolbar==4.4.6
14+
django-ldapdb @ git+https://github.com/nikolaik/django-ldapdb@381e4f40032c96ea6ae6623a5a0339b3ea526ae5
1415
django-settings-export==1.2.1
1516
django-watchman==1.3.0
16-
djangorestframework==3.13.1
17-
djangorestframework-api-key==2.0.0
18-
djangorestframework-datatables==0.7.0
19-
djangosaml2==1.5.1
20-
elementpath==2.4.0
21-
flake8==3.9.0
17+
django_csp==3.8
18+
djangorestframework==3.15.2
19+
djangorestframework-datatables==0.7.2
20+
djangosaml2==1.9.3
21+
elementpath==4.4.0
22+
flake8==7.1.0
23+
fonttools==4.53.1
2224
gunicorn==22.0.0
25+
httmock==1.4.0
2326
idna==3.7
24-
importlib-metadata==3.7.3
25-
importlib-resources==5.4.0
26-
install==1.3.5
27-
IPy==1.1
28-
mccabe==0.6.1
29-
mysqlclient==2.0.3
30-
numpy==1.23.4
31-
pandas==1.1.5
32-
plotly==4.14.3
33-
prometheus-api-client==0.4.2
34-
pyasn1==0.4.8
35-
pyasn1-modules==0.2.8
36-
pycodestyle==2.7.0
37-
pycparser==2.21
38-
pyflakes==2.3.0
39-
PyJWT==2.7.0
40-
Pyment==0.3.3
27+
kiwisolver==1.4.5
28+
matplotlib==3.9.2
29+
mccabe==0.7.0
30+
mysqlclient==2.2.4
31+
numpy==2.0.0
32+
packaging==24.1
33+
pandas==2.2.2
34+
pillow==10.4.0
35+
prometheus-api-client==0.5.5
36+
pyasn1==0.6.0
37+
pyasn1_modules==0.4.0
38+
pycodestyle==2.12.0
39+
pycparser==2.22
40+
pyflakes==3.2.0
4141
pyOpenSSL==24.1.0
42-
pysaml2==7.1.2
43-
python-dateutil==2.8.1
44-
python-ldap==3.4.3
45-
pytz==2021.1
46-
PyYAML==6.0
47-
regex==2020.11.13
42+
pyparsing==3.1.2
43+
pysaml2==7.5.0
44+
python-dateutil==2.9.0.post0
45+
python-ldap==3.4.4
46+
pytz==2024.1
47+
PyYAML==6.0.1
48+
regex==2024.5.15
4849
requests==2.32.3
49-
retrying==1.3.3
50-
six==1.15.0
50+
six==1.16.0
5151
sqlparse==0.5.0
52-
typing-extensions==3.7.4.3
53-
tzlocal==2.1
54-
urllib3==1.26.19
55-
xmlschema==1.9.2
56-
zipp==3.19.1
52+
tzdata==2024.1
53+
tzlocal==5.2
54+
urllib3==2.2.2
55+
xmlschema==2.5.1

run-django-production.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ set -o nounset
77
cp /secrets/settings/99-local.py /opt/userportal/userportal/settings/99-local.py
88
mkdir -p /var/www/api/static
99
cp -r /opt/userportal/collected-static/* /var/www/api/static/
10-
gunicorn --bind :8000 --workers 1 --timeout 90 userportal.wsgi
10+
/opt/userportal-env/bin/gunicorn --bind :8000 --workers $WORKERS --threads $THREADS --timeout 90 userportal.wsgi

userportal/authentication.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def clean_username(self, username):
2323
username = username.split('@')[0]
2424
return username
2525

26-
def configure_user(self, request, user):
26+
def configure_user(self, request, user, created=True):
2727
if '[email protected]' in request.META['affiliation'] \
2828
or '[email protected]' in request.META['affiliation']:
2929
user.is_staff = True

userportal/settings/10-base.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
11
"""
22
Django settings for userportal project.
3-
4-
Generated by 'django-admin startproject' using Django 3.1.7.
5-
6-
For more information on this file, see
7-
https://docs.djangoproject.com/en/3.1/topics/settings/
8-
9-
For the full list of settings and their values, see
10-
https://docs.djangoproject.com/en/3.1/ref/settings/
113
"""
124

135
from pathlib import Path
@@ -43,6 +35,7 @@
4335
'django.contrib.staticfiles',
4436
'django.contrib.humanize',
4537
'djangosaml2',
38+
'csp',
4639
'watchman',
4740

4841
'pages',
@@ -78,6 +71,7 @@
7871
'django.contrib.messages.middleware.MessageMiddleware',
7972
'django.middleware.clickjacking.XFrameOptionsMiddleware',
8073
'djangosaml2.middleware.SamlSessionMiddleware',
74+
'csp.middleware.CSPMiddleware',
8175
]
8276

8377
ROOT_URLCONF = 'userportal.urls'
@@ -204,3 +198,9 @@
204198
'DEFAULT_PAGINATION_CLASS': 'rest_framework_datatables.pagination.DatatablesPageNumberPagination',
205199
'PAGE_SIZE': 100,
206200
}
201+
202+
# Content Security Policy
203+
CSP_DEFAULT_SRC = ("'self'")
204+
CSP_IMG_SRC = ("'self'", "data:", 'object-arbutus.cloud.computecanada.ca')
205+
CSP_STYLE_SRC = ("'self'", "'unsafe-inline'", 'cdn.jsdelivr.net', 'cdnjs.cloudflare.com', 'cdn.datatables.net')
206+
CSP_SCRIPT_SRC = ("'self'", "'unsafe-inline'", 'cdn.jsdelivr.net', 'cdnjs.cloudflare.com', 'cdn.datatables.net', 'code.jquery.com', 'cdn.plot.ly')

userportal/settings/20-databases.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
'HOST': 'dbserver',
1111
'PORT': '3128',
1212
'OPTIONS': {
13-
}
13+
'charset': 'utf8mb4',
14+
'use_unicode': True,
15+
},
1416
},
1517
'slurm': {
1618
'ENGINE': 'django.db.backends.mysql',

0 commit comments

Comments
 (0)