BTHLABS-64: Support for customized environments

Co-authored-by: Tomek Wójcik <labs@tomekwojcik.pl>
Co-committed-by: Tomek Wójcik <labs@tomekwojcik.pl>
This commit is contained in:
2025-10-27 19:04:48 +00:00
committed by Tomek Wójcik
parent 168657bd14
commit d8bbe57b17
25 changed files with 291 additions and 173 deletions

View File

@@ -29,8 +29,8 @@ jobs:
roleId: "${{ secrets.VAULT_ROLE_ID }}" roleId: "${{ secrets.VAULT_ROLE_ID }}"
secretId: "${{ secrets.VAULT_SECRET_ID }}" secretId: "${{ secrets.VAULT_SECRET_ID }}"
secrets: | secrets: |
gitea/data/docker-hosted.nexus.bthlabs.pl username | DOCKER_USERNAME ; gitea/data/docker-hosted.nexus.bthlab.bthlabs.net username | DOCKER_USERNAME ;
gitea/data/docker-hosted.nexus.bthlabs.pl password | DOCKER_PASSWORD gitea/data/docker-hosted.nexus.bthlab.bthlabs.net password | DOCKER_PASSWORD
- name: "Set up Docker Buildx" - name: "Set up Docker Buildx"
id: "setup-docker-buildx" id: "setup-docker-buildx"
uses: "docker/setup-buildx-action@v3" uses: "docker/setup-buildx-action@v3"
@@ -44,7 +44,7 @@ jobs:
- name: "Login to Docket Registry" - name: "Login to Docket Registry"
uses: "docker/login-action@v3" uses: "docker/login-action@v3"
with: with:
registry: "docker-hosted.nexus.bthlabs.pl" registry: "nexus.bthlab.bthlabs.net:8002"
username: "${{ steps.import-secrets.outputs.DOCKER_USERNAME }}" username: "${{ steps.import-secrets.outputs.DOCKER_USERNAME }}"
password: "${{ steps.import-secrets.outputs.DOCKER_PASSWORD }}" password: "${{ steps.import-secrets.outputs.DOCKER_PASSWORD }}"
- name: "Build `backend-deployment` image" - name: "Build `backend-deployment` image"
@@ -58,28 +58,11 @@ jobs:
--cache-from "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket" \ --cache-from "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket" \
--cache-to "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket,mode=max" \ --cache-to "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket,mode=max" \
--push \ --push \
--platform linux/amd64,linux/arm64 \ --platform linux/amd64 \
--build-arg IMAGE_ID="deployment.${SHORT_SHA}" \ --build-arg IMAGE_ID="deployment.${SHORT_SHA}" \
-f services/backend/Dockerfile \ -f services/backend/Dockerfile \
--target deployment \ --target deployment \
-t "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:deployment-${VERSION}-${BUILD}" \ -t "nexus.bthlab.bthlabs.net:8002/hotpocket/backend:deployment-${VERSION}-${BUILD}" \
services/
- name: "Build `backend-aio` image"
env:
SHORT_SHA: "${{ steps.get-build-options.outputs.short-sha }}"
VERSION: "${{ steps.get-backend-version.outputs.version }}"
BUILD: "${{ steps.get-backend-version.outputs.build-number }}"
run: |
set -x
docker buildx build \
--cache-from "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket" \
--cache-to "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket,mode=max" \
--push \
--platform linux/amd64,linux/arm64 \
--build-arg IMAGE_ID="aio.${SHORT_SHA}" \
-f services/backend/Dockerfile \
--target aio \
-t "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:aio-${VERSION}-${BUILD}" \
services/ services/
deploy: deploy:
@@ -143,7 +126,7 @@ jobs:
cd deployment/hotpocket.bthlab ; cd deployment/hotpocket.bthlab ;
export KUBECONFIG="/opt/k8s/etc/kubeconfig" ; export KUBECONFIG="/opt/k8s/etc/kubeconfig" ;
/opt/k8s/bin/kubectl config use-context ${KUBERNETES_CLUSTER} ; /opt/k8s/bin/kubectl config use-context ${KUBERNETES_CLUSTER} ;
/opt/k8s/bin/kubectl -n ${KUBERNETES_NAMESPACE} set image cronjobs/backend-job-migrations migrations=docker-hosted.nexus.bthlabs.pl/hotpocket/backend:${BACKEND_TAG} ; /opt/k8s/bin/kubectl -n ${KUBERNETES_NAMESPACE} set image cronjobs/backend-job-migrations migrations=nexus.bthlab.bthlabs.net:8002/hotpocket/backend:${BACKEND_TAG} ;
/opt/k8s/bin/kubectl -n ${KUBERNETES_NAMESPACE} delete jobs --ignore-not-found=true backend-job-migrations ; /opt/k8s/bin/kubectl -n ${KUBERNETES_NAMESPACE} delete jobs --ignore-not-found=true backend-job-migrations ;
/opt/k8s/bin/kubectl -n ${KUBERNETES_NAMESPACE} create job backend-job-migrations --from=cronjob/backend-job-migrations ; /opt/k8s/bin/kubectl -n ${KUBERNETES_NAMESPACE} create job backend-job-migrations --from=cronjob/backend-job-migrations ;
/opt/k8s/bin/kubectl -n ${KUBERNETES_NAMESPACE} wait --for=condition=complete --timeout=300s job/backend-job-migrations /opt/k8s/bin/kubectl -n ${KUBERNETES_NAMESPACE} wait --for=condition=complete --timeout=300s job/backend-job-migrations
@@ -158,6 +141,6 @@ jobs:
cd deployment/hotpocket.bthlab ; cd deployment/hotpocket.bthlab ;
export KUBECONFIG="/opt/k8s/etc/kubeconfig" ; export KUBECONFIG="/opt/k8s/etc/kubeconfig" ;
/opt/k8s/bin/kubectl config use-context ${KUBERNETES_CLUSTER} ; /opt/k8s/bin/kubectl config use-context ${KUBERNETES_CLUSTER} ;
/opt/k8s/bin/kustomize edit set image hotpocket-backend=docker-hosted.nexus.bthlabs.pl/hotpocket/backend:${BACKEND_TAG} ; /opt/k8s/bin/kustomize edit set image hotpocket-backend=nexus.bthlab.bthlabs.net:8002/hotpocket/backend:${BACKEND_TAG} ;
/opt/k8s/bin/kustomize build . | /opt/k8s/bin/kubectl apply -f - /opt/k8s/bin/kustomize build . | /opt/k8s/bin/kubectl apply -f -
) )

1
.gitignore vendored
View File

@@ -1,4 +1,5 @@
.ci/ .ci/
.envrc* .envrc*
.ipythonhome/ .ipythonhome/
services/vendor/
/docker-compose-ci-*.yaml /docker-compose-ci-*.yaml

View File

@@ -1,5 +1,7 @@
DJANGO_SETTINGS_MODULE=hotpocket_backend.settings.deployment.admin DJANGO_SETTINGS_MODULE=hotpocket_bthlabs.settings.admin
HOTPOCKET_BACKEND_GUNICORN_WORKERS=2 HOTPOCKET_BACKEND_GUNICORN_WORKERS=2
HOTPOCKET_BACKEND_SECRETS_PACKAGE=hotpocket_bthlabs.secrets
HOTPOCKET_BACKEND_ENV=development
HOTPOCKET_BACKEND_APP=admin HOTPOCKET_BACKEND_APP=admin
HOTPOCKET_BACKEND_SECRET_KEY=thisissecret HOTPOCKET_BACKEND_SECRET_KEY=thisissecret
HOTPOCKET_BACKEND_ALLOWED_HOSTS=thisissecret HOTPOCKET_BACKEND_ALLOWED_HOSTS=admin.hotpocket.bthlab.bthlabs.net

View File

@@ -1,7 +1,9 @@
DJANGO_SETTINGS_MODULE=hotpocket_backend.settings.deployment.webapp DJANGO_SETTINGS_MODULE=hotpocket_bthlabs.settings.webapp
HOTPOCKET_BACKEND_GUNICORN_WORKERS=2 HOTPOCKET_BACKEND_GUNICORN_WORKERS=2
HOTPOCKET_BACKEND_SECRETS_PACKAGE=hotpocket_bthlabs.secrets
HOTPOCKET_BACKEND_ENV=development
HOTPOCKET_BACKEND_APP=webapp HOTPOCKET_BACKEND_APP=webapp
HOTPOCKET_BACKEND_SECRET_KEY=thisissecret HOTPOCKET_BACKEND_SECRET_KEY=thisissecret
HOTPOCKET_BACKEND_ALLOWED_HOSTS=thisissecret HOTPOCKET_BACKEND_ALLOWED_HOSTS=app.hotpocket.bthlab.bthlabs.net
HOTPOCKET_BACKEND_SAVES_SAVE_ADAPTER=hotpocket_backend.apps.saves.adapters.postgres:PostgresSaveAdapter HOTPOCKET_BACKEND_SAVES_SAVE_ADAPTER=hotpocket_backend.apps.saves.adapters.postgres:PostgresSaveAdapter
HOTPOCKET_BACKEND_SAVES_ASSOCIATION_ADAPTER=hotpocket_backend.apps.saves.adapters.postgres:PostgresAssociationAdapter HOTPOCKET_BACKEND_SAVES_ASSOCIATION_ADAPTER=hotpocket_backend.apps.saves.adapters.postgres:PostgresAssociationAdapter

View File

@@ -4,6 +4,7 @@ kind: Kustomization
resources: resources:
- resources/namespace.yaml - resources/namespace.yaml
- resources/volumes.yaml - resources/volumes.yaml
- resources/backend/config-map-local-deps.yaml
- resources/backend/job-migrations.yaml - resources/backend/job-migrations.yaml
- resources/backend/webapp.yaml - resources/backend/webapp.yaml
- resources/backend/webapp-service.yaml - resources/backend/webapp-service.yaml
@@ -35,5 +36,5 @@ patches: []
images: images:
- name: hotpocket-backend - name: hotpocket-backend
newName: docker-hosted.nexus.bthlabs.pl/hotpocket/backend newName: nexus.bthlab.bthlabs.net:8002/hotpocket/backend
newTag: deployment-v25.10.4-01 newTag: deployment-8e09ae51-01

View File

@@ -26,7 +26,7 @@ spec:
containers: containers:
- name: app - name: app
image: hotpocket-backend:latest image: hotpocket-backend:latest
command: args:
- "/srv/venv/bin/gunicorn" - "/srv/venv/bin/gunicorn"
- "-c" - "-c"
- "/srv/lib/gunicorn.conf.py" - "/srv/lib/gunicorn.conf.py"
@@ -37,36 +37,21 @@ spec:
- configMapRef: - configMapRef:
name: backend-admin-config name: backend-admin-config
env: env:
- name: HOTPOCKET_BACKEND_SECRET_KEY - name: VAULT_URL
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-admin name: backend-vault
key: secret_key key: url
- name: HOTPOCKET_BACKEND_ALLOWED_HOSTS - name: VAULT_ROLE_ID
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-admin name: backend-vault
key: allowed_hosts key: role_id
- name: HOTPOCKET_BACKEND_DATABASE_USER - name: VAULT_SECRET_ID
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-postgres name: backend-vault
key: username key: secret_id
- name: HOTPOCKET_BACKEND_DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: backend-postgres
key: password
- name: HOTPOCKET_BACKEND_CELERY_BROKER_URL
valueFrom:
secretKeyRef:
name: backend-celery
key: broker_url
- name: HOTPOCKET_BACKEND_CELERY_RESULT_BACKEND
valueFrom:
secretKeyRef:
name: backend-celery
key: result_backend
ports: ports:
- containerPort: 8000 - containerPort: 8000
name: http name: http
@@ -91,6 +76,15 @@ spec:
name: shm name: shm
- mountPath: /srv/run - mountPath: /srv/run
name: backend-admin-srv-run name: backend-admin-srv-run
- name: backend-admin-local-deps
mountPath: "/srv/lib/requirements.txt"
subPath: "requirements.txt"
- name: backend-admin-local-deps
mountPath: "/srv/etc/entrypoint.d/01-install-extra-deps.sh"
subPath: "01-install-extra-deps.sh"
- name: backend-admin-local-deps
mountPath: "/srv/etc/entrypoint.d/99-collectstatic.sh"
subPath: "99-collectstatic.sh"
dnsPolicy: ClusterFirst dnsPolicy: ClusterFirst
restartPolicy: Always restartPolicy: Always
volumes: volumes:
@@ -99,3 +93,7 @@ spec:
medium: Memory medium: Memory
- name: backend-admin-srv-run - name: backend-admin-srv-run
emptyDir: {} emptyDir: {}
- name: backend-admin-local-deps
configMap:
name: "backend-local-deps"
defaultMode: 0755

View File

@@ -20,7 +20,7 @@ spec:
containers: containers:
- name: app - name: app
image: hotpocket-backend:latest image: hotpocket-backend:latest
command: args:
- "/srv/venv/bin/celery" - "/srv/venv/bin/celery"
- "-A" - "-A"
- "hotpocket_backend.celery:app" - "hotpocket_backend.celery:app"
@@ -35,36 +35,21 @@ spec:
- configMapRef: - configMapRef:
name: backend-webapp-config name: backend-webapp-config
env: env:
- name: HOTPOCKET_BACKEND_SECRET_KEY - name: VAULT_URL
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-webapp name: backend-vault
key: secret_key key: url
- name: HOTPOCKET_BACKEND_ALLOWED_HOSTS - name: VAULT_ROLE_ID
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-webapp name: backend-vault
key: allowed_hosts key: role_id
- name: HOTPOCKET_BACKEND_DATABASE_USER - name: VAULT_SECRET_ID
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-postgres name: backend-vault
key: username key: secret_id
- name: HOTPOCKET_BACKEND_DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: backend-postgres
key: password
- name: HOTPOCKET_BACKEND_CELERY_BROKER_URL
valueFrom:
secretKeyRef:
name: backend-celery
key: broker_url
- name: HOTPOCKET_BACKEND_CELERY_RESULT_BACKEND
valueFrom:
secretKeyRef:
name: backend-celery
key: result_backend
volumeMounts: volumeMounts:
- mountPath: /dev/shm - mountPath: /dev/shm
name: shm name: shm
@@ -72,6 +57,12 @@ spec:
name: backend-celery-beat-srv-run name: backend-celery-beat-srv-run
- mountPath: /srv/uploads - mountPath: /srv/uploads
name: backend-celery-beat-srv-uploads name: backend-celery-beat-srv-uploads
- name: backend-admin-local-deps
mountPath: "/srv/lib/requirements.txt"
subPath: "requirements.txt"
- name: backend-admin-local-deps
mountPath: "/srv/etc/entrypoint.d/01-install-extra-deps.sh"
subPath: "01-install-extra-deps.sh"
dnsPolicy: ClusterFirst dnsPolicy: ClusterFirst
restartPolicy: Always restartPolicy: Always
volumes: volumes:
@@ -83,3 +74,7 @@ spec:
claimName: backend-celery-beat-run claimName: backend-celery-beat-run
- name: backend-celery-beat-srv-uploads - name: backend-celery-beat-srv-uploads
emptyDir: {} emptyDir: {}
- name: backend-admin-local-deps
configMap:
name: "backend-local-deps"
defaultMode: 0755

View File

@@ -26,7 +26,7 @@ spec:
containers: containers:
- name: app - name: app
image: hotpocket-backend:latest image: hotpocket-backend:latest
command: args:
- "/srv/venv/bin/celery" - "/srv/venv/bin/celery"
- "-A" - "-A"
- "hotpocket_backend.celery:app" - "hotpocket_backend.celery:app"
@@ -43,36 +43,21 @@ spec:
- configMapRef: - configMapRef:
name: backend-webapp-config name: backend-webapp-config
env: env:
- name: HOTPOCKET_BACKEND_SECRET_KEY - name: VAULT_URL
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-webapp name: backend-vault
key: secret_key key: url
- name: HOTPOCKET_BACKEND_ALLOWED_HOSTS - name: VAULT_ROLE_ID
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-webapp name: backend-vault
key: allowed_hosts key: role_id
- name: HOTPOCKET_BACKEND_DATABASE_USER - name: VAULT_SECRET_ID
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-postgres name: backend-vault
key: username key: secret_id
- name: HOTPOCKET_BACKEND_DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: backend-postgres
key: password
- name: HOTPOCKET_BACKEND_CELERY_BROKER_URL
valueFrom:
secretKeyRef:
name: backend-celery
key: broker_url
- name: HOTPOCKET_BACKEND_CELERY_RESULT_BACKEND
valueFrom:
secretKeyRef:
name: backend-celery
key: result_backend
volumeMounts: volumeMounts:
- mountPath: /dev/shm - mountPath: /dev/shm
name: shm name: shm
@@ -80,6 +65,12 @@ spec:
name: backend-celery-worker-srv-run name: backend-celery-worker-srv-run
- mountPath: /srv/uploads - mountPath: /srv/uploads
name: backend-celery-worker-srv-uploads name: backend-celery-worker-srv-uploads
- name: backend-admin-local-deps
mountPath: "/srv/lib/requirements.txt"
subPath: "requirements.txt"
- name: backend-admin-local-deps
mountPath: "/srv/etc/entrypoint.d/01-install-extra-deps.sh"
subPath: "01-install-extra-deps.sh"
dnsPolicy: ClusterFirst dnsPolicy: ClusterFirst
restartPolicy: Always restartPolicy: Always
volumes: volumes:
@@ -91,3 +82,7 @@ spec:
- name: backend-celery-worker-srv-uploads - name: backend-celery-worker-srv-uploads
persistentVolumeClaim: persistentVolumeClaim:
claimName: backend-uploads claimName: backend-uploads
- name: backend-admin-local-deps
configMap:
name: "backend-local-deps"
defaultMode: 0755

View File

@@ -0,0 +1,18 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: backend-local-deps
namespace: hotpocket-development
data:
01-install-extra-deps.sh: |
#!/usr/bin/env bash
export PIP_INDEX_URL="https://nexus.bthlabs.pl/repository/pypi/simple/"
/srv/venv/bin/pip install -r /srv/lib/requirements.txt
99-collectstatic.sh: |
#!/usr/bin/env bash
(
cd /srv/app;
./manage.py collectstatic --no-input
)
requirements.txt: |
hotpocket_bthlabs==25.10.27

View File

@@ -22,7 +22,7 @@ spec:
containers: containers:
- name: migrations - name: migrations
image: hotpocket-backend:latest image: hotpocket-backend:latest
command: args:
- "./manage.py" - "./manage.py"
- "migrate" - "migrate"
envFrom: envFrom:
@@ -31,36 +31,21 @@ spec:
- configMapRef: - configMapRef:
name: backend-webapp-config name: backend-webapp-config
env: env:
- name: HOTPOCKET_BACKEND_SECRET_KEY - name: VAULT_URL
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-webapp name: backend-vault
key: secret_key key: url
- name: HOTPOCKET_BACKEND_ALLOWED_HOSTS - name: VAULT_ROLE_ID
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-webapp name: backend-vault
key: allowed_hosts key: role_id
- name: HOTPOCKET_BACKEND_DATABASE_USER - name: VAULT_SECRET_ID
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-postgres name: backend-vault
key: username key: secret_id
- name: HOTPOCKET_BACKEND_DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: backend-postgres
key: password
- name: HOTPOCKET_BACKEND_CELERY_BROKER_URL
valueFrom:
secretKeyRef:
name: backend-celery
key: broker_url
- name: HOTPOCKET_BACKEND_CELERY_RESULT_BACKEND
valueFrom:
secretKeyRef:
name: backend-celery
key: result_backend
volumeMounts: volumeMounts:
- mountPath: /dev/shm - mountPath: /dev/shm
name: shm name: shm
@@ -68,6 +53,12 @@ spec:
name: backend-webapp-srv-run name: backend-webapp-srv-run
- mountPath: /srv/uploads - mountPath: /srv/uploads
name: backend-webapp-srv-uploads name: backend-webapp-srv-uploads
- name: backend-admin-local-deps
mountPath: "/srv/lib/requirements.txt"
subPath: "requirements.txt"
- name: backend-admin-local-deps
mountPath: "/srv/etc/entrypoint.d/01-install-extra-deps.sh"
subPath: "01-install-extra-deps.sh"
dnsPolicy: ClusterFirst dnsPolicy: ClusterFirst
restartPolicy: Never restartPolicy: Never
volumes: volumes:
@@ -78,3 +69,7 @@ spec:
emptyDir: {} emptyDir: {}
- name: backend-webapp-srv-uploads - name: backend-webapp-srv-uploads
emptyDir: {} emptyDir: {}
- name: backend-admin-local-deps
configMap:
name: "backend-local-deps"
defaultMode: 0755

View File

@@ -26,7 +26,7 @@ spec:
containers: containers:
- name: app - name: app
image: hotpocket-backend:latest image: hotpocket-backend:latest
command: args:
- "/srv/venv/bin/gunicorn" - "/srv/venv/bin/gunicorn"
- "-c" - "-c"
- "/srv/lib/gunicorn.conf.py" - "/srv/lib/gunicorn.conf.py"
@@ -37,36 +37,21 @@ spec:
- configMapRef: - configMapRef:
name: backend-webapp-config name: backend-webapp-config
env: env:
- name: HOTPOCKET_BACKEND_SECRET_KEY - name: VAULT_URL
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-webapp name: backend-vault
key: secret_key key: url
- name: HOTPOCKET_BACKEND_ALLOWED_HOSTS - name: VAULT_ROLE_ID
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-webapp name: backend-vault
key: allowed_hosts key: role_id
- name: HOTPOCKET_BACKEND_DATABASE_USER - name: VAULT_SECRET_ID
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-postgres name: backend-vault
key: username key: secret_id
- name: HOTPOCKET_BACKEND_DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: backend-postgres
key: password
- name: HOTPOCKET_BACKEND_CELERY_BROKER_URL
valueFrom:
secretKeyRef:
name: backend-celery
key: broker_url
- name: HOTPOCKET_BACKEND_CELERY_RESULT_BACKEND
valueFrom:
secretKeyRef:
name: backend-celery
key: result_backend
ports: ports:
- containerPort: 8000 - containerPort: 8000
name: http name: http
@@ -93,6 +78,15 @@ spec:
name: backend-webapp-srv-run name: backend-webapp-srv-run
- mountPath: /srv/uploads - mountPath: /srv/uploads
name: backend-webapp-srv-uploads name: backend-webapp-srv-uploads
- name: backend-admin-local-deps
mountPath: "/srv/lib/requirements.txt"
subPath: "requirements.txt"
- name: backend-admin-local-deps
mountPath: "/srv/etc/entrypoint.d/01-install-extra-deps.sh"
subPath: "01-install-extra-deps.sh"
- name: backend-admin-local-deps
mountPath: "/srv/etc/entrypoint.d/99-collectstatic.sh"
subPath: "99-collectstatic.sh"
dnsPolicy: ClusterFirst dnsPolicy: ClusterFirst
restartPolicy: Always restartPolicy: Always
volumes: volumes:
@@ -104,3 +98,7 @@ spec:
- name: backend-webapp-srv-uploads - name: backend-webapp-srv-uploads
persistentVolumeClaim: persistentVolumeClaim:
claimName: backend-uploads claimName: backend-uploads
- name: backend-admin-local-deps
configMap:
name: "backend-local-deps"
defaultMode: 0755

View File

@@ -13,4 +13,5 @@ backend/hotpocket_backend/settings/metal/
backend/hotpocket_backend/static/ backend/hotpocket_backend/static/
extension/node_modules/ extension/node_modules/
extension/dist/ extension/dist/
vendor/
.envrc* .envrc*

View File

@@ -1,12 +1,25 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import annotations from __future__ import annotations
import logging
from django.apps import AppConfig from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from hotpocket_backend.apps.core.conf import settings
LOGGER = logging.getLogger(__name__)
class CoreConfig(AppConfig): class CoreConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField' default_auto_field = 'django.db.models.BigAutoField'
label = 'core' label = 'core'
name = 'hotpocket_backend.apps.core' name = 'hotpocket_backend.apps.core'
verbose_name = _('Core') verbose_name = _('Core')
def ready(self):
LOGGER.info(
'HotPocket Backend ready: env=`%s` app=`%s`',
settings.ENV.name,
settings.APP.name,
)

View File

@@ -6,7 +6,7 @@ import typing
from hotpocket_backend.secrets.admin import AdminSecrets from hotpocket_backend.secrets.admin import AdminSecrets
from hotpocket_backend.secrets.webapp import WebAppSecrets from hotpocket_backend.secrets.webapp import WebAppSecrets
from hotpocket_common.constants import App, Env from hotpocket_common.constants import App, Environment
class PSettings(typing.Protocol): class PSettings(typing.Protocol):
@@ -16,7 +16,7 @@ class PSettings(typing.Protocol):
SECRET_KEY: str SECRET_KEY: str
APP: App APP: App
ENV: Env ENV: Environment
SECRETS: AdminSecrets | WebAppSecrets SECRETS: AdminSecrets | WebAppSecrets
@@ -32,3 +32,9 @@ class PSettings(typing.Protocol):
UPLOADS_PATH: pathlib.Path UPLOADS_PATH: pathlib.Path
AUTH_KEY_TTL: int AUTH_KEY_TTL: int
UI_BASE_HEAD_INCLUDES: list
UI_BASE_SCRIPT_INCLUDES: list
UI_PAGE_HEAD_INCLUDES: list
UI_PAGE_SCRIPT_INCLUDES: list

View File

@@ -82,3 +82,21 @@ def appearance_settings(request: HttpRequest) -> dict:
return { return {
'APPEARANCE_SETTINGS': result, 'APPEARANCE_SETTINGS': result,
} }
def base_includes(request: HttpRequest) -> dict:
return {
'BASE_INCLUDES': {
'head': settings.UI_BASE_HEAD_INCLUDES,
'script': settings.UI_BASE_SCRIPT_INCLUDES,
},
}
def page_includes(request: HttpRequest) -> dict:
return {
'PAGE_INCLUDES': {
'head': settings.UI_PAGE_HEAD_INCLUDES,
'script': settings.UI_PAGE_SCRIPT_INCLUDES,
},
}

View File

@@ -31,11 +31,17 @@
<link rel="icon" type="image/png" sizes="32x32" href="{% static 'ui/img/icon-32.png' %}"> <link rel="icon" type="image/png" sizes="32x32" href="{% static 'ui/img/icon-32.png' %}">
<link rel="icon" type="image/png" sizes="16x16" href="{% static 'ui/img/icon-16.png' %}"> <link rel="icon" type="image/png" sizes="16x16" href="{% static 'ui/img/icon-16.png' %}">
<link rel="manifest" href="{% url 'ui.meta.manifest_json' %}"> <link rel="manifest" href="{% url 'ui.meta.manifest_json' %}">
{% for head_include in BASE_INCLUDES.head %}
{% include head_include %}
{% endfor %}
{% block page_head %}{% endblock %} {% block page_head %}{% endblock %}
</head> </head>
<body class="{% block body_class %}{% endblock %}" hx-headers='{"x-csrftoken": "{{ csrf_token }}"}'> <body class="{% block body_class %}{% endblock %}" hx-headers='{"x-csrftoken": "{{ csrf_token }}"}'>
{% block body %} {% block body %}
{% endblock %} {% endblock %}
{% block scripts %}{% endblock %} {% block scripts %}{% endblock %}
{% for script_include in BASE_INCLUDES.script %}
{% include script_include %}
{% endfor %}
</body> </body>
</html> </html>

View File

@@ -2,6 +2,12 @@
{% load i18n static ui %} {% load i18n static ui %}
{% block page_head %}
{% for head_include in PAGE_INCLUDES.head %}
{% include head_include %}
{% endfor %}
{% endblock %}
{% block body %} {% block body %}
<nav id="navbar" class="navbar navbar-expand-sm bg-body-tertiary fixed-top"> <nav id="navbar" class="navbar navbar-expand-sm bg-body-tertiary fixed-top">
<div class="container"> <div class="container">
@@ -153,7 +159,11 @@
<script src="{% static 'ui/js/hotpocket-backend.ui.BrowseAccountAppsView.js' %}" type="text/javascript"></script> <script src="{% static 'ui/js/hotpocket-backend.ui.BrowseAccountAppsView.js' %}" type="text/javascript"></script>
<script src="{% static 'ui/js/hotpocket-backend.ui.InlineCreateSaveForm.js' %}" type="text/javascript"></script> <script src="{% static 'ui/js/hotpocket-backend.ui.InlineCreateSaveForm.js' %}" type="text/javascript"></script>
<script src="{% static 'ui/js/hotpocket-backend.ui.PasteboardLink.js' %}" type="text/javascript"></script> <script src="{% static 'ui/js/hotpocket-backend.ui.PasteboardLink.js' %}" type="text/javascript"></script>
{% block page_scripts %}{% endblock %} {% for script_include in PAGE_INCLUDES.script %}
{% include script_include %}
{% endfor %}
{% block page_scripts %}
{% endblock %}
<script type="text/javascript"> <script type="text/javascript">
(() => { (() => {
window.HotPocket.run({ window.HotPocket.run({

View File

@@ -19,8 +19,12 @@ ALLOWED_HOSTS = []
ENV = Env(os.getenv('HOTPOCKET_BACKEND_ENV', None)) ENV = Env(os.getenv('HOTPOCKET_BACKEND_ENV', None))
APP = App(os.getenv('HOTPOCKET_BACKEND_APP', None)) APP = App(os.getenv('HOTPOCKET_BACKEND_APP', None))
HOTPOCKET_BACKEND_SECRETS_PACKAGE = os.getenv(
'HOTPOCKET_BACKEND_SECRETS_PACKAGE', 'hotpocket_backend.secrets',
)
SECRETS: BaseSecrets = load_secrets( SECRETS: BaseSecrets = load_secrets(
'hotpocket_backend.secrets', ENV.value, APP.value, HOTPOCKET_BACKEND_SECRETS_PACKAGE, ENV.value, APP.value,
) )
SECRET_KEY = SECRETS.SECRET_KEY SECRET_KEY = SECRETS.SECRET_KEY

View File

@@ -4,13 +4,15 @@ from __future__ import annotations
from pathlib import Path from pathlib import Path
from hotpocket_common.constants import App, Environment
BASE_DIR = Path(__file__).resolve().parent.parent.parent BASE_DIR = Path(__file__).resolve().parent.parent.parent
DEBUG = False DEBUG = False
ALLOWED_HOSTS = [] ALLOWED_HOSTS = []
ENV = 'build' ENV = Environment('BUILD', 'build')
APP = 'backend' APP = App.WEBAPP
INSTALLED_APPS = [ INSTALLED_APPS = [
'django.contrib.auth', 'django.contrib.auth',

View File

@@ -31,6 +31,11 @@ MIDDLEWARE = [
'django_htmx.middleware.HtmxMiddleware', 'django_htmx.middleware.HtmxMiddleware',
] ]
TEMPLATES[0]['OPTIONS']['context_processors'] += [ # noqa: F405
'hotpocket_backend.apps.ui.context_processors.base_includes',
'hotpocket_backend.apps.ui.context_processors.page_includes',
]
ROOT_URLCONF = 'hotpocket_backend.urls.webapp' ROOT_URLCONF = 'hotpocket_backend.urls.webapp'
LOGIN_REDIRECT_URL = '/accounts/post-login/' LOGIN_REDIRECT_URL = '/accounts/post-login/'
@@ -81,3 +86,9 @@ CORS_ALLOW_HEADERS = (
) )
AUTH_KEY_TTL = 30 AUTH_KEY_TTL = 30
UI_BASE_HEAD_INCLUDES = []
UI_BASE_SCRIPT_INCLUDES = []
UI_PAGE_HEAD_INCLUDES = []
UI_PAGE_SCRIPT_INCLUDES = []

View File

@@ -1190,14 +1190,14 @@ files = [
[[package]] [[package]]
name = "keep-it-secret" name = "keep-it-secret"
version = "1.2.0" version = "1.3.0"
description = "Keep It Secret by BTHLabs" description = "Keep It Secret by BTHLabs"
optional = false optional = false
python-versions = ">=3.10,<4.0" python-versions = ">=3.10,<4.0"
groups = ["main"] groups = ["main"]
files = [ files = [
{file = "keep_it_secret-1.2.0-py3-none-any.whl", hash = "sha256:aae8f3d3c1db93223ad3afb5c35c2c7202068b082b8bf7d199ed5bc610e63449"}, {file = "keep_it_secret-1.3.0-py3-none-any.whl", hash = "sha256:9efe032bd1efbf18fa0cc15b73e38e17e23ee8a8690ffab948f16368f8eb9126"},
{file = "keep_it_secret-1.2.0.tar.gz", hash = "sha256:2585591d451674e30c08fcdbba95de2180904069da149bca628cc51261720839"}, {file = "keep_it_secret-1.3.0.tar.gz", hash = "sha256:80d6907b296e1f520c1ad30f9748c75ed007bb91ec4db7a83b0cb1b200804f6c"},
] ]
[package.dependencies] [package.dependencies]
@@ -1208,6 +1208,11 @@ hvac = {version = ">=2.1.0", optional = true, markers = "extra == \"vault\""}
aws = ["boto3 (>=1.34.0)"] aws = ["boto3 (>=1.34.0)"]
vault = ["hvac (>=2.1.0)"] vault = ["hvac (>=2.1.0)"]
[package.source]
type = "legacy"
url = "https://nexus.bthlabs.pl/repository/pypi/simple"
reference = "nexus"
[[package]] [[package]]
name = "kombu" name = "kombu"
version = "5.5.4" version = "5.5.4"
@@ -2572,4 +2577,4 @@ brotli = ["brotli"]
[metadata] [metadata]
lock-version = "2.1" lock-version = "2.1"
python-versions = "^3.12" python-versions = "^3.12"
content-hash = "bdbe000a5510f8f6eadb468eaa66df87c65df006c05dbfdde0a660316efbb120" content-hash = "9ea38ee8174f679163c0b46cde1cb4eff4b7330db8a3b4649a7a910bdf5fe15d"

View File

@@ -22,7 +22,7 @@ django-crispy-forms = "2.4"
django-htmx = "1.26.0" django-htmx = "1.26.0"
hotpocket-common = {path = "../packages/common", develop = true} hotpocket-common = {path = "../packages/common", develop = true}
hotpocket-soa = {path = "../packages/soa", develop = true} hotpocket-soa = {path = "../packages/soa", develop = true}
keep-it-secret = {version = "1.2.0", extras = ["aws", "vault"]} keep-it-secret = {version = "1.3.0", extras = ["aws", "vault"]}
psycopg = {version = "3.2.10", extras = ["binary"]} psycopg = {version = "3.2.10", extras = ["binary"]}
pydantic = "2.12.2" pydantic = "2.12.2"
pyquery = "2.0.1" pyquery = "2.0.1"

View File

@@ -1,3 +1,3 @@
from .accounts import AccessTokenOriginApp # noqa: F401 from .accounts import AccessTokenOriginApp # noqa: F401
from .associations import AssociationsSearchMode # noqa: F401 from .associations import AssociationsSearchMode # noqa: F401
from .core import NULL_UUID, App, Env # noqa: F401 from .core import NULL_UUID, App, Env, Environment # noqa: F401

View File

@@ -2,16 +2,69 @@
from __future__ import annotations from __future__ import annotations
import enum import enum
import typing
import uuid import uuid
NULL_UUID = uuid.UUID('00000000-0000-0000-0000-000000000000') NULL_UUID = uuid.UUID('00000000-0000-0000-0000-000000000000')
class Env(enum.Enum): class Environment:
METAL = 'metal' def __init__(self, name: str, value: str):
DOCKER = 'docker' self._name = name
DEPLOYMENT = 'deployment' self._value = value
AIO = 'aio'
@property
def name(self) -> str:
return self._name
@property
def value(self) -> str:
return self._value
def __repr__(self) -> str:
return f'<Env {self.name}: {self.value}>'
def __str__(self) -> str:
return self.name
def to_rpc(self) -> str:
return self.value
class Environments:
METAL = Environment('METAL', 'metal')
DOCKER = Environment('DOCKER', 'docker')
DEPLOYMENT = Environment('DEPLOYMENT', 'deployment')
AIO = Environment('AIO', 'aio')
def _current_envs(self) -> typing.Generator[Environment, None, None]:
for attribute in dir(self):
candidate = getattr(self, attribute)
if isinstance(candidate, Environment):
yield candidate
def __call__(self, value: str) -> Environment:
result: Environment | None = None
for candidate in self._current_envs():
if candidate.value == value:
result = candidate
break
if result is None:
raise ValueError(f'Could not resolve env: `{value}`')
return result
def choices(self) -> list[tuple[str, str]]:
result = []
for env in self._current_envs():
result.append((env.value, env.name))
return result
Env = Environments()
class App(enum.Enum): class App(enum.Enum):

View File

@@ -146,6 +146,7 @@ def build(ctx: Context,
image_tag=None, image_tag=None,
machine=None, machine=None,
platform=None, platform=None,
registry='docker-hosted.nexus.bthlabs.pl',
): ):
image_tag = image_tag or '{target}.{{short_sha}}'.format(target=target) image_tag = image_tag or '{target}.{{short_sha}}'.format(target=target)
@@ -178,7 +179,7 @@ def build(ctx: Context,
if platform is not None if platform is not None
else '' else ''
), ),
f'-t docker-hosted.nexus.bthlabs.pl/hotpocket/{service}:{docker_build_ctx.tag}', # noqa: E501 f'-t {registry}/hotpocket/{service}:{docker_build_ctx.tag}', # noqa: E501
f'-f services/{service}/Dockerfile', f'-f services/{service}/Dockerfile',
f'--build-arg IMAGE_ID={image_tag}', f'--build-arg IMAGE_ID={image_tag}',
f'--target {docker_build_ctx.target}', f'--target {docker_build_ctx.target}',