Skip to content

Commit

Permalink
Merge pull request #14 from offspot/multi-demo
Browse files Browse the repository at this point in the history
Revamped for multi-demo & minimal downtime
  • Loading branch information
rgaudin authored Sep 9, 2024
2 parents b00f254 + c9a5f98 commit 6505df8
Show file tree
Hide file tree
Showing 36 changed files with 1,298 additions and 760 deletions.
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ repos:
- id: trailing-whitespace
- id: end-of-file-fixer
- repo: https://github.com/psf/black
rev: "24.3.0"
rev: "24.8.0"
hooks:
- id: black
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.3.3
rev: v0.6.4
hooks:
- id: ruff
- repo: https://github.com/RobertCraigie/pyright-python
rev: v1.1.355
rev: v1.1.379
hooks:
- id: pyright
name: pyright (system)
Expand Down
133 changes: 46 additions & 87 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,37 @@
# Kiwix Hotspot Demo

This Hostpot Demo allows to run a demo hotspot on a regular machine / VM. This demo contains all the required tooling to transform a Hotspot image and a bare machine into a working Hotspot Demo.

Functionalities:
- Arrive on home page
- Browse hostpot content
This repo allows setting up online replicas of Kiwix Hotspot Web Access from Hotspot-image (imager-service built).
Those replicas (called *demos* or *deployments*) are configured in the `demos.yaml` file at the root of this repo.

The tool automatically monitors this file and adjusts on changes.

Kiwix Hotspot Demo adheres to openZIM's [Contribution Guidelines](https://github.com/openzim/overview/wiki/Contributing).

Kiwix Hotspot Demo has implemented openZIM's [Python bootstrap, conventions and policies](https://github.com/openzim/_python-bootstrap/docs/Policy.md) **v1.0.0**.

## Managing live demo

Adding, removing or reordering demos is done by editing (via a PR) [`demo.offspot.yaml`](https://github.com/kiwix/operations/blob/main/demos/demo.offspot.yaml) file on [`kiwix/operations`](https://github.com/kiwix/operations) repository.

- The `ident` key must match the imager-service ident of the auto-image.
- The `name` key is an optionnal user-friendly label for the homepage.
- The `alias` key is an optionnal user-friendly replacement of `ident` for the demo's sub-domain (`xxx.demo.hotspot.kiwix.org`)
- The icon can be added/updated via a PR on this repository (files are named after `ident` in `/src/offspot_demo/multi-proxy/assets`)

## Pre-requisites

Installing this demo requires:

- a Linux machine (or VM)
- with Docker (compose is required as well but it is now parted of docker)
- with Python 3.12 and preferably a venv
- with Python 3.11, preferably in a venv
- root access
- `loop` must be enabled in kernel or module loaded

If you start from a bare machine, you can:

- install Docker by following instructions at https://docs.docker.com/engine/install/debian/
- compile Python from sources by executing the install.sh script
- tested on Debian Buster 10
- prefer a package install if Python 3.12 is available on your distro
- create the venv and automatize its activation for your user:
- `python -m venv env`
- automatize the venv activation: `echo "source ~/env/bin/activate" | tee /etc/profile.d/python-venv.sh`
Expand All @@ -40,110 +46,63 @@ To install the demo, you have to:
- could be any other appropriate location, but then you have to modify `<src_path>/systemd-unit/demo-offspot.service`
- customize this file as needed
- automatically load the environment data in your user session: `echo "export \$(grep -v '^#' /etc/demo/environment | xargs) && env | grep OFFSPOT_DEMO" | tee /etc/profile.d/demo-env.sh`
- setup the demo: run `demo-setup`

## Tooling

This repository contains various modules and scripts useful to setup / update the demo. Beside the single-use `setup` script, only running `watcher` periodically should be necessary in production. Developers can use individual scripts for each step to inspect output.

### setup script

- install symlink on `/etc/docker/compose.yaml` to `<src_path>/maint-compose/docker-compose.yaml`
- simple caddy default server with minimal HTML UI saying "we are in maintenance" (with HTTPS auto certificates)
- install a systemd unit to manage the `/etc/docker/compose.yaml` docker-compose (start / stop)
- source file in `src/offspot_demo/systemd-unit`
- start and enable this systemd unit

### watcher script

- runs once, launched periodically
- checks the special image endpoint on imager service (https://api.imager.kiwix.org/auto-images/offspot-demo/json)
- check if target URL has changed
- call `deploy` module if it did

### toggle module/script

```sh
demo-toggle [image|maint]
```

- stop docker-compose
- change symlink
- start docker-compose

### deploy module/script
- install the services and required aria2

```sh
demo-deploy http://xxxxx/xyz.img
# download and install aria2 (used for downloads)
wget -O /tmp/aria2.zip https://github.com/abcfy2/aria2-static-build/releases/download/1.37.0/aria2-x86_64-linux-musl_libressl_static.zip \
&& unzip -d /tmp /tmp/aria2.zip \
&& mv /tmp/aria2c /usr/local/bin \
&& rm /tmp/aria2.zip \
&& aria2c -v

# this folder must exists
mkdir -p /var/log/demo

# install systend units
cp src/offspot_demo/systemd-unit/* /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now multi-proxy.service demo-watcher.service demo-watcher.timer
```

- check URL
- `offspot-toggle maint`
- unmount old image `/data`
- release loop-device
- remove old image file `/demo/image.img`
- purge docker images and containers
- download new image into `/demo/image.img` and check integrity
- attach image to loop-device
- mount 3rd partition to `/data`
- `offspot-prepare /data`
- attach image
- `offspot-togglw image`


### prepare module/script
## How it works

```sh
demo-prepare /data
```
- always-running caddy web server named `multi-proxy` that responds to the FQDN and links to individual demos
- one script runs *always* (restarted every 15mn) running two scripts one after the other
- config-watcher that checks [`demo.offspot.yaml`](https://github.com/kiwix/operations/blob/main/demos/demo.offspot.yaml) file in kiwix/operations repo and updates `/etc/demo/environment` accordingly
- update-watcher removes deployments (not in config anymore), deploys new or updated ones (images are updated periodically so it checks online if a new version is available)
- deploy script (ran for an indiv demo) downloads the image file then:
- turn that demo off (switch to maintenance mode)
- undeploys (unmount, release loop, removes stuff)
- gets a loop device, mounts third partition of file
- runs prepare script: fixes in-images variables for use with that demo's FQDN, writes fixed compose file, informs multi-proxy of new domain(s)
- switch from maintenance mode to image mode (launch the new compose file.

- check if already prepared via `/data/prepared.ok`
- read and parse `/data/contents/dashboard.yaml`
- read `fqdn` as `orig_fqdn`
- rewrite metadata for `fqdn=demo.hotspot.kiwix.org`
- rewrite all `url` and `download.url` for `packages` to replace `orig_fqdn` with `fqdn`
- rewrite urls in `readers` and `links` as well
- read and parse /image/image.yaml
- convert `offspot.containers` and write to `/data/compose.yaml`
- for all volumes:
- ensure all `source` is relative to `/data`.
- Otherwise remove bind
- Unless it's `/var/log` and image is `ghcr.io/offspot/reverse-proxy:` (for metrics)
- for all services:
- remove `cap_add` (will break captive portal but not an issue)
- if image does not start with `ghcr.io/offspot/reverse-proxy:`, remove `ports` else, limit to `80:80` and `443:443`
- if image starts with `ghcr.io/offspot/captive-portal:` add ports `2080:2080` `2443:2443`
- remove `privileged`
- for all environment in all services (exclude `PROTECTED_SERVICES`?:
- replace `old_fqdn` with `fqdn`
- pull all OCI images from `oci_images`
- touch `/data/prepared.ok`
Check the source code starting from the `config_watcher` and `update-watcher` to discover the various steps.

## Kiwix instance

Kiwix is running a demo instance at http://demo.hotspot.kiwix.org
Kiwix is running a demo instance at https://demo.hotspot.kiwix.org

### Domain names

- `demo.hotspot.kiwix.org A 51.159.6.102`
- `demo.hotspot.kiwix.org A 62.210.206.65`
- `*.demo.hotspot.kiwix.org CNAME demo.hotspot.kiwix.org`

### Machine

- Scaleway Start-2-M-SATA (dedibox) with 16GB RAM and 1TB disk for €17/m
- Scaleway Start-1-L-SATA (dedibox) with 16GB RAM and 2TB disk for €20/m
- Debian
- node-like setup with bastion
- docker install (comes with compose)
- python install (3.12) + venv (in `install.sh`)
- `mount`, `coreutils` and `aria2` (in `install.sh`)
- this project installed somewhere
- this project installed in `/root/demo/env`
- `pip install git+https://github.com/offspot/demo@main`
- configuration at `/etc/demo/environment`. Files in `/data/demo`

## Next

- Enhance/Remove dirty Python 3.12 installation
- Rework the dirty systemd manipulations (mainly/only in setup.py)
- Can access Captive portal (just for UI)? Via :2080 and :2443?
- *Protect* the service via a password (provided in-login page? as we want to prevent bots mostly)
- Use LXC containers to isolate from host and allow restoring snapshots frequently to prevent any attack from persisting
- Use Apache Guacamole to isolate the hotpost HTTP service(s) as users would access a VNC-like rendering of it
Expand Down
41 changes: 33 additions & 8 deletions contrib/environment
Original file line number Diff line number Diff line change
@@ -1,17 +1,42 @@
# FQDN which will be used by the demo, e.g. demo.hotspot.kiwix.org
OFFSPOT_DEMO_FQDN="demo.hotspot.kiwix.org"
# address to use in multi-proxy to reach the individual hotspot-proxies (on their assign ports)
OFFSPOT_DEMO_HOST_IP="62.210.206.65"

# URL of the Image to watch / deploy (either autoimage URL or email URL)
OFFSPOT_DEMO_IMAGE_URL="https://api.imager.kiwix.org/auto-images/offspot-demo/json"
# comma-separated demo info
# format is {ident}:[{alias}]:[{name}]:[{subdomains}]
# alias and names can be empty (uses ident then)
# subdomains are usually left empty so ends with an hanging semicolon
# that's because prepare script will update it
OFFSPOT_DEMOS_LIST="demo:free:Free Package:"

# Folder where everything will be deployed
OFFSPOT_DEMO_TARGET_DIR="/data"
# imager-service API credentials to retrieve URLs
IMAGER_SERVICE_API_USERNAME="notset"
IMAGER_SERVICE_API_PASSWORD="notset"

# Location of the image
OFFSPOT_DEMO_IMAGE_PATH="/demo/image.img"
# Email adress for acme to receive notifications about expiring/expired certificates
OFFSPOT_DEMO_TLS_EMAIL="[email protected]"

# nb of seconds to wait when starting a compose to check its still running
STARTUP_DURATION="60"

# location of the demos.yaml file to read main config from
MULTI_CONFIG_URL="https://raw.githubusercontent.com/kiwix/operations/main/demos/demo.offspot.yaml"

# Configuration file (this very one file)
OFFSPOT_CONFIGURATION="/etc/demo/environment"

# Root folder where everything will be deployed (in per-demo subfolder)
OFFSPOT_DEMO_TARGET_ROOT_DIR="/data/demo/data"

# Location of the images on disk
OFFSPOT_DEMO_IMAGES_ROOT_DIR="/data/demo/images"
OFFSPOT_DEMO_COMPOSE_ROOT_DIR="/data/demo/compose"

# OCI plateform to use (by default, offspot is linux/aarch64 but usually demo will run on linux/amd64)
OFFSPOT_DEMO_OCI_PLATFORM="linux/amd64"

# Email adress for acme to receive notifications about expiring/expired certificates
OFFSPOT_DEMO_TLS_EMAIL="[email protected]"
OFFSPOT_DEMO_SRC_DIR="/data/demo/repo/src/offspot_demo"
OFFSPOT_ENV_DIR="/data/demo/env"
OFFSPOT_DEMO_PROXY_CONTAINER_NAME="multi-proxy"
OFFSPOT_DEMO_PROXY_IMAGE_NAME="multi-proxy"
125 changes: 0 additions & 125 deletions install.sh

This file was deleted.

Loading

0 comments on commit 6505df8

Please sign in to comment.