Skip to content

Commit 8424079

Browse files
committed
feat(controller): switch wsgi to asgi
1 parent 36e1230 commit 8424079

8 files changed

Lines changed: 143 additions & 76 deletions

File tree

rootfs/api/asgi.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""
2+
ASGI config for Drycc Workflow Controller project.
3+
4+
It exposes the ASGI callable as a module-level variable named ``application``.
5+
6+
For more information on this file, see
7+
https://docs.djangoproject.com/en/4.1/howto/deployment/asgi/
8+
"""
9+
10+
import os
11+
12+
from django.core.asgi import get_asgi_application
13+
14+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'api.settings.production')
15+
16+
application = get_asgi_application()

rootfs/api/permissions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ def has_permission(self, request, view):
121121
"""
122122
Return `True` if permission is granted, `False` otherwise.
123123
"""
124-
auth_header = request.environ.get('HTTP_X_DRYCC_BUILDER_AUTH')
124+
auth_header = request.META.get('HTTP_X_DRYCC_BUILDER_AUTH')
125125
if not auth_header:
126126
return False
127127
return auth_header == settings.BUILDER_KEY

rootfs/api/urls.py

Lines changed: 114 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
URL routing patterns for the Drycc REST API.
33
"""
44
from django.conf import settings
5-
from django.conf.urls import include, url
5+
from django.urls import include, re_path
66
from rest_framework.routers import DefaultRouter
77
from social_core.utils import setting_name
88
from api import views
@@ -13,152 +13,201 @@
1313

1414
# Add the generated REST URLs and login/logout endpoint
1515
app_urlpatterns = [
16-
url(r'^', include(router.urls)),
17-
url(r'auth/login/?$', views.AuthLoginView.as_view({"post": "login"})),
18-
url(r'auth/token/(?P<key>[-_\w]+)/?$', views.AuthTokenView.as_view({"get": "token"})),
16+
re_path(r'^', include(router.urls)),
17+
re_path(r'auth/login/?$', views.AuthLoginView.as_view({"post": "login"})),
18+
re_path(r'auth/token/(?P<key>[-_\w]+)/?$', views.AuthTokenView.as_view({"get": "token"})),
1919
# application release components
20-
url(r"^apps/(?P<id>{})/config/?$".format(settings.APP_URL_REGEX),
20+
re_path(
21+
r"^apps/(?P<id>{})/config/?$".format(settings.APP_URL_REGEX),
2122
views.ConfigViewSet.as_view({'get': 'retrieve', 'post': 'create'})),
22-
url(r"^apps/(?P<id>{})/builds/(?P<uuid>[-_\w]+)/?$".format(settings.APP_URL_REGEX),
23+
re_path(
24+
r"^apps/(?P<id>{})/builds/(?P<uuid>[-_\w]+)/?$".format(settings.APP_URL_REGEX),
2325
views.BuildViewSet.as_view({'get': 'retrieve'})),
24-
url(r"^apps/(?P<id>{})/builds/?$".format(settings.APP_URL_REGEX),
26+
re_path(
27+
r"^apps/(?P<id>{})/builds/?$".format(settings.APP_URL_REGEX),
2528
views.BuildViewSet.as_view({'get': 'list', 'post': 'create'})),
26-
url(r"^apps/(?P<id>{})/releases/v(?P<version>[0-9]+)/?$".format(settings.APP_URL_REGEX),
29+
re_path(
30+
r"^apps/(?P<id>{})/releases/v(?P<version>[0-9]+)/?$".format(settings.APP_URL_REGEX),
2731
views.ReleaseViewSet.as_view({'get': 'retrieve'})),
28-
url(r"^apps/(?P<id>{})/releases/rollback/?$".format(settings.APP_URL_REGEX),
32+
re_path(
33+
r"^apps/(?P<id>{})/releases/rollback/?$".format(settings.APP_URL_REGEX),
2934
views.ReleaseViewSet.as_view({'post': 'rollback'})),
30-
url(r"^apps/(?P<id>{})/releases/?$".format(settings.APP_URL_REGEX),
35+
re_path(
36+
r"^apps/(?P<id>{})/releases/?$".format(settings.APP_URL_REGEX),
3137
views.ReleaseViewSet.as_view({'get': 'list'})),
3238
# restart pods
33-
url(r"^apps/(?P<id>{})/pods/restart/?$".format(settings.APP_URL_REGEX),
39+
re_path(
40+
r"^apps/(?P<id>{})/pods/restart/?$".format(settings.APP_URL_REGEX),
3441
views.PodViewSet.as_view({'post': 'restart'})),
35-
url(r"^apps/(?P<id>{})/pods/(?P<type>[-_\w.]+)/restart/?$".format(settings.APP_URL_REGEX),
42+
re_path(
43+
r"^apps/(?P<id>{})/pods/(?P<type>[-_\w.]+)/restart/?$".format(settings.APP_URL_REGEX),
3644
views.PodViewSet.as_view({'post': 'restart'})),
37-
url(r"^apps/(?P<id>{})/pods/(?P<type>[-_\w]+)/(?P<name>[-_\w]+)/restart/?$".format(
38-
settings.APP_URL_REGEX),
45+
re_path(
46+
r"^apps/(?P<id>{})/pods/(?P<type>[-_\w]+)/(?P<name>[-_\w]+)/restart/?$".format(
47+
settings.APP_URL_REGEX),
3948
views.PodViewSet.as_view({'post': 'restart'})),
4049
# list pods
41-
url(r"^apps/(?P<id>{})/pods/(?P<type>[-_\w]+)/(?P<name>[-_\w]+)/?$".format(
42-
settings.APP_URL_REGEX),
50+
re_path(
51+
r"^apps/(?P<id>{})/pods/(?P<type>[-_\w]+)/(?P<name>[-_\w]+)/?$".format(
52+
settings.APP_URL_REGEX),
4353
views.PodViewSet.as_view({'get': 'list'})),
44-
url(r"^apps/(?P<id>{})/pods/(?P<type>[-_\w.]+)/?$".format(settings.APP_URL_REGEX),
54+
re_path(
55+
r"^apps/(?P<id>{})/pods/(?P<type>[-_\w.]+)/?$".format(settings.APP_URL_REGEX),
4556
views.PodViewSet.as_view({'get': 'list'})),
46-
url(r"^apps/(?P<id>{})/pods/?$".format(settings.APP_URL_REGEX),
57+
re_path(
58+
r"^apps/(?P<id>{})/pods/?$".format(settings.APP_URL_REGEX),
4759
views.PodViewSet.as_view({'get': 'list'})),
4860
# application domains
49-
url(r"^apps/(?P<id>{})/domains/(?P<domain>\**\.?[-\._\w]+)/?$".format(settings.APP_URL_REGEX),
61+
re_path(
62+
r"^apps/(?P<id>{})/domains/(?P<domain>\**\.?[-\._\w]+)/?$".format(settings.APP_URL_REGEX),
5063
views.DomainViewSet.as_view({'delete': 'destroy'})),
51-
url(r"^apps/(?P<id>{})/domains/?$".format(settings.APP_URL_REGEX),
64+
re_path(
65+
r"^apps/(?P<id>{})/domains/?$".format(settings.APP_URL_REGEX),
5266
views.DomainViewSet.as_view({'post': 'create', 'get': 'list'})),
5367
# application services
54-
url(r"^apps/(?P<id>{})/services/?$".format(settings.APP_URL_REGEX),
68+
re_path(
69+
r"^apps/(?P<id>{})/services/?$".format(settings.APP_URL_REGEX),
5570
views.ServiceViewSet.as_view({'post': 'create_or_update',
5671
'get': 'list', 'delete': 'delete'})),
5772
# application actions
58-
url(r"^apps/(?P<id>{})/scale/?$".format(settings.APP_URL_REGEX),
73+
re_path(
74+
r"^apps/(?P<id>{})/scale/?$".format(settings.APP_URL_REGEX),
5975
views.AppViewSet.as_view({'post': 'scale'})),
60-
url(r"^apps/(?P<id>{})/logs/?$".format(settings.APP_URL_REGEX),
76+
re_path(
77+
r"^apps/(?P<id>{})/logs/?$".format(settings.APP_URL_REGEX),
6178
views.AppViewSet.as_view({'get': 'logs'})),
62-
url(r"^apps/(?P<id>{})/run/?$".format(settings.APP_URL_REGEX),
79+
re_path(
80+
r"^apps/(?P<id>{})/run/?$".format(settings.APP_URL_REGEX),
6381
views.AppViewSet.as_view({'post': 'run'})),
6482
# application settings
65-
url(r"^apps/(?P<id>{})/settings/?$".format(settings.APP_URL_REGEX),
83+
re_path(
84+
r"^apps/(?P<id>{})/settings/?$".format(settings.APP_URL_REGEX),
6685
views.AppSettingsViewSet.as_view({'get': 'retrieve', 'post': 'create'})),
6786
# application ip allowlist
68-
url(r"^apps/(?P<id>{})/allowlist/?$".format(settings.APP_URL_REGEX),
87+
re_path(
88+
r"^apps/(?P<id>{})/allowlist/?$".format(settings.APP_URL_REGEX),
6989
views.AllowlistViewSet.as_view({'post': 'create', 'get': 'list', 'delete': 'delete'})),
7090
# application TLS settings
71-
url(r"^apps/(?P<id>{})/tls/?$".format(settings.APP_URL_REGEX),
91+
re_path(
92+
r"^apps/(?P<id>{})/tls/?$".format(settings.APP_URL_REGEX),
7293
views.TLSViewSet.as_view({'get': 'retrieve', 'post': 'create'})),
7394
# apps sharing
74-
url(r"^apps/(?P<id>{})/perms/(?P<username>[-_\w]+)/?$".format(settings.APP_URL_REGEX),
95+
re_path(
96+
r"^apps/(?P<id>{})/perms/(?P<username>[-_\w]+)/?$".format(settings.APP_URL_REGEX),
7597
views.AppPermsViewSet.as_view({'delete': 'destroy'})),
76-
url(r"^apps/(?P<id>{})/perms/?$".format(settings.APP_URL_REGEX),
98+
re_path(
99+
r"^apps/(?P<id>{})/perms/?$".format(settings.APP_URL_REGEX),
77100
views.AppPermsViewSet.as_view({'get': 'list', 'post': 'create'})),
78101
# application volumes
79-
url(r"^apps/(?P<id>{})/volumes/?$".format(settings.APP_URL_REGEX),
102+
re_path(
103+
r"^apps/(?P<id>{})/volumes/?$".format(settings.APP_URL_REGEX),
80104
views.AppVolumesViewSet.as_view({'get': 'list', 'post': 'create'})),
81-
url(r"^apps/(?P<id>{})/volumes/(?P<name>[-_\w]+)/?$".format(settings.APP_URL_REGEX),
105+
re_path(
106+
r"^apps/(?P<id>{})/volumes/(?P<name>[-_\w]+)/?$".format(settings.APP_URL_REGEX),
82107
views.AppVolumesViewSet.as_view({'patch': 'expand', 'delete': 'destroy'})),
83-
url(r"^apps/(?P<id>{})/volumes/(?P<name>[-_\w]+)/path/?$".format(settings.APP_URL_REGEX),
108+
re_path(
109+
r"^apps/(?P<id>{})/volumes/(?P<name>[-_\w]+)/path/?$".format(settings.APP_URL_REGEX),
84110
views.AppVolumeMountPathViewSet.as_view({'patch': 'path'})),
85111
# application resources
86-
url(r"^resources/services/?$", views.AppResourcesViewSet.as_view({'get': 'services'})),
87-
url(r"^resources/services/(?P<id>[-_\w]+)/plans/?$",
112+
re_path(r"^resources/services/?$", views.AppResourcesViewSet.as_view({'get': 'services'})),
113+
re_path(
114+
r"^resources/services/(?P<id>[-_\w]+)/plans/?$",
88115
views.AppResourcesViewSet.as_view({'get': 'plans'})),
89-
url(r"^apps/(?P<id>{})/resources/?$".format(settings.APP_URL_REGEX),
116+
re_path(
117+
r"^apps/(?P<id>{})/resources/?$".format(settings.APP_URL_REGEX),
90118
views.AppResourcesViewSet.as_view({'get': 'list', 'post': 'create'})),
91-
url(r"^apps/(?P<id>{})/resources/(?P<name>[-_\w]+)/?$".format(settings.APP_URL_REGEX),
119+
re_path(
120+
r"^apps/(?P<id>{})/resources/(?P<name>[-_\w]+)/?$".format(settings.APP_URL_REGEX),
92121
views.AppSingleResourceViewSet.as_view({
93122
'get': 'retrieve',
94123
'delete': 'destroy',
95124
'put': 'update'
96125
})),
97-
url(r"^apps/(?P<id>{})/resources/(?P<name>[-_\w]+)/binding/?$".format(settings.APP_URL_REGEX),
126+
re_path(
127+
r"^apps/(?P<id>{})/resources/(?P<name>[-_\w]+)/binding/?$".format(settings.APP_URL_REGEX),
98128
views.AppResourceBindingViewSet.as_view({'patch': 'binding'})),
99129
# apps base endpoint
100-
url(r"^apps/(?P<id>{})/?$".format(settings.APP_URL_REGEX),
130+
re_path(
131+
r"^apps/(?P<id>{})/?$".format(settings.APP_URL_REGEX),
101132
views.AppViewSet.as_view({'get': 'retrieve', 'post': 'update', 'delete': 'destroy'})),
102-
url(r'^apps/?$',
133+
re_path(
134+
r'^apps/?$',
103135
views.AppViewSet.as_view({'get': 'list', 'post': 'create'})),
104136
# key
105-
url(r'^keys/(?P<id>.+)/?$',
137+
re_path(
138+
r'^keys/(?P<id>.+)/?$',
106139
views.KeyViewSet.as_view({'get': 'retrieve', 'delete': 'destroy'})),
107-
url(r'^keys/?$',
140+
re_path(
141+
r'^keys/?$',
108142
views.KeyViewSet.as_view({'get': 'list', 'post': 'create'})),
109143
# hooks
110-
url(r'^hooks/keys/(?P<id>{})/(?P<username>[-_\w]+)?$'.format(settings.APP_URL_REGEX),
144+
re_path(
145+
r'^hooks/keys/(?P<id>{})/(?P<username>[-_\w]+)?$'.format(settings.APP_URL_REGEX),
111146
views.KeyHookViewSet.as_view({'get': 'users'})),
112-
url(r'^hooks/keys/(?P<id>{})/?$'.format(settings.APP_URL_REGEX),
147+
re_path(
148+
r'^hooks/keys/(?P<id>{})/?$'.format(settings.APP_URL_REGEX),
113149
views.KeyHookViewSet.as_view({'get': 'app'})),
114-
url(r'^hooks/key/(?P<fingerprint>.+)/?$',
150+
re_path(
151+
r'^hooks/key/(?P<fingerprint>.+)/?$',
115152
views.KeyHookViewSet.as_view({'get': 'public_key'})),
116-
url(r'^hooks/build/?$',
153+
re_path(
154+
r'^hooks/build/?$',
117155
views.BuildHookViewSet.as_view({'post': 'create'})),
118-
url(r'^hooks/config/?$',
156+
re_path(
157+
r'^hooks/config/?$',
119158
views.ConfigHookViewSet.as_view({'post': 'create'})),
120159
# authn / authz
121-
url(r'^auth/whoami/?$',
160+
re_path(
161+
r'^auth/whoami/?$',
122162
views.UserManagementViewSet.as_view({'get': 'list'})),
123163
# admin sharing
124-
url(r'^admin/perms/(?P<username>[\w.@+-]+)/?$',
164+
re_path(
165+
r'^admin/perms/(?P<username>[\w.@+-]+)/?$',
125166
views.AdminPermsViewSet.as_view({'delete': 'destroy'})),
126-
url(r'^admin/perms/?$',
167+
re_path(
168+
r'^admin/perms/?$',
127169
views.AdminPermsViewSet.as_view({'get': 'list', 'post': 'create'})),
128170
# certificates
129-
url(r'^certs/(?P<name>[-_*.\w]+)/domain/(?P<domain>\**\.?[-\._\w]+)?$',
171+
re_path(
172+
r'^certs/(?P<name>[-_*.\w]+)/domain/(?P<domain>\**\.?[-\._\w]+)?$',
130173
views.CertificateViewSet.as_view({'delete': 'detach', 'post': 'attach'})),
131-
url(r'^certs/(?P<name>[-_*.\w]+)/?$',
174+
re_path(
175+
r'^certs/(?P<name>[-_*.\w]+)/?$',
132176
views.CertificateViewSet.as_view({
133177
'get': 'retrieve',
134178
'delete': 'destroy'
135179
})),
136-
url(r'^certs/?$',
180+
re_path(
181+
r'^certs/?$',
137182
views.CertificateViewSet.as_view({'get': 'list', 'post': 'create'})),
138183
# users
139-
url(r'^users/?$',
184+
re_path(
185+
r'^users/?$',
140186
views.UserView.as_view({'get': 'list'})),
141-
url(r'^users/(?P<username>[\w.@+-]+)/enable/?$',
187+
re_path(
188+
r'^users/(?P<username>[\w.@+-]+)/enable/?$',
142189
views.UserView.as_view({'patch': 'enable'})),
143-
url(r'^users/(?P<username>[\w.@+-]+)/disable/?$',
190+
re_path(
191+
r'^users/(?P<username>[\w.@+-]+)/disable/?$',
144192
views.UserView.as_view({'patch': 'disable'})),
145-
url(r'^apps/(?P<id>{})/metrics/(?P<type>[a-z0-9]+(\-[a-z0-9]+)*)/status/?$'.format(
146-
settings.APP_URL_REGEX),
193+
re_path(
194+
r'^apps/(?P<id>{})/metrics/(?P<type>[a-z0-9]+(\-[a-z0-9]+)*)/status/?$'.format(
195+
settings.APP_URL_REGEX),
147196
views.MetricView.as_view({'get': 'status'})),
148-
url(r'^manager/(?P<type>[\w.@+-]+)s/(?P<id>{})/block/?$'.format(settings.APP_URL_REGEX),
197+
re_path(
198+
r'^manager/(?P<type>[\w.@+-]+)s/(?P<id>{})/block/?$'.format(settings.APP_URL_REGEX),
149199
views.WorkflowManagerViewset.as_view({'post': 'block'})),
150-
url(r'^manager/(?P<type>[\w.@+-]+)s/(?P<id>{})/unblock/?$'.format(settings.APP_URL_REGEX),
200+
re_path(
201+
r'^manager/(?P<type>[\w.@+-]+)s/(?P<id>{})/unblock/?$'.format(settings.APP_URL_REGEX),
151202
views.WorkflowManagerViewset.as_view({'delete': 'unblock'})),
152203
# social login is placed at the end of the URL match
153-
url(r'^login/(?P<backend>[^/]+){0}$'.format(extra), views.auth,
154-
name='begin'),
155-
url(r'^complete/(?P<backend>[^/]+){0}$'.format(extra), views.complete,
156-
name='complete'),
157-
url('', include('social_django.urls', namespace='social')),
204+
re_path(r'^login/(?P<backend>[^/]+){0}$'.format(extra), views.auth, name='begin'),
205+
re_path(r'^complete/(?P<backend>[^/]+){0}$'.format(extra), views.complete, name='complete'),
206+
re_path('', include('social_django.urls', namespace='social')),
158207
]
159208

160209
webhook_urlpatterns = [
161-
url(
210+
re_path(
162211
r'^webhooks/scale/(?P<token>.+)/?$',
163212
views.AdmissionWebhookViewSet.as_view({'post': 'scale'})
164213
),

rootfs/api/wsgi.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
It exposes the WSGI callable as a module-level variable named ``application``.
55
66
For more information on this file, see
7-
https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/
7+
https://docs.djangoproject.com/en/4.1/howto/deployment/wsgi/
88
"""
99

1010
import os
1111

1212
from django.core.wsgi import get_wsgi_application
1313

14-
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "api.settings.production")
14+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'api.settings.production')
1515

1616
application = get_wsgi_application()

rootfs/bin/boot

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ python /workspace/manage.py migrate --noinput
3030
# spawn a gunicorn server in the background
3131
echo ""
3232
echo "Starting up Gunicorn"
33-
gunicorn -c /workspace/drycc/gunicorn/config.py api.wsgi &
33+
gunicorn -c /workspace/drycc/gunicorn/config.py api.asgi &
3434

3535
# smart shutdown on SIGTERM (SIGINT is handled by gunicorn)
3636
function on_exit() {

rootfs/drycc/gunicorn/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
bind = '0.0.0.0:8000'
1515

1616
workers = int(os.environ.get('GUNICORN_WORKERS', cpu_count() * 4 + 1))
17-
17+
worker_class = "uvicorn.workers.UvicornWorker"
1818
pythonpath = dirname(dirname(dirname(realpath(__file__))))
1919
timeout = 1200
2020
pidfile = '/tmp/gunicorn.pid'

rootfs/drycc/urls.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
"""
77

88

9-
from django.conf.urls import include, url
9+
from django.urls import include, re_path
1010
from api.views import LivenessCheckView
1111
from api.views import ReadinessCheckView
1212

1313
urlpatterns = [
14-
url(r'^healthz$', LivenessCheckView.as_view()),
15-
url(r'^readiness$', ReadinessCheckView.as_view()),
16-
url(r'^v2/', include('api.urls')),
14+
re_path(r'^healthz$', LivenessCheckView.as_view()),
15+
re_path(r'^readiness$', ReadinessCheckView.as_view()),
16+
re_path(r'^v2/', include('api.urls')),
1717
]

rootfs/requirements.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
# Drycc controller requirements
22
backoff==1.11.1
3-
django==3.2.15
3+
django==4.1
44
django-cors-headers==3.7.0
55
django-guardian==2.4.0
66
djangorestframework==3.12.4
77
docker==5.0.0
88
gunicorn==20.1.0
9+
uvicorn==0.18.2
10+
asgiref==3.5.2
911
idna==3.2
1012
jmespath==0.10.0
1113
jsonschema==3.2.0
@@ -15,7 +17,7 @@ packaging==21.0
1517
pyasn1==0.4.8
1618
psycopg2-binary==2.9.3
1719
pyOpenSSL==20.0.1
18-
pytz==2021.1
20+
pytz==2022.2.1
1921
requests==2.26.0
2022
requests-toolbelt==0.9.1
2123
celery==5.2.2

0 commit comments

Comments
 (0)