Skip to content

Commit 4e91d1e

Browse files
ferozerubabaroloabaroloemileswartsyusufsheiqh
authored
Gov Paas to DBT PaaS migration (#652)
* TSS-1615: Pingdom (#644) * TSS-1615: Pingdom * format --------- Co-authored-by: abarolo <[email protected]> * TSS-1614: Xray + ASIM Logging (#645) * TSS-1614: Xray * Switch based on platform * Handle all 3 loggers --------- Co-authored-by: abarolo <[email protected]> * Trigger pipeline * Add .copilot directory for deployments * Allow ELB health checks (#653) * Allow ELB health checks The ALLOWED_HOSTS variable needs to be dynamically configured to allow health check requests from the ELB. Use the DBT copilot python package helper function to do this. * Alphabetically order imports * Fix empty line * Read new evnironment variable for CORS ALLOWED_HOSTS isn't suitable as the automatic entry for the load balancer doesn't have a protocol. The CORS_ALLOWED_ORIGINS values need to managed indepentently and contain https prefixes. * Add debugging information for allowed hosts * Debug Copilot environment variables * More debugging for ALLOWED_HOSTS * Bump Copilot python dependency This includes a fix for the allowed_hosts helper function * Remove debugging code * Test Slack notifications with empty commit * Remove ALLOWED_HOSTS debugging * Temporarily disable error handling to see error connecting to Datahub * Revert "Temporarily disable error handling to see error connecting to Datahub" This reverts commit 820a970. * Add APM to Sentry * debug failed upload * Fix syntax for printing responseCode * Kick off another deployment * Workaround for adding the node Docker layer This is required to compile assets * Update webpack React output filename * Update `devtool` in Webpack configuration file * Update Webpack configuration to use `source-map` * Update error message in AttachmentForm * Trigger pipeline * Update requirements * Merge master and sentry apm tracking * chore: update Django configuration settings for Sentry * Turn on static file compression Enable static file compression and caching * Tidy up * PAAS Migration branch cleanup (#696) * enhancing contrast colors (#693) * Fix test and format * Test fix --------- Co-authored-by: Uka Osim <[email protected]> Co-authored-by: abarolo <[email protected]> * Use env.bool to check whether Elastic APM is enabled --------- Co-authored-by: abarolo <[email protected]> Co-authored-by: abarolo <[email protected]> Co-authored-by: Emile Swarts <[email protected]> Co-authored-by: Yusuf <[email protected]> Co-authored-by: Gareth Pitt-Nash <[email protected]> Co-authored-by: Uka Osim <[email protected]>
1 parent 4befa19 commit 4e91d1e

23 files changed

+1183
-248
lines changed

.copilot/config.yml

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
repository: dmas/dmas-frontend
2+
builder:
3+
name: paketobuildpacks/builder-jammy-full
4+
version: 0.3.339

.copilot/image_build_run.sh

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env bash
2+
3+
# Exit early if something goes wrong
4+
set -e
5+
6+
# Add commands below to run inside the container after all the other buildpacks have been applied

.copilot/phases/build.sh

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env bash
2+
3+
# Exit early if something goes wrong
4+
set -e
5+
6+
# Add commands below to run as part of the build phase

.copilot/phases/install.sh

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env bash
2+
3+
# Exit early if something goes wrong
4+
set -e
5+
6+
# Add commands below to run as part of the install phase

.copilot/phases/post_build.sh

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env bash
2+
3+
# Exit early if something goes wrong
4+
set -e
5+
6+
# Add commands below to run as part of the post_build phase

.copilot/phases/pre_build.sh

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env bash
2+
3+
# Exit early if something goes wrong
4+
set -e
5+
6+
# Add commands below to run as part of the pre_build phase

Procfile

+2-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
web: gunicorn config.wsgi:application --bind 0.0.0.0:$PORT --worker-class gevent --worker-connections 1000 --timeout 120 --log-file - --capture-output
1+
web: opentelemetry-instrument gunicorn config.wsgi:application --bind 0.0.0.0:$PORT --worker-class gevent --worker-connections 1000 --timeout 120 --log-file - --capture-output
2+
app: opentelemetry-instrument gunicorn config.wsgi:application --bind 0.0.0.0:$PORT --worker-class gevent --worker-connections 1000 --timeout 120 --log-file - --capture-output

config/settings/base.py

+49-37
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@
1515
from pathlib import Path
1616

1717
import dj_database_url
18+
import requests
1819
import sentry_sdk
20+
from dbt_copilot_python.database import database_url_from_env
21+
from dbt_copilot_python.network import setup_allowed_hosts
22+
from dbt_copilot_python.utility import is_copilot
23+
from django_log_formatter_asim import ASIMFormatter
1924
from django_log_formatter_ecs import ECSFormatter
2025
from environ import Env
2126
from sentry_sdk.integrations.django import DjangoIntegration
@@ -45,9 +50,10 @@
4550
DEBUG = env("DEBUG")
4651

4752
ALLOWED_HOSTS = env.list("ALLOWED_HOSTS", default=[])
48-
# Application definition
53+
ALLOWED_HOSTS = setup_allowed_hosts(ALLOWED_HOSTS)
4954

50-
ELASTIC_APM_ENABLED = env("ELASTIC_APM_ENABLED", default=not DEBUG)
55+
# Application definition
56+
ELASTIC_APM_ENABLED = env.bool("ELASTIC_APM_ENABLED", default=not DEBUG)
5157

5258
PRIORITISATION_STRATEGIC_ASSESSMENTS = env.bool(
5359
"PRIORITISATION_STRATEGIC_ASSESSMENTS", default=False
@@ -91,6 +97,7 @@
9197
"healthcheck",
9298
"reports",
9399
"users",
100+
"pingdom",
94101
]
95102

96103
INSTALLED_APPS = BASE_APPS + DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
@@ -148,11 +155,16 @@
148155
# Database
149156
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
150157

151-
DATABASES = {
152-
"default": dj_database_url.config(
153-
env="DATABASE_URL", conn_max_age=0, conn_health_checks=True, default=""
154-
)
155-
}
158+
if is_copilot():
159+
DATABASES = {
160+
"default": dj_database_url.config(
161+
default=database_url_from_env("DATABASE_ENV_VAR_KEY"),
162+
conn_max_age=0,
163+
conn_health_checks=True,
164+
)
165+
}
166+
else:
167+
DATABASES = {"default": env.db("DATABASE_URL")}
156168

157169

158170
# Password validation
@@ -196,12 +208,19 @@
196208
STATICFILES_DIRS = [
197209
str(ROOT_DIR / "core/frontend/dist/"),
198210
]
199-
STATICFILES_STORAGE = "whitenoise.storage.CompressedStaticFilesStorage"
211+
200212
STATICFILES_FINDERS = (
201213
"django.contrib.staticfiles.finders.FileSystemFinder",
202214
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
203215
)
204216

217+
STORAGES = {
218+
"staticfiles": {
219+
"BACKEND": env.str(
220+
"STATICFILES_STORAGE", "whitenoise.storage.CompressedStaticFilesStorage"
221+
),
222+
},
223+
}
205224

206225
USER_DATA_CACHE_TIME = 3600
207226
METADATA_CACHE_TIME = "10600"
@@ -271,15 +290,19 @@
271290
"version": 1,
272291
"disable_existing_loggers": False,
273292
"formatters": {
274-
"ecs_formatter": {
275-
"()": ECSFormatter,
276-
},
293+
"asim_formatter": {"()": ASIMFormatter},
294+
"ecs_formatter": {"()": ECSFormatter},
277295
"simple": {
278296
"format": "{asctime} {levelname} {message}",
279297
"style": "{",
280298
},
281299
},
282300
"handlers": {
301+
"asim": {
302+
"class": "logging.StreamHandler",
303+
"stream": sys.stdout, # noqa F405
304+
"formatter": "asim_formatter",
305+
},
283306
"ecs": {
284307
"class": "logging.StreamHandler",
285308
"stream": sys.stdout, # noqa F405
@@ -292,47 +315,34 @@
292315
},
293316
},
294317
"root": {
295-
"handlers": [
296-
"ecs",
297-
"stdout",
298-
],
318+
"handlers": ["asim", "ecs", "stdout"],
299319
"level": os.getenv("ROOT_LOG_LEVEL", "INFO"), # noqa F405
300320
},
301321
"loggers": {
302-
"": {
303-
"handlers": [
304-
"ecs",
305-
"stdout",
306-
],
307-
"level": os.getenv("DJANGO_LOG_LEVEL", "INFO"), # noqa F405
308-
"propagate": False,
309-
},
310322
"django": {
311-
"handlers": [
312-
"ecs",
313-
"stdout",
314-
],
323+
"handlers": ["asim", "ecs", "stdout"],
315324
"level": os.getenv("DJANGO_LOG_LEVEL", "INFO"), # noqa F405
316325
"propagate": False,
317326
},
318327
"django.server": {
319-
"handlers": [
320-
"ecs",
321-
"stdout",
322-
],
328+
"handlers": ["asim", "ecs", "stdout"],
323329
"level": os.getenv("DJANGO_SERVER_LOG_LEVEL", "ERROR"), # noqa F405
324330
"propagate": False,
325331
},
326332
"django.db.backends": {
327-
"handlers": [
328-
"ecs",
329-
"stdout",
330-
],
333+
"handlers": ["asim", "ecs", "stdout"],
331334
"level": os.getenv("DJANGO_DB_LOG_LEVEL", "ERROR"), # noqa F405
332335
"propagate": False,
333336
},
334337
},
335338
}
339+
340+
341+
# Django Log Formatter ASIM settings
342+
if is_copilot():
343+
DLFA_TRACE_HEADERS = ("X-B3-TraceId", "X-B3-SpanId")
344+
345+
336346
DLFE_APP_NAME = True
337347
DLFE_LOG_SENSITIVE_USER_DATA = True
338348

@@ -343,9 +353,11 @@
343353

344354
# Sentry
345355
SENTRY_BROWSER_TRACES_SAMPLE_RATE = env.float("SENTRY_BROWSER_TRACES_SAMPLE_RATE", 0.0)
346-
if not DEBUG:
356+
SENTRY_DNS = env("SENTRY_DSN", default=None)
357+
358+
if SENTRY_DNS:
347359
sentry_sdk.init(
348-
dsn=env("SENTRY_DSN"),
360+
dsn=SENTRY_DNS,
349361
environment=env("SENTRY_ENVIRONMENT"),
350362
integrations=[
351363
DjangoIntegration(),

config/settings/hardening.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@
1818

1919
CSRF_COOKIE_HTTPONLY = True
2020

21-
CORS_ALLOWED_ORIGINS = env.list("ALLOWED_HOSTS", default=[])
21+
CORS_ALLOWED_ORIGINS = env.list("CORS_ALLOWED_ORIGINS", default=[])

config/settings/test.py

-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88

99
WHITENOISE_AUTOREFRESH = True
1010

11-
STATICFILES_STORAGE = "django.contrib.staticfiles.storage.StaticFilesStorage"
12-
1311
PASSWORD_HASHERS = [
1412
"django.contrib.auth.hashers.MD5PasswordHasher",
1513
]

config/urls.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
from django.contrib import admin
2020
from django.urls import include, path
2121

22+
from pingdom.urls import urlpatterns as pingdom_urlpatterns
23+
2224
urlpatterns = []
2325

2426
if settings.DEBUG and settings.DJANGO_ENV == "local":
@@ -33,4 +35,4 @@
3335
path("", include("reports.urls", namespace="reports")),
3436
path("", include("core.urls", namespace="core")),
3537
path("", include("healthcheck.urls", namespace="healthcheck")),
36-
]
38+
] + pingdom_urlpatterns

config/wsgi.py

+2
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,7 @@
88
"""
99

1010
from django.core.wsgi import get_wsgi_application
11+
from opentelemetry.instrumentation.wsgi import OpenTelemetryMiddleware
1112

1213
application = get_wsgi_application()
14+
application = OpenTelemetryMiddleware(application)

core/frontend/src/js/components/AttachmentForm.js

+8-7
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ ma.components.AttachmentForm = (function (jessie) {
99
fileUpload,
1010
attachments,
1111
submitButton,
12-
multiDocument = true
12+
multiDocument = true,
1313
) {
1414
if (!fileUpload) {
1515
throw new Error("fileUpload is required");
@@ -44,7 +44,7 @@ ma.components.AttachmentForm = (function (jessie) {
4444
this.fileUpload.setProgress(
4545
"uploading file... " +
4646
Math.floor((e.loaded / e.total) * 100) +
47-
"%"
47+
"%",
4848
);
4949
}
5050
}
@@ -85,15 +85,16 @@ ma.components.AttachmentForm = (function (jessie) {
8585
this.attachments.addItem(item, this.multiDocument);
8686
} else {
8787
this.showError(
88-
"There was an issue uploading the document, try again"
88+
"There was an issue uploading the document, try again",
8989
);
9090
}
9191
} else if (responseCode === 401) {
9292
this.showError(data.message);
9393
} else {
9494
var message =
95-
data.message ||
96-
"A system error has occured, so the file has not been uploaded. Try again.";
95+
// data.message ||
96+
//"A system error has occured, so the file has not been uploaded. Try again.;
97+
responseCode;
9798
this.showError(message);
9899
}
99100
};
@@ -109,15 +110,15 @@ ma.components.AttachmentForm = (function (jessie) {
109110
xhr2.upload.addEventListener(
110111
"progress",
111112
bind(this.updateProgress, this),
112-
false
113+
false,
113114
);
114115
}
115116

116117
xhr2.addEventListener("error", bind(this.transferFailed, this), false);
117118
xhr2.addEventListener(
118119
"abort",
119120
bind(this.transferCanceled, this),
120-
false
121+
false,
121122
);
122123
xhr2.addEventListener("load", bind(this.loaded, this), false);
123124

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
"build": "webpack --config webpack.config.js --mode production",
1010
"heroku-prebuild": "",
1111
"heroku-postbuild": "npm run build",
12-
"lint": "eslint --fix --ext .js ./core/frontend/src/js"
12+
"lint": "eslint --fix --ext .js ./core/frontend/src/js",
13+
"start": "echo starting"
1314
},
1415
"dependencies": {
1516
"@babel/core": "^7.11.5",

pingdom/apps.py

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from django.apps import AppConfig
2+
3+
4+
class PingdomConfig(AppConfig):
5+
name = "pingdom"
6+
verbose_name = "Pingdom config"

pingdom/services.py

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from django.db import DatabaseError
2+
3+
from healthcheck.models import HealthCheck
4+
5+
6+
class CheckDatabase:
7+
name = "database"
8+
9+
def check(self):
10+
try:
11+
HealthCheck.objects.exists()
12+
return True, ""
13+
except DatabaseError as e:
14+
return False, e
15+
16+
17+
services_to_check = (CheckDatabase,)

pingdom/urls.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from django.urls import path
2+
3+
from pingdom.views import pingdom
4+
5+
urlpatterns = [
6+
path("pingdom/ping.xml", pingdom, name="pingdom"),
7+
]

pingdom/views.py

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from django.http import HttpResponse
2+
3+
from pingdom.services import services_to_check
4+
5+
PINGDOM_TEMPLATE = """<?xml version="1.0" encoding="UTF-8"?>
6+
<pingdom_http_custom_check>
7+
<status>{status}</status>
8+
</pingdom_http_custom_check>\n"""
9+
10+
COMMENT_TEMPLATE = "<!--{comment}-->\n"
11+
12+
13+
def pingdom(request):
14+
print("processing")
15+
checked = {}
16+
for service in services_to_check:
17+
checked[service.name] = service().check()
18+
19+
if all(item[0] for item in checked.values()):
20+
return HttpResponse(
21+
PINGDOM_TEMPLATE.format(status="OK"), content_type="text/xml"
22+
)
23+
else:
24+
body = PINGDOM_TEMPLATE.format(status="FALSE")
25+
for service_result in filter(lambda x: x[0] is False, checked.values()):
26+
body += COMMENT_TEMPLATE.format(comment=service_result[1])
27+
return HttpResponse(body, status=500, content_type="text/xml")

0 commit comments

Comments
 (0)