Skip to content

Commit

Permalink
Merge pull request #99 from maykinmedia/feature/setup-config
Browse files Browse the repository at this point in the history
add `setup_configuration` command
  • Loading branch information
annashamray authored Apr 23, 2024
2 parents b06d5c6 + 2f4250f commit 3789ec2
Show file tree
Hide file tree
Showing 25 changed files with 594 additions and 14 deletions.
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
pkg-config \
build-essential \
libpq-dev \
git \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app
Expand Down Expand Up @@ -54,7 +55,9 @@ COPY --from=build /usr/local/bin/uwsgi /usr/local/bin/uwsgi

# Stage 3.2 - Copy source code
WORKDIR /app
COPY ./bin/wait_for_db.sh /wait_for_db.sh
COPY ./bin/docker_start.sh /start.sh
COPY ./bin/setup_configuration.sh /setup_configuration.sh
RUN mkdir /app/log /app/config

COPY --from=frontend-build /app/src/objecttypes/static /app/src/objecttypes/static
Expand Down
8 changes: 2 additions & 6 deletions bin/docker_start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,8 @@ uwsgi_threads=${UWSGI_THREADS:-2}

mountpoint=${SUBPATH:-/}

until pg_isready; do
>&2 echo "Waiting for database connection..."
sleep 1
done

>&2 echo "Database is up."
# wait for required services
${SCRIPTPATH}/wait_for_db.sh

# Apply database migrations
>&2 echo "Apply database migrations"
Expand Down
11 changes: 11 additions & 0 deletions bin/setup_configuration.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash

# setup initial configuration using environment variables
# Run this script from the root of the repository

#set -e
${SCRIPTPATH}/wait_for_db.sh

src/manage.py migrate

src/manage.py setup_configuration --no-selftest
15 changes: 15 additions & 0 deletions bin/wait_for_db.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/sh

set -e

# Wait for the database container
# See: https://docs.docker.com/compose/startup-order/
export PGHOST=${DB_HOST:-db}
export PGPORT=${DB_PORT:-5432}

until pg_isready; do
>&2 echo "Waiting for database connection..."
sleep 1
done

>&2 echo "Database is up."
31 changes: 24 additions & 7 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,37 @@ version: '3'

services:
db:
# NOTE: No persistance storage configured.
# See: https://hub.docker.com/_/postgres/
image: postgres
image: postgres:11-alpine
environment:
- POSTGRES_USER=${DB_USER:-objecttypes}
- POSTGRES_PASSWORD=${DB_PASSWORD:-objecttypes}
- POSTGRES_HOST_AUTH_METHOD=trust
volumes:
- ./docker-init-db.sql:/docker-entrypoint-initdb.d/init_db.sql
# - db:/var/lib/postgresql/data
command: postgres -c max_connections=300 -c log_min_messages=LOG

web:
build: .
environment:
environment: &app-env
- DJANGO_SETTINGS_MODULE=objecttypes.conf.docker
- SECRET_KEY=${SECRET_KEY:-fgv=c0hz&tl*8*3m3893@m+1pstrvidc9e^5@fpspmg%cy$15d}
- ALLOWED_HOSTS=*
- TWO_FACTOR_FORCE_OTP_ADMIN=no
- TWO_FACTOR_PATCH_ADMIN=no
# setup_configuration env vars
- OBJECTTYPES_DOMAIN=web:8000
- OBJECTTYPES_ORGANIZATION=ObjectTypes
- OBJECTS_OBJECTTYPES_TOKEN=some-random-string
- OBJECTS_OBJECTTYPES_PERSON=Some Person
- [email protected]
ports:
- 8000:8000
depends_on:
- db
web-init:
condition: service_completed_successfully

web-init:
build: .
environment: *app-env
command: /setup_configuration.sh
depends_on:
- db
3 changes: 3 additions & 0 deletions docker-init-db.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CREATE USER objecttypes;
CREATE DATABASE objecttypes;
GRANT ALL PRIVILEGES ON DATABASE objecttypes TO objecttypes;
2 changes: 2 additions & 0 deletions requirements/base.in
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ open-api-framework

# Core python libraries
jsonschema
furl

# Framework libraries
django-jsonsuit
sharing-configs
django-setup-configuration

# API libraries
drf-nested-routers
7 changes: 6 additions & 1 deletion requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ django==4.2.11
# django-relativedelta
# django-rest-framework-condition
# django-sendfile2
# django-setup-configuration
# django-simple-certmanager
# django-solo
# django-two-factor-auth
Expand Down Expand Up @@ -138,6 +139,8 @@ django-rest-framework-condition==0.1.1
# via commonground-api-common
django-sendfile2==0.7.0
# via django-privates
django-setup-configuration==0.1.0
# via -r requirements/base.in
django-simple-certmanager==2.0.0
# via zgw-consumers
django-solo==2.0.0
Expand Down Expand Up @@ -184,7 +187,9 @@ face==20.1.1
flower==2.0.1
# via open-api-framework
furl==2.1.3
# via ape-pie
# via
# -r requirements/base.in
# ape-pie
gemma-zds-client==1.0.1
# via
# commonground-api-common
Expand Down
3 changes: 3 additions & 0 deletions requirements/ci.txt
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ django==4.2.11
# django-relativedelta
# django-rest-framework-condition
# django-sendfile2
# django-setup-configuration
# django-simple-certmanager
# django-solo
# django-two-factor-auth
Expand Down Expand Up @@ -213,6 +214,8 @@ django-sendfile2==0.7.0
# via
# -r requirements/base.txt
# django-privates
django-setup-configuration==0.1.0
# via -r requirements/base.txt
django-simple-certmanager==2.0.0
# via
# -r requirements/base.txt
Expand Down
3 changes: 3 additions & 0 deletions requirements/dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ django==4.2.11
# django-relativedelta
# django-rest-framework-condition
# django-sendfile2
# django-setup-configuration
# django-simple-certmanager
# django-solo
# django-two-factor-auth
Expand Down Expand Up @@ -237,6 +238,8 @@ django-sendfile2==0.7.0
# via
# -r requirements/ci.txt
# django-privates
django-setup-configuration==0.1.0
# via -r requirements/ci.txt
django-simple-certmanager==2.0.0
# via
# -r requirements/ci.txt
Expand Down
35 changes: 35 additions & 0 deletions src/objecttypes/conf/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
DEBUG = config("DEBUG", default=False)

ALLOWED_HOSTS = config("ALLOWED_HOSTS", default="", split=True)
IS_HTTPS = config("IS_HTTPS", default=not DEBUG)

USE_X_FORWARDED_HOST = config("USE_X_FORWARDED_HOST", default=False)

Expand Down Expand Up @@ -77,6 +78,7 @@
"solo",
"drf_spectacular",
"vng_api_common",
"django_setup_configuration",
# Two-factor authentication in the Django admin, enforced.
"django_otp",
"django_otp.plugins.otp_static",
Expand All @@ -87,6 +89,7 @@
# Project applications.
"objecttypes.accounts",
"objecttypes.api",
"objecttypes.config",
"objecttypes.core",
"objecttypes.token",
"objecttypes.utils",
Expand Down Expand Up @@ -423,3 +426,35 @@

if config("DISABLE_2FA", default=False): # pragma: no cover
MAYKIN_2FA_ALLOW_MFA_BYPASS_BACKENDS = AUTHENTICATION_BACKENDS

#
# Django setup configuration
#
SETUP_CONFIGURATION_STEPS = [
"objecttypes.config.site.SiteConfigurationStep",
"objecttypes.config.objects.ObjectsAuthStep",
"objecttypes.config.demo.DemoUserStep",
]


#
# Objecttypes settings
#

# setup_configuration command
# sites config
SITES_CONFIG_ENABLE = config("SITES_CONFIG_ENABLE", default=True)
OBJECTTYPES_DOMAIN = config("OBJECTTYPES_DOMAIN", "")
OBJECTTYPES_ORGANIZATION = config("OBJECTTYPES_ORGANIZATION", "")
# objects auth config
OBJECTS_OBJECTTYPES_CONFIG_ENABLE = config(
"OBJECTS_OBJECTTYPES_CONFIG_ENABLE", default=True
)
OBJECTS_OBJECTTYPES_TOKEN = config("OBJECTS_OBJECTTYPES_TOKEN", "")
OBJECTS_OBJECTTYPES_PERSON = config("OBJECTS_OBJECTTYPES_PERSON", "")
OBJECTS_OBJECTTYPES_EMAIL = config("OBJECTS_OBJECTTYPES_EMAIL", "")
# Demo User Configuration
DEMO_CONFIG_ENABLE = config("DEMO_CONFIG_ENABLE", default=DEBUG)
DEMO_TOKEN = config("DEMO_TOKEN", "")
DEMO_PERSON = config("DEMO_PERSON", "")
DEMO_EMAIL = config("DEMO_EMAIL", "")
1 change: 1 addition & 0 deletions src/objecttypes/conf/ci.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

os.environ.setdefault("SECRET_KEY", "dummy")
os.environ.setdefault("ENVIRONMENT", "ci")
os.environ.setdefault("IS_HTTPS", "no")

from .base import * # noqa isort:skip

Expand Down
1 change: 1 addition & 0 deletions src/objecttypes/conf/dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import warnings

os.environ.setdefault("DEBUG", "yes")
os.environ.setdefault("IS_HTTPS", "no")
os.environ.setdefault("ALLOWED_HOSTS", "*")
os.environ.setdefault(
"SECRET_KEY", "fgv=c0hz&tl*8*3m3893@m+1pstrvidc9e^5@fpspmg%cy$15d"
Expand Down
Empty file.
53 changes: 53 additions & 0 deletions src/objecttypes/config/demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from django.conf import settings
from django.urls import reverse

import requests
from django_setup_configuration.configuration import BaseConfigurationStep
from django_setup_configuration.exceptions import SelfTestFailed

from objecttypes.token.models import TokenAuth
from objecttypes.utils import build_absolute_url


class DemoUserStep(BaseConfigurationStep):
"""
Create demo user to request Objectypes API
"""

verbose_name = "Demo User Configuration"
required_settings = [
"DEMO_TOKEN",
"DEMO_PERSON",
"DEMO_EMAIL",
]
enable_setting = "DEMO_CONFIG_ENABLE"

def is_configured(self) -> bool:
return TokenAuth.objects.filter(token=settings.DEMO_TOKEN).exists()

def configure(self):
TokenAuth.objects.update_or_create(
token=settings.DEMO_TOKEN,
defaults={
"contact_person": settings.DEMO_PERSON,
"email": settings.DEMO_EMAIL,
},
)

def test_configuration(self):
endpoint = reverse("v2:objecttype-list")
full_url = build_absolute_url(endpoint, request=None)

try:
response = requests.get(
full_url,
headers={
"Authorization": f"Token {settings.DEMO_TOKEN}",
"Accept": "application/json",
},
)
response.raise_for_status()
except requests.RequestException as exc:
raise SelfTestFailed(
"Could not list objecttypes for the configured token"
) from exc
55 changes: 55 additions & 0 deletions src/objecttypes/config/objects.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from django.conf import settings
from django.urls import reverse

import requests
from django_setup_configuration.configuration import BaseConfigurationStep
from django_setup_configuration.exceptions import SelfTestFailed

from objecttypes.token.models import TokenAuth
from objecttypes.utils import build_absolute_url


class ObjectsAuthStep(BaseConfigurationStep):
"""
Configure credentials for Objects API to request Objecttypes API
"""

verbose_name = "Objects API Authentication Configuration"
required_settings = [
"OBJECTS_OBJECTTYPES_TOKEN",
"OBJECTS_OBJECTTYPES_PERSON",
"OBJECTS_OBJECTTYPES_EMAIL",
]
enable_setting = "OBJECTS_OBJECTTYPES_CONFIG_ENABLE"

def is_configured(self) -> bool:
return TokenAuth.objects.filter(
token=settings.OBJECTS_OBJECTTYPES_TOKEN
).exists()

def configure(self):
TokenAuth.objects.update_or_create(
token=settings.OBJECTS_OBJECTTYPES_TOKEN,
defaults={
"contact_person": settings.OBJECTS_OBJECTTYPES_PERSON,
"email": settings.OBJECTS_OBJECTTYPES_EMAIL,
},
)

def test_configuration(self):
endpoint = reverse("v2:objecttype-list")
full_url = build_absolute_url(endpoint, request=None)

try:
response = requests.get(
full_url,
headers={
"Authorization": f"Token {settings.OBJECTS_OBJECTTYPES_TOKEN}",
"Accept": "application/json",
},
)
response.raise_for_status()
except requests.RequestException as exc:
raise SelfTestFailed(
"Could not list objecttypes for the configured token"
) from exc
Loading

0 comments on commit 3789ec2

Please sign in to comment.