Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor/deployment #7

Merged
merged 25 commits into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
196ad06
feat(secret_key): don't use hardcoded secret key
Guillaumebeuzeboc Jan 18, 2024
1df549a
feat(allow hosts): allow extension of the list
Guillaumebeuzeboc Jan 18, 2024
0873ae4
feat(debug): set it to false
Guillaumebeuzeboc Jan 18, 2024
3896895
feat(CSRF): enable CSRF
Guillaumebeuzeboc Jan 18, 2024
241c385
feat(database): provide database location with env var
Guillaumebeuzeboc Jan 18, 2024
34b8c9c
fix(ci): use python3.10
Guillaumebeuzeboc Jan 19, 2024
78ed7b2
fix(makefile): start dev server from makefile
Guillaumebeuzeboc Jan 22, 2024
bdded17
feat(setting): define standard static_root
Guillaumebeuzeboc Jan 22, 2024
7e4504c
feat(setup): include template files
Guillaumebeuzeboc Jan 22, 2024
a4fe044
feat(snap): add snap to distribute the server
Guillaumebeuzeboc Jan 22, 2024
bd34979
feat(snap): create-super-user
Guillaumebeuzeboc Jan 22, 2024
ad22dc2
refactor(test)
Guillaumebeuzeboc Jan 24, 2024
4fe6576
feat(rock): create a rock
Guillaumebeuzeboc Jan 24, 2024
eb01c84
CI(rock)
Guillaumebeuzeboc Jan 24, 2024
6ae4dba
fix(daphne): change bind address
Guillaumebeuzeboc Jan 25, 2024
c77567e
feat(django): USE_X_FORWARDED_HOST
Guillaumebeuzeboc Jan 25, 2024
7b9a1f9
fix(gitignore): ignore generated static files
Guillaumebeuzeboc Jan 31, 2024
d700d71
fix(gunicorn): use guniron instead of daphne
Guillaumebeuzeboc Jan 31, 2024
ae527a4
fix(settings): manage static files with script_name
Guillaumebeuzeboc Jan 31, 2024
641b9e2
fix(create_super_user): accept parameters
Guillaumebeuzeboc Jan 31, 2024
380b713
fix(security): disable csrf for now
Guillaumebeuzeboc Jan 31, 2024
f1ccc01
fix(actions): rename build rock action
Guillaumebeuzeboc Feb 9, 2024
b503d7b
fix(rock-release): keep rock for 7 days only
Guillaumebeuzeboc Feb 9, 2024
a917017
Merge branch 'main' into refactor/deployment
Guillaumebeuzeboc Feb 9, 2024
bb915dd
Merge branch 'main' into refactor/deployment
Guillaumebeuzeboc Feb 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .github/workflows/build-rock.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Build rock on PR

on:
workflow_dispatch: {}
pull_request:
branches:
- main

jobs:
main:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Determine any rockcraft.yaml changed in the PR
id: changed-files
uses: tj-actions/changed-files@v35
with:
files: "./rockcraft.yaml"

- name: Setup LXD
if: steps.changed-files.outputs.any_changed
uses: canonical/[email protected]
with:
channel: latest/stable

- name: Install dependencies
if: steps.changed-files.outputs.any_changed
run: |
sudo snap install --classic rockcraft
- name: Build ROCK
if: steps.changed-files.outputs.any_changed
run: |
rockcraft pack --verbose
59 changes: 59 additions & 0 deletions .github/workflows/rock-release-dev.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# The workflow canonical/observability/.github/workflows/rock-release-dev.yaml@main
# https://github.com/canonical/observability/blob/34b7edb56094e8e3f01200ce49e01bf9dd6688ac/.github/workflows/rock-release-dev.yaml
# does not allow setting a GHCR repo where to publish at the moment.
# We thus copy it below and adapt it.

name: Build ROCK and release dev tag to GHCR

on:
workflow_dispatch:
push:
branches:
- main

jobs:
main:
runs-on: ubuntu-latest
steps:

- name: Checkout repository
uses: actions/checkout@v3

- name: Find the *latest* rockcraft.yaml
id: find-latest
run: |
latest_rockcraft_file=$(find $GITHUB_WORKSPACE -name "rockcraft.yaml" | sort -V | tail -n1)
rockcraft_dir=$(dirname ${latest_rockcraft_file#\./})
echo "latest-dir=$rockcraft_dir" >> $GITHUB_OUTPUT
- name: Build ROCK
uses: canonical/craft-actions/rockcraft-pack@main
with:
path: "${{ steps.find-latest.outputs.latest-dir }}"
verbosity: verbose
id: rockcraft

- name: Upload locally built ROCK artifact
uses: actions/upload-artifact@v4
with:
name: cos-registration-agent-rock
path: ${{ steps.rockcraft.outputs.rock }}
retention-days: 7

- name: Upload ROCK to ghcr.io
run: |
sudo skopeo --insecure-policy copy oci-archive:$(realpath ${{ steps.rockcraft.outputs.rock }}) docker://ghcr.io/ubuntu-robotics/cos-registration-server:dev --dest-creds "${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}"
- name: Generate digest
run: |
digest=$(skopeo inspect oci-archive:$(realpath ${{ steps.rockcraft.outputs.rock }}) --format '{{.Digest}}')
echo "digest=${digest#*:}" >> "$GITHUB_OUTPUT"
- name: Install Syft
run: |
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
- name: Create SBOM
run: syft $(realpath ${{ steps.rockcraft.outputs.rock }}) -o spdx-json=cos-registration-server.sbom.json

- name: Upload SBOM
uses: actions/upload-artifact@v4
with:
name: cos-registration-server-sbom
path: "cos-registration-server.sbom.json"
8 changes: 5 additions & 3 deletions .github/workflows/main.yml → .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This is a basic workflow to help you get started with Actions

name: CI
name: tests

# Controls when the workflow will run
on:
Expand All @@ -18,7 +18,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: [3.9]
python-version: ["3.10"]
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
Expand All @@ -28,6 +28,8 @@ jobs:
python-version: ${{ matrix.python-version }}
- name: Install project
run: make install
- name: Generate django secret key
run: export SECRET_KEY_DJANGO=$(make secretkey)
- name: Run linter
run: make lint

Expand All @@ -36,7 +38,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: [3.9]
python-version: ["3.10"]
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
Expand Down
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,10 @@ dmypy.json

# templates
.github/templates/*

# snap
*.snap
# rock
*.rock
# static files
cos_registration_server/static/
4 changes: 4 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ then activate it with `source .venv/bin/activate`.

Run `make install` to install the project in develop mode.

## Start the developer server

Run `make runserver` to start the django developer server.

## Run the tests to ensure everything is working

Run `make test` to run the tests.
Expand Down
3 changes: 1 addition & 2 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
include LICENSE
include HISTORY.md
include Containerfile
graft tests
graft cos_registration_server
recursive-include cos_registration_server/devices/templates *
9 changes: 7 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ install: ## Install the project in dev mode.
runserver: ## Django run server.
$(ENV_PREFIX)python3 cos_registration_server/manage.py runserver

.PHONY: secretkey
secretkey: ## Generate the django secret key.
$(ENV_PREFIX)python3 -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())'


.PHONY: fmt
fmt: ## Format code using black & isort.
$(ENV_PREFIX)isort cos_registration_server/
Expand Down Expand Up @@ -75,9 +80,9 @@ virtualenv: ## Create a virtual environment.
release: ## Create a new tag for release.
@echo "WARNING: This operation will create s version tag and push to github"
@read -p "Version? (provide the next x.y.z semver) : " TAG
@echo "$${TAG}" > cos_registration_server/VERSION
@echo "$${TAG}" > cos_registration_server/cos_registration_server/VERSION
@$(ENV_PREFIX)gitchangelog > HISTORY.md
@git add cos_registration_server/VERSION HISTORY.md
@git add cos_registration_server/cos_registration_server/VERSION HISTORY.md
@git commit -m "release: version $${TAG} 🚀"
@echo "creating git tag : $${TAG}"
@git tag $${TAG}
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,20 @@ requiring to access the device database.
</details>

## Installation
First we must generate a secret key for our django to sign data.
The secret key must be a large random value and it must be kept secret.

A secret key can be generated with the following command:

`export SECRET_KEY_DJANGO=$(make secretkey)`

We can expand the allowed hosts list:

`export ALLOWED_HOST_DJANGO="cos-registration-server.com"`

Additionally, we can provide a directory for the database:

`export DATABASE_BASE_DIR_DJANGO="/var/lib"`

`make install`

Expand Down
Empty file.
3 changes: 0 additions & 3 deletions cos_registration_server/api/views.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
from api.serializer import DeviceSerializer
from devices.models import Device
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.parsers import JSONParser


@csrf_exempt
def devices(request):
if request.method == "GET":
devices = Device.objects.all()
Expand All @@ -26,7 +24,6 @@ def devices(request):
return JsonResponse(serialized.errors, status=400)


@csrf_exempt
def device(request, uid):
try:
device = Device.objects.get(uid=uid)
Expand Down
43 changes: 30 additions & 13 deletions cos_registration_server/cos_registration_server/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,28 @@
https://docs.djangoproject.com/en/4.2/ref/settings/
"""

import os
from pathlib import Path

# 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/4.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = (
"django-insecure-$b#5b(2h9_%p439=#ev0!dkde9wqt=rgoc!jvi-y93^@+wcvw8"
)
try:
SECRET_KEY = os.environ["SECRET_KEY_DJANGO"]
except KeyError:
pass

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
DEBUG = False

ALLOWED_HOSTS = ["*"]
ALLOWED_HOSTS = ["localhost", "127.0.0.1"]

# to be able to add the webserver address
try:
additional_host = os.environ["ALLOWED_HOST_DJANGO"]
ALLOWED_HOSTS.append(additional_host)
except KeyError:
pass

# Application definition

Expand All @@ -48,10 +51,10 @@
"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",
"whitenoise.middleware.WhiteNoiseMiddleware",
]

ROOT_URLCONF = "cos_registration_server.urls"
Expand All @@ -78,10 +81,16 @@
# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases

# to be able to store the database in a juju storage
try:
database_base_dir = Path(os.environ["DATABASE_BASE_DIR_DJANGO"])
except KeyError:
database_base_dir = BASE_DIR

DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
"NAME": database_base_dir / "db.sqlite3",
}
}

Expand Down Expand Up @@ -124,9 +133,17 @@
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/

STATIC_URL = "static/"
STATIC_URL = os.getenv("SCRIPT_NAME", "") + "/static/"

STATIC_ROOT = BASE_DIR / "static/"

WHITENOISE_STATIC_PREFIX = "static/"

# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

# To keep the reverse proxy prefix when forwarding.
USE_X_FORWARDED_HOST = True

2 changes: 1 addition & 1 deletion cos_registration_server/devices/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def test_one_device_then_two(self):
class DeviceViewTests(TestCase):
def setUp(self):
# custom client with META HTTP_HOST specified
self.base_url = "192.168.1.2:8080"
self.base_url = "127.0.0.1:8080"
self.client = Client(HTTP_HOST=self.base_url)

def test_unlisted_device(self):
Expand Down
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
django
djangorestframework
whitenoise
tzdata
gunicorn
8 changes: 8 additions & 0 deletions rock/local/configure.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/bash

cd /lib/python3.10/site-packages/cos_registration_server

export DATABASE_BASE_DIR_DJANGO="/server_data"

# migrate the database
/bin/python3 manage.py migrate
9 changes: 9 additions & 0 deletions rock/local/create_super_user.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/bash

# necessary for daphne as the option --root-path doesn't work
cd /lib/python3.10/site-packages/cos_registration_server

export DATABASE_BASE_DIR_DJANGO="/server_data"
export SECRET_KEY_DJANGO=$(cat /server_data/secret_key)

python3 manage.py createsuperuser $@
8 changes: 8 additions & 0 deletions rock/local/install.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/bash

mkdir /server_data

SECRET_KEY=$(/bin/python3 -c \
'from django.core.management.utils import get_random_secret_key;
print(get_random_secret_key())')
echo $SECRET_KEY > /server_data/secret_key
8 changes: 8 additions & 0 deletions rock/local/launcher.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/bash

cd /lib/python3.10/site-packages/cos_registration_server

export DATABASE_BASE_DIR_DJANGO="/server_data"
export SECRET_KEY_DJANGO=$(cat /server_data/secret_key)

gunicorn --bind 0.0.0.0:8000 cos_registration_server.wsgi
Loading
Loading