Added backstage template for basic python django application

This commit is contained in:
evdo 2025-04-16 15:50:48 +02:00
parent 1a8c2846bc
commit 59ff83a8f8
14 changed files with 453 additions and 0 deletions

View file

@ -10,6 +10,7 @@ spec:
- ./app-with-bucket/template.yaml - ./app-with-bucket/template.yaml
- ./demo-go-hello-world/template.yaml - ./demo-go-hello-world/template.yaml
- ./spring-petclinic/template.yaml - ./spring-petclinic/template.yaml
- ./django_template/template.yaml
--- ---
apiVersion: backstage.io/v1alpha1 apiVersion: backstage.io/v1alpha1
kind: Location kind: Location

View file

@ -0,0 +1,51 @@
name: ci
on: push
jobs:
build:
runs-on: ubuntu-22.04
steps:
-
name: Repository meta
id: repository
run: |
registry=${{ github.server_url }}
registry=${registry##http*://}
echo "registry=${registry}" >> "$GITHUB_OUTPUT"
echo "registry=${registry}"
repository="$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')"
echo "repository=${repository}" >> "$GITHUB_OUTPUT"
echo "repository=${repository}"
-
name: Docker meta
uses: docker/metadata-action@v5
id: docker
with:
images: ${{ steps.repository.outputs.registry }}/${{ steps.repository.outputs.repository }}
-
name: Login to registry
uses: docker/login-action@v3
with:
registry: {% raw %} ${{ steps.repository.outputs.registry }}
username: ${{ secrets.PACKAGES_USER }}
password: ${{ secrets.PACKAGES_TOKEN }} {% endraw %}
-
name: Set up QEMU
uses: docker/setup-qemu-action@v3
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
buildkitd-flags: '--allow-insecure-entitlement network.host'
driver-opts: network=host
-
name: Build and push
uses: docker/build-push-action@v6
with:
push: true
allow: network.host
network: host
platforms: linux/amd64,linux/arm64
tags: ${{ steps.docker.outputs.tags }}

View file

@ -0,0 +1,10 @@
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "project/manage.py", "runserver", "0.0.0.0:8000"]

View file

@ -0,0 +1,35 @@
---
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: ${{ values.name }}
description: A Django application generated via a custom Backstage template.
annotations:
backstage.io/techdocs-ref: dir:.
backstage.io/kubernetes-label-selector: 'app=django'
backstage.io/kubernetes-namespace: ${{ values.namespace }}
argocd/app-name: ${{values.name | dump}}
links:
- url: https://gitea-192-168-197-3.c-one-infra.de/giteaAdmin/${{ values.name }}
title: Source Code Repository
icon: git
spec:
owner: guests
lifecycle: experimental
type: service
system: ${{ values.name | dump }}
---
apiVersion: backstage.io/v1alpha1
kind: System
metadata:
name: ${{ values.name | dump }}
description: A system containing a Django application created via template.
annotations:
backstage.io/techdocs-ref: dir:.
links:
- url: https://gitea-192-168-197-3.c-one-infra.de/giteaAdmin/${{ values.name }}
title: Gitea Repository
icon: git
spec:
owner: guests
lifecycle: experimental

View file

@ -0,0 +1,78 @@
---
apiVersion: v1
kind: Namespace
metadata:
name: ${{ values.namespace }}
---
apiVersion: v1
kind: Service
metadata:
name: django
namespace: ${{ values.namespace }}
labels:
app: django
spec:
type: ClusterIP
ports:
- port: 8000
targetPort: http
name: http
selector:
app: django
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ${{ values.namespace }}
namespace: ${{ values.namespace }}
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
ingressClassName: nginx
rules:
- host: 192-168-197-3.c-one-infra.de
http:
paths:
- backend:
service:
name: django
port:
number: 8000
path: /${{ values.name }}
pathType: Prefix
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: django
namespace: ${{ values.namespace }}
labels:
app: django
spec:
replicas: 1
selector:
matchLabels:
app: django
template:
metadata:
labels:
app: django
spec:
containers:
- name: django
image: gitea-192-168-197-3.c-one-infra.de/giteaadmin/${{ values.name }}
command: ["python", "project/manage.py", "runserver", "0.0.0.0:8000"]
env:
- name: APP_NAME
value: ${{ values.name }}
ports:
- name: http
containerPort: 8000
livenessProbe:
httpGet:
path: /healthcheck
port: http
periodSeconds: 10

View file

@ -0,0 +1,22 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,16 @@
"""
ASGI config for project project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.2/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
application = get_asgi_application()

View file

@ -0,0 +1,123 @@
"""
Django settings for project project.
Generated by 'django-admin startproject' using Django 5.2.
For more information on this file, see
https://docs.djangoproject.com/en/5.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.2/ref/settings/
"""
from pathlib import Path
import os
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-8uqicq3zw$=f=%wc=z*!o)0f-%1f_v^6+^3p4+8fcq!u$3fnq6'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ["*", ]
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'project.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'project.wsgi.application'
# Database
# https://docs.djangoproject.com/en/5.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/5.2/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.2/howto/static-files/
STATIC_URL = 'static/'
# Default primary key field type
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

View file

@ -0,0 +1,17 @@
from django.http import HttpResponse
from django.urls import path
def hello_world(request):
return HttpResponse("Hello EDP!")
urlpatterns = [
path('', hello_world)
]
def healthcheck(request):
return HttpResponse("I'm healthy!")
urlpatterns = [
path("healthcheck/", healthcheck),
path("", hello_world),
]

View file

@ -0,0 +1,16 @@
"""
WSGI config for project project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.2/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
application = get_wsgi_application()

View file

@ -0,0 +1,4 @@
Django>=4.2
requests
celery
django-celery-beat

View file

@ -0,0 +1,80 @@
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: django-app
title: Django App Template
description: Template for creating a simple Django application with ArgoCD deployment
spec:
owner: user:guest
type: service
parameters:
- title: Django App Configuration
required:
- name
properties:
name:
title: Project Name
type: string
description: Unique name of the Django app
ui:autofocus: true
steps:
- id: fetch-template
name: Generate Project
action: fetch:template
input:
url: ./skeleton
values:
name: ${{ parameters.name }}
gitea_username: ${{ secrets.GITEA_USERNAME }}
gitea_password: ${{ secrets.GITEA_PASSWORD }}
targetPath: ./
- id: fetch-overrides # Apply specific overrides to add features and make modifications for compatibility
name: Fetch Overrides
action: fetch:template
input:
# url: ./skeleton/.github/workflows
# targetPath: ./.github/workflows
url: ./skeleton/
targetPath: ./
replace: true
values:
name: ${{ parameters.name }}
namespace: ${{ parameters.name }}
- id: publish
name: Publish to Gitea
action: publish:gitea
input:
repoUrl: gitea-192-168-197-3.c-one-infra.de:443/?repo=${{ parameters.name }}
description: Django app for ${{ parameters.name }}
sourcePath: ./
defaultBranch: main
- id: create-argocd-app
name: Create ArgoCD App
action: cnoe:create-argocd-app
input:
appName: ${{ parameters.name }}
appNamespace: ${{ parameters.name }}
argoInstance: in-cluster
projectName: default
repoUrl: https://gitea-192-168-197-3.c-one-infra.de:443/giteaAdmin/${{ parameters.name }}
path: "k8s"
- id: register
name: Register in Backstage Catalog
action: catalog:register
input:
repoContentsUrl: ${{ steps['publish'].output.repoContentsUrl }}
catalogInfoPath: catalog-info.yaml
output:
links:
- title: Open Repository
url: ${{ steps['publish'].output.remoteUrl }}
- title: View in Catalog
icon: catalog
entityRef: ${{ steps['register'].output.entityRef }}