diff --git a/README.md b/README.md index edda15c..35525e0 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,35 @@ -# ns8-bookstack - -This is a NS8 App for [Bookstack](https://www.bookstackapp.com/). +# NS8 Bookstack +This is an NS8 application for [Bookstack](https://www.bookstackapp.com/), a free and open source Wiki designed for teams. ## Install Instantiate the module with: - add-module ghcr.io/compgeniuses/bookstack:latest 1 + add-module ghcr.io/geniusdynamics/bookstack:latest 1 The output of the command will return the instance name. Output example: - {"module_id": "bookstack1", "image_name": "bookstack", "image_url": "ghcr.io/compgeniuses/bookstack:latest"} + {"module_id": "bookstack1", "image_name": "bookstack", "image_url": "ghcr.io/geniusdynamics/bookstack:latest"} + ## Default Credentials -Initial Login Credetials for boockstack -- `USername`: admin@admin.com + +Initial Login Credentials for Bookstack + +- `Username`: admin@admin.com - `Password`: password ## Configure -Let's assume that the mattermost instance is named `bookstack1`. +Let's assume that the bookstack instance is named `bookstack1`. Launch `configure-module`, by setting the following parameters: + - `host`: a fully qualified domain name for the application - `http2https`: enable or disable HTTP to HTTPS redirection (true/false) - `lets_encrypt`: enable or disable Let's Encrypt certificate (true/false) - Example: ``` @@ -41,27 +43,40 @@ EOF ``` The above command will: + - start and configure the bookstack instance -- configure a virtual host for trafik to access the instance +- configure a virtual host for Traefik to access the instance ## Get the configuration + You can retrieve the configuration with ``` api-cli run get-configuration --agent module/bookstack1 ``` +## Update Module + +```bash +api-cli run update-module --data '{ + "module_url": "ghcr.io/geniusdynamics/bookstack:latest", + "instances": ["bookstack1"], + "force": true +}' + +``` + ## Uninstall To uninstall the instance: remove-module --no-preserve bookstack1 -## Smarthost setting discovery +## Smarthost Setting Discovery Some configuration settings, like the smarthost setup, are not part of the `configure-module` action input: they are discovered by looking at some -Redis keys. To ensure the module is always up-to-date with the +Redis keys. To ensure the module is always up-to-date with the centralized [smarthost setup](https://nethserver.github.io/ns8-core/core/smarthost/) every time bookstack starts, the command `bin/discover-smarthost` runs and refreshes @@ -78,26 +93,30 @@ expected to work: it can be rewritten or discarded completely. ## Debug -some CLI are needed to debug +Some CLI commands are needed to debug the module: + +- The module runs under an agent that initiates a lot of environment variables (in `/home/bookstack1/.config/state`), it could be useful to verify them on the root terminal: + + `runagent -m bookstack1 env` -- The module runs under an agent that initiate a lot of environment variables (in /home/bookstack1/.config/state), it could be nice to verify them -on the root terminal +- You can become runagent for testing scripts and initiate all environment variables: - `runagent -m bookstack1 env` + `runagent -m bookstack1` -- you can become runagent for testing scripts and initiate all environment variables - - `runagent -m bookstack1` +The path becomes: - the path become : ``` echo $PATH /home/bookstack1/.config/bin:/usr/local/agent/pyenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/ ``` -- if you want to debug a container or see environment inside - `runagent -m bookstack1` - ``` +- If you want to debug a container or see environment inside: + + `runagent -m bookstack1` + +Then you can run: + +``` podman ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d292c6ff28e9 localhost/podman-pause:4.6.1-1702418000 9 minutes ago Up 9 minutes 127.0.0.1:20015->80/tcp 80b8de25945f-infra @@ -105,9 +124,10 @@ d8df02bf6f4a docker.io/library/mariadb:10.11.5 --character-set-s... 9 9e58e5bd676f docker.io/library/nginx:stable-alpine3.17 nginx -g daemon o... 9 minutes ago Up 9 minutes 127.0.0.1:20015->80/tcp bookstack-app ``` -you can see what environment variable is inside the container +You can see what environment variables are inside the container: + ``` -podman exec bookstack-app env +podman exec bookstack-app env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin TERM=xterm PKG_RELEASE=1 @@ -124,18 +144,18 @@ MARIADB_DB_PORT=3306 HOME=/root ``` -you can run a shell inside the container +You can run a shell inside the container: ``` -podman exec -ti bookstack-app sh -/ # +podman exec -ti bookstack-app sh +/ # ``` + ## Testing Test the module using the `test-module.sh` script: - - ./test-module.sh ghcr.io/compgeniuses/bookstack:latest + ./test-module.sh ghcr.io/geniusdynamics/bookstack:latest The tests are made using [Robot Framework](https://robotframework.org/) @@ -146,4 +166,4 @@ Translated with [Weblate](https://hosted.weblate.org/projects/ns8/). To setup the translation process: - add [GitHub Weblate app](https://docs.weblate.org/en/latest/admin/continuous.html#github-setup) to your repository -- add your repository to [hosted.weblate.org]((https://hosted.weblate.org) or ask a compgeniuses developer to add it to ns8 Weblate project +- add your repository to [hosted.weblate.org](https://hosted.weblate.org) or ask a NethServer developer to add it to the ns8 Weblate project diff --git a/build-images.sh b/build-images.sh index 6b5f090..4e7571b 100644 --- a/build-images.sh +++ b/build-images.sh @@ -14,7 +14,7 @@ images=() repobase="${REPOBASE:-ghcr.io/geniusdynamics}" # Configure the image name reponame="bookstack" -BOOKSTACK_TAG="25.07.1" +BOOKSTACK_TAG="25.12.8" # Create a new empty container image container=$(buildah from scratch) diff --git a/imageroot/actions/configure-module/10configure_environment_vars b/imageroot/actions/configure-module/10configure_environment_vars index 9853029..3e85b05 100755 --- a/imageroot/actions/configure-module/10configure_environment_vars +++ b/imageroot/actions/configure-module/10configure_environment_vars @@ -6,34 +6,30 @@ # import json +import os import sys import agent +import base64 # Try to parse the stdin as JSON. # If parsing fails, output everything to stderr data = json.load(sys.stdin) host = data.get("host", "") -port = data.get("TCP_PORT", "") -url = host + ":" + port -APP_URL = "https://" + host -agent.write_envfile("app.env", {"APP_URL": APP_URL}) -# This is specific to you module, so you need to change it accordingly. -# we read a json stdin {"vars1":true, "var2":"foo", "vars3": 3} and we writ it to .config/state/environment -# Upper case to set environment variable and minor case to read from stdin -# this values must exists in the json stdin -# agent.set_env("MAIL_SERVER", data["mail_server"]) -# agent.set_env("LDAP_DOMAIN", data["ldap_domain"]) +def generate_laravel_app_key(): + key = os.urandom(32) # 32 bytes for AES-256 + return "base64:" + base64.b64encode(key).decode("utf-8") + -# you can add default values for the following variables -# agent.set_env("MAIL_DOMAIN",data.get("mail_domain","")) -# agent.set_env("WOWORKERSCOUNT",data.get("workers_count",3)) -# agent.set_env("AUXILIARYACCOUNT",data.get("auxiliary_account",True)) -# agent.set_env("ACTIVESYNC",data.get("activesync",False)) +if os.path.exists("app-db.env"): + dt = agent.read_envfile("app-db.env") + APP_KEY = dt.get("APP_KEY", generate_laravel_app_key()) +else: + APP_KEY = generate_laravel_app_key() +APP_URL = "https://" + host +agent.write_envfile("app.env", {"APP_URL": APP_URL, "APP_KEY": APP_KEY}) -# Make sure everything is saved inside the environment file -# just before starting systemd unit # agent.dump_env() diff --git a/imageroot/actions/create-module/10configure_vars b/imageroot/actions/create-module/10configure_vars index 4c46aa0..ce3eff1 100755 --- a/imageroot/actions/create-module/10configure_vars +++ b/imageroot/actions/create-module/10configure_vars @@ -9,6 +9,7 @@ import json import sys import agent import os +import base64 # Try to parse the stdin as JSON. # If parsing fails, output everything to stderr @@ -23,6 +24,13 @@ def generate_random_password(length): return password[:length] +def generate_laravel_app_key(): + key = os.urandom(32) # 32 bytes for AES-256 + return "base64:" + base64.b64encode(key).decode("utf-8") + + +APP_KEY = generate_laravel_app_key() + MARIADB_ROOT_PASSWORD = generate_random_password(16) MARIADB_DATABASE = data.get("MARIADB_DATABASE", "bookstack") MARIADB_USER = data.get("MARIADB_USER", "bookstack") @@ -39,9 +47,10 @@ maria_db = { app = { "DB_HOST": "mariadb-app", "DB_PORT": "3306", - "DB_USER": MARIADB_USER, - "DB_PASS": MARIADB_PASSWORD, + "DB_USERNAME": MARIADB_USER, + "DB_PASSWORD": MARIADB_PASSWORD, "DB_DATABASE": MARIADB_DATABASE, + "APP_KEY": generate_random_password(64), } agent.write_envfile("database.env", maria_db) diff --git a/imageroot/systemd/user/mariadb-app.service b/imageroot/systemd/user/mariadb-app.service index 98df8ed..fa018d3 100644 --- a/imageroot/systemd/user/mariadb-app.service +++ b/imageroot/systemd/user/mariadb-app.service @@ -21,7 +21,7 @@ ExecStart=/usr/bin/podman run --conmon-pidfile %t/mariadb-app.pid \ --pod-id-file %t/bookstack.pod-id --replace -d --name mariadb-app \ --env-file=%S/state/database.env \ --volume mysql-data:/var/lib/mysql/:Z \ - --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci + ${MARIADB_IMAGE} ExecStartPost=/usr/bin/podman exec mariadb-app /bin/bash -c 'printf "[client] \npassword=${MARIADB_ROOT_PASSWORD}" > /root/.my.cnf' ExecStop=/usr/bin/podman stop --ignore --cidfile %t/mariadb-app.ctr-id -t 10 ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/mariadb-app.ctr-id diff --git a/imageroot/update-module.d/migrate_vars b/imageroot/update-module.d/migrate_vars new file mode 100755 index 0000000..b120dac --- /dev/null +++ b/imageroot/update-module.d/migrate_vars @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 + +# +# Copyright (C) 2022 Nethesis S.r.l. +# SPDX-License-Identifier: GPL-3.0-or-later +# + +import os +import agent + +if os.path.exists("app-db.env"): + dt = agent.read_envfile("app-db.env") + if "DB_USERNAME" not in dt and "DB_USER" in dt: + dt["DB_USERNAME"] = dt.pop("DB_USER") + if "DB_PASSWORD" not in dt and "DB_PASS" in dt: + dt["DB_PASSWORD"] = dt.pop("DB_PASS") + agent.write_envfile("app-db.env", dt)