From a9d2e3aedd002869f488da3122745451d828ff4f Mon Sep 17 00:00:00 2001 From: Martin Bhuong Date: Fri, 8 Mar 2024 13:08:52 +0000 Subject: [PATCH] initial commits for IT-TOOLS --- .devcontainer/devcontainer.json | 2 +- .github/workflows/clean-registry.yml | 2 +- README.md | 77 ++++++------------ build-images.sh | 14 ++-- .../actions/configure-module/80start_services | 2 +- .../configure-module/validate-input.json | 10 +-- .../get-configuration/validate-output.json | 10 +-- .../actions/restore-module/40restore_database | 41 ---------- imageroot/bin/module-cleanup-state | 8 -- imageroot/bin/module-dump-state | 21 ----- imageroot/etc/state-include.conf | 4 +- .../smarthost-changed/10reload_services | 2 +- imageroot/systemd/user/it-tools-app.service | 33 ++++++++ imageroot/systemd/user/it-tools.service | 34 ++++++++ imageroot/systemd/user/kickstart-app.service | 42 ---------- imageroot/systemd/user/kickstart.service | 34 -------- imageroot/systemd/user/mariadb-app.service | 40 --------- imageroot/update-module.d/20restart | 2 +- tests/{kickstart.robot => it-tools.robot} | 10 +-- ui/public/i18n/en/translation.json | 4 +- ui/public/metadata.json | 18 ++-- ui/src/assets/module_default_logo.png | Bin 4199 -> 14705 bytes ui/src/views/Settings.vue | 4 +- 23 files changed, 135 insertions(+), 279 deletions(-) delete mode 100755 imageroot/actions/restore-module/40restore_database delete mode 100755 imageroot/bin/module-cleanup-state delete mode 100755 imageroot/bin/module-dump-state create mode 100644 imageroot/systemd/user/it-tools-app.service create mode 100644 imageroot/systemd/user/it-tools.service delete mode 100644 imageroot/systemd/user/kickstart-app.service delete mode 100644 imageroot/systemd/user/kickstart.service delete mode 100644 imageroot/systemd/user/mariadb-app.service rename tests/{kickstart.robot => it-tools.robot} (76%) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index cee5521..e1cec90 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,7 +1,7 @@ // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: // https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/javascript-node { - "name": "ns8-kickstart", + "name": "ns8-it-tools", "image": "mcr.microsoft.com/devcontainers/javascript-node:0-18-bullseye", // Configure tool-specific properties. "customizations": { diff --git a/.github/workflows/clean-registry.yml b/.github/workflows/clean-registry.yml index 82e36ae..70e75b8 100644 --- a/.github/workflows/clean-registry.yml +++ b/.github/workflows/clean-registry.yml @@ -15,5 +15,5 @@ jobs: steps: - uses: NethServer/ns8-github-actions/.github/actions/delete-image@v1 with: - images: "kickstart" + images: "it-tools" delete_image_token: ${{ secrets.IMAGES_CLEANUP_TOKEN }} diff --git a/README.md b/README.md index 548b9a5..2a923b3 100644 --- a/README.md +++ b/README.md @@ -1,48 +1,23 @@ -# ns8-kickstart +# ns8-it-tools -This is a template module for [NethServer 8](https://github.com/NethServer/ns8-core). -To start a new module from it: +This is a nehserver 8 App for [IT TEch Tools](https://github.com/CorentinTh/it-tools). +Useful tools for developer and people working in IT. -1. Click on [Use this template](https://github.com/NethServer/ns8-kickstart/generate). - Name your repo with `ns8-` prefix (e.g. `ns8-mymodule`). - Do not end your module name with a number, like ~~`ns8-baaad2`~~! - -1. Clone the repository, enter the cloned directory and - [configure your GIT identity](https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup#_your_identity) - -1. Rename some references inside the repo: - ``` - modulename=$(basename $(pwd) | sed 's/^ns8-//') && - git mv imageroot/systemd/user/kickstart.service imageroot/systemd/user/${modulename}.service && - git mv imageroot/systemd/user/kickstart-app.service imageroot/systemd/user/${modulename}-app.service && - git mv tests/kickstart.robot tests/${modulename}.robot && - sed -i "s/kickstart/${modulename}/g" $(find .github/ * -type f) && - git commit -a -m "Repository initialization" - ``` - -1. Edit this `README.md` file, by replacing this section with your module - description - -1. Adjust `.github/workflows` to your needs. `clean-registry.yml` might - need the proper list of image names to work correctly. Unused workflows - can be disabled from the GitHub Actions interface. - -1. Commit and push your local changes ## Install Instantiate the module with: - add-module ghcr.io/nethserver/kickstart:latest 1 + add-module ghcr.io/geniusdynamics/it-tools:latest 1 The output of the command will return the instance name. Output example: - {"module_id": "kickstart1", "image_name": "kickstart", "image_url": "ghcr.io/nethserver/kickstart:latest"} + {"module_id": "it-tools1", "image_name": "it-tools", "image_url": "ghcr.io/geniusdynamics/it-tools:latest"} ## Configure -Let's assume that the mattermost instance is named `kickstart1`. +Let's assume that the mattermost instance is named `it-tools1`. Launch `configure-module`, by setting the following parameters: - `host`: a fully qualified domain name for the application @@ -53,9 +28,9 @@ Launch `configure-module`, by setting the following parameters: Example: ``` -api-cli run configure-module --agent module/kickstart1 --data - <80/tcp 80b8de25945f-infra d8df02bf6f4a docker.io/library/mariadb:10.11.5 --character-set-s... 9 minutes ago Up 9 minutes 127.0.0.1:20015->80/tcp mariadb-app -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 kickstart-app +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 it-tools-app ``` you can see what environment variable is inside the container ``` -podman exec kickstart-app env +podman exec it-tools-app env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin TERM=xterm PKG_RELEASE=1 MARIADB_DB_HOST=127.0.0.1 -MARIADB_DB_NAME=kickstart +MARIADB_DB_NAME=it-tools MARIADB_IMAGE=docker.io/mariadb:10.11.5 MARIADB_DB_TYPE=mysql container=podman NGINX_VERSION=1.24.0 NJS_VERSION=0.7.12 -MARIADB_DB_USER=kickstart -MARIADB_DB_PASSWORD=kickstart +MARIADB_DB_USER=it-tools +MARIADB_DB_PASSWORD=it-tools MARIADB_DB_PORT=3306 HOME=/root ``` @@ -149,7 +124,7 @@ HOME=/root you can run a shell inside the container ``` -podman exec -ti kickstart-app sh +podman exec -ti it-tools-app sh / # ``` ## Testing @@ -157,7 +132,7 @@ podman exec -ti kickstart-app sh Test the module using the `test-module.sh` script: - ./test-module.sh ghcr.io/nethserver/kickstart:latest + ./test-module.sh ghcr.io/nethserver/it-tools:latest The tests are made using [Robot Framework](https://robotframework.org/) diff --git a/build-images.sh b/build-images.sh index 59304a4..4a18bd8 100644 --- a/build-images.sh +++ b/build-images.sh @@ -11,24 +11,24 @@ set -e # Prepare variables for later use images=() # The image will be pushed to GitHub container registry -repobase="${REPOBASE:-ghcr.io/nethserver}" +repobase="${REPOBASE:-ghcr.io/geniusdynamics}" # Configure the image name -reponame="kickstart" +reponame="it-tools" # Create a new empty container image container=$(buildah from scratch) -# Reuse existing nodebuilder-kickstart container, to speed up builds -if ! buildah containers --format "{{.ContainerName}}" | grep -q nodebuilder-kickstart; then +# Reuse existing nodebuilder-it-tools container, to speed up builds +if ! buildah containers --format "{{.ContainerName}}" | grep -q nodebuilder-it-tools; then echo "Pulling NodeJS runtime..." - buildah from --name nodebuilder-kickstart -v "${PWD}:/usr/src:Z" docker.io/library/node:lts + buildah from --name nodebuilder-it-tools -v "${PWD}:/usr/src:Z" docker.io/library/node:lts fi echo "Build static UI files with node..." buildah run \ --workingdir=/usr/src/ui \ --env="NODE_OPTIONS=--openssl-legacy-provider" \ - nodebuilder-kickstart \ + nodebuilder-it-tools \ sh -c "yarn install && yarn build" # Add imageroot directory to the container image @@ -45,7 +45,7 @@ buildah config --entrypoint=/ \ --label="org.nethserver.authorizations=traefik@node:routeadm" \ --label="org.nethserver.tcp-ports-demand=1" \ --label="org.nethserver.rootfull=0" \ - --label="org.nethserver.images=docker.io/mariadb:10.11.5 docker.io/nginx:stable-alpine3.17" \ + --label="org.nethserver.images=docker.io/corentinth/it-tools:latest" \ "${container}" # Commit the image buildah commit "${container}" "${repobase}/${reponame}" diff --git a/imageroot/actions/configure-module/80start_services b/imageroot/actions/configure-module/80start_services index ba46344..c988eb8 100755 --- a/imageroot/actions/configure-module/80start_services +++ b/imageroot/actions/configure-module/80start_services @@ -13,4 +13,4 @@ exec 1>&2 touch smarthost.env -systemctl --user enable --now kickstart.service +systemctl --user enable --now it-tools.service diff --git a/imageroot/actions/configure-module/validate-input.json b/imageroot/actions/configure-module/validate-input.json index 6289db8..5b96d41 100644 --- a/imageroot/actions/configure-module/validate-input.json +++ b/imageroot/actions/configure-module/validate-input.json @@ -1,11 +1,11 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Configure kickstart", - "$id": "http://nethserver.org/json-schema/task/input/kickstart/configure-module", - "description": "Configure kickstart", + "title": "Configure it-tools", + "$id": "http://nethserver.org/json-schema/task/input/it-tools/configure-module", + "description": "Configure it-tools", "examples": [ { - "host": "kickstart.domain.org", + "host": "it-tools.domain.org", "http2https": true, "lets_encrypt": true } @@ -19,7 +19,7 @@ "properties": { "host": { "type": "string", - "description": "Host name for the application, like 'kickstart.domain.org'", + "description": "Host name for the application, like 'it-tools.domain.org'", "format": "hostname", "pattern": "\\." }, diff --git a/imageroot/actions/get-configuration/validate-output.json b/imageroot/actions/get-configuration/validate-output.json index 04e246c..4f2fbc0 100644 --- a/imageroot/actions/get-configuration/validate-output.json +++ b/imageroot/actions/get-configuration/validate-output.json @@ -1,11 +1,11 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Get kickstart settings", - "$id": "http://nethserver.org/json-schema/task/input/kickstart/get-configuration", - "description": "Get kickstart settings", + "title": "Get it-tools settings", + "$id": "http://nethserver.org/json-schema/task/input/it-tools/get-configuration", + "description": "Get it-tools settings", "examples": [ { - "host": "kickstart.domain.org", + "host": "it-tools.domain.org", "http2https": true, "lets_encrypt": true } @@ -19,7 +19,7 @@ "properties": { "host": { "type": "string", - "description": "Host name for the application, like 'kickstart.domain.org'", + "description": "Host name for the application, like 'it-tools.domain.org'", "format": "idn-hostname" }, "lets_encrypt": { diff --git a/imageroot/actions/restore-module/40restore_database b/imageroot/actions/restore-module/40restore_database deleted file mode 100755 index 4c6ce36..0000000 --- a/imageroot/actions/restore-module/40restore_database +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -# -# Copyright (C) 2022 Nethesis S.r.l. -# SPDX-License-Identifier: GPL-3.0-or-later -# - -set -e -o pipefail -exec 1>&2 # Redirect any output to the journal (stderr) - -# Prepare an initialization script that restores the dump file -mkdir -vp initdb.d -mv -v kickstart.sql initdb.d -#do the bash file to restore and exit once done -cat - >initdb.d/zz_kickstart_restore.sh <<'EOS' -# Print additional information: -mysql --version -# The script is sourced, override entrypoint args and exit: -set -- true -docker_temp_server_stop -exit 0 -EOS - -# once we exit we remove initdb.d -trap 'rm -rfv initdb.d/' EXIT - -# we start a container to initiate a database and load the dump -# at the end of kickstart_restore.sh the dump is loaded and -# we exit the container -podman run \ - --rm \ - --interactive \ - --network=none \ - --volume=./initdb.d:/docker-entrypoint-initdb.d:z \ - --volume mysql-data:/var/lib/mysql/:Z \ - --env MARIADB_ROOT_PASSWORD=Nethesis,1234 \ - --env MARIADB_DATABASE=kickstart \ - --env MARIADB_USER=kickstart \ - --env MARIADB_PASSWORD=kickstart \ - --replace --name=restore_db \ - ${MARIADB_IMAGE} diff --git a/imageroot/bin/module-cleanup-state b/imageroot/bin/module-cleanup-state deleted file mode 100755 index 3de7b77..0000000 --- a/imageroot/bin/module-cleanup-state +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -# -# Copyright (C) 2022 Nethesis S.r.l. -# SPDX-License-Identifier: GPL-3.0-or-later -# - -rm -vf kickstart.sql diff --git a/imageroot/bin/module-dump-state b/imageroot/bin/module-dump-state deleted file mode 100755 index 1cfaec8..0000000 --- a/imageroot/bin/module-dump-state +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -# -# Copyright (C) 2022 Nethesis S.r.l. -# SPDX-License-Identifier: GPL-3.0-or-later -# - -set -e - -if ! systemctl --user -q is-active kickstart.service; then - exit 0 -fi - -podman exec mariadb-app mysqldump \ - --databases kickstart \ - --default-character-set=utf8mb4 \ - --skip-dump-date \ - --ignore-table=mysql.event \ - --single-transaction \ - --quick \ - --add-drop-table > kickstart.sql diff --git a/imageroot/etc/state-include.conf b/imageroot/etc/state-include.conf index 70bcdc7..b3d387d 100644 --- a/imageroot/etc/state-include.conf +++ b/imageroot/etc/state-include.conf @@ -5,6 +5,6 @@ # List here what you want to save during backup : volumes or file Path -state/kickstart.sql -volumes/kickstart-app +#state/kickstart.sql +#volumes/kickstart-app diff --git a/imageroot/events/smarthost-changed/10reload_services b/imageroot/events/smarthost-changed/10reload_services index 2132b78..aaa0e9c 100755 --- a/imageroot/events/smarthost-changed/10reload_services +++ b/imageroot/events/smarthost-changed/10reload_services @@ -7,4 +7,4 @@ set -e -systemctl --user try-reload-or-restart kickstart.service +systemctl --user try-reload-or-restart it-tools.service diff --git a/imageroot/systemd/user/it-tools-app.service b/imageroot/systemd/user/it-tools-app.service new file mode 100644 index 0000000..05b353e --- /dev/null +++ b/imageroot/systemd/user/it-tools-app.service @@ -0,0 +1,33 @@ +# +# Copyright (C) 2022 Nethesis S.r.l. +# SPDX-License-Identifier: GPL-3.0-or-later +# + +[Unit] +Description=Podman it-tools-app.service +BindsTo=it-tools.service +After=it-tools.service + +[Service] +Environment=PODMAN_SYSTEMD_UNIT=%n +EnvironmentFile=%S/state/environment +EnvironmentFile=-%S/state/smarthost.env +WorkingDirectory=%S/state +Restart=always +TimeoutStopSec=70 +ExecStartPre=/bin/mkdir -p config +ExecStartPre=/bin/rm -f %t/it-tools-app.pid %t/it-tools-app.ctr-id +ExecStartPre=-runagent discover-smarthost +ExecStart=/usr/bin/podman run --conmon-pidfile %t/it-tools-app.pid \ + --cidfile %t/it-tools-app.ctr-id --cgroups=no-conmon \ + --pod-id-file %t/it-tools.pod-id --replace -d --name it-tools-app \ + ${IT_TOOLS_IMAGE} +ExecStop=/usr/bin/podman stop --ignore --cidfile %t/it-tools-app.ctr-id -t 10 +ExecReload=/usr/bin/podman kill -s HUP it-tools-app +SyslogIdentifier=%u +ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/it-tools-app.ctr-id +PIDFile=%t/it-tools-app.pid +Type=forking + +[Install] +WantedBy=default.target diff --git a/imageroot/systemd/user/it-tools.service b/imageroot/systemd/user/it-tools.service new file mode 100644 index 0000000..c201b6d --- /dev/null +++ b/imageroot/systemd/user/it-tools.service @@ -0,0 +1,34 @@ +# +# Copyright (C) 2022 Nethesis S.r.l. +# SPDX-License-Identifier: GPL-3.0-or-later +# + +# +# This systemd unit starts a it-tools instance using Podman. +# Most parts of this file come from podman-generate-systemd. +# + +[Unit] +Description=Podman it-tools.service +Requires=it-tools-app.service +Before=it-tools-app.service + +[Service] +Environment=PODMAN_SYSTEMD_UNIT=%n +EnvironmentFile=-%S/state/environment +Restart=always +TimeoutStopSec=70 +ExecStartPre=/bin/rm -f %t/it-tools.pid %t/it-tools.pod-id +ExecStartPre=/usr/bin/podman pod create --infra-conmon-pidfile %t/it-tools.pid \ + --pod-id-file %t/it-tools.pod-id \ + --name it-tools \ + --publish 127.0.0.1:${TCP_PORT}:80 \ + --replace +ExecStart=/usr/bin/podman pod start --pod-id-file %t/it-tools.pod-id +ExecStop=/usr/bin/podman pod stop --ignore --pod-id-file %t/it-tools.pod-id -t 10 +ExecStopPost=/usr/bin/podman pod rm --ignore -f --pod-id-file %t/it-tools.pod-id +PIDFile=%t/it-tools.pid +Type=forking + +[Install] +WantedBy=default.target diff --git a/imageroot/systemd/user/kickstart-app.service b/imageroot/systemd/user/kickstart-app.service deleted file mode 100644 index 74a2a38..0000000 --- a/imageroot/systemd/user/kickstart-app.service +++ /dev/null @@ -1,42 +0,0 @@ -# -# Copyright (C) 2022 Nethesis S.r.l. -# SPDX-License-Identifier: GPL-3.0-or-later -# - -[Unit] -Description=Podman kickstart-app.service -BindsTo=kickstart.service -After=kickstart.service mariadb-app.service - -[Service] -Environment=PODMAN_SYSTEMD_UNIT=%n -EnvironmentFile=%S/state/environment -EnvironmentFile=-%S/state/smarthost.env -WorkingDirectory=%S/state -Restart=always -TimeoutStopSec=70 -ExecStartPre=/bin/mkdir -p config -ExecStartPre=/bin/rm -f %t/kickstart-app.pid %t/kickstart-app.ctr-id -ExecStartPre=-runagent discover-smarthost -ExecStart=/usr/bin/podman run --conmon-pidfile %t/kickstart-app.pid \ - --cidfile %t/kickstart-app.ctr-id --cgroups=no-conmon \ - --pod-id-file %t/kickstart.pod-id --replace -d --name kickstart-app \ - --volume kickstart-app:/var/www/html/:Z \ - --volume ./config:/tmp:Z \ - --env=MARIADB_* \ - --env MARIADB_DB_TYPE=mysql \ - --env MARIADB_DB_HOST=127.0.0.1 \ - --env MARIADB_DB_PORT=3306 \ - --env MARIADB_DB_USER=kickstart \ - --env MARIADB_DB_PASSWORD=kickstart \ - --env MARIADB_DB_NAME=kickstart \ - ${NGINX_IMAGE} -ExecStop=/usr/bin/podman stop --ignore --cidfile %t/kickstart-app.ctr-id -t 10 -ExecReload=/usr/bin/podman kill -s HUP kickstart-app -SyslogIdentifier=%u -ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/kickstart-app.ctr-id -PIDFile=%t/kickstart-app.pid -Type=forking - -[Install] -WantedBy=default.target diff --git a/imageroot/systemd/user/kickstart.service b/imageroot/systemd/user/kickstart.service deleted file mode 100644 index 2e19fad..0000000 --- a/imageroot/systemd/user/kickstart.service +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright (C) 2022 Nethesis S.r.l. -# SPDX-License-Identifier: GPL-3.0-or-later -# - -# -# This systemd unit starts a kickstart instance using Podman. -# Most parts of this file come from podman-generate-systemd. -# - -[Unit] -Description=Podman kickstart.service -Requires=mariadb-app.service kickstart-app.service -Before=mariadb-app.service kickstart-app.service - -[Service] -Environment=PODMAN_SYSTEMD_UNIT=%n -EnvironmentFile=-%S/state/environment -Restart=always -TimeoutStopSec=70 -ExecStartPre=/bin/rm -f %t/kickstart.pid %t/kickstart.pod-id -ExecStartPre=/usr/bin/podman pod create --infra-conmon-pidfile %t/kickstart.pid \ - --pod-id-file %t/kickstart.pod-id \ - --name kickstart \ - --publish 127.0.0.1:${TCP_PORT}:80 \ - --replace -ExecStart=/usr/bin/podman pod start --pod-id-file %t/kickstart.pod-id -ExecStop=/usr/bin/podman pod stop --ignore --pod-id-file %t/kickstart.pod-id -t 10 -ExecStopPost=/usr/bin/podman pod rm --ignore -f --pod-id-file %t/kickstart.pod-id -PIDFile=%t/kickstart.pid -Type=forking - -[Install] -WantedBy=default.target diff --git a/imageroot/systemd/user/mariadb-app.service b/imageroot/systemd/user/mariadb-app.service deleted file mode 100644 index d4212a1..0000000 --- a/imageroot/systemd/user/mariadb-app.service +++ /dev/null @@ -1,40 +0,0 @@ -# -# Copyright (C) 2022 Nethesis S.r.l. -# SPDX-License-Identifier: GPL-3.0-or-later -# - -[Unit] -Description=Podman mariadb-app.service -BindsTo=kickstart.service -After=kickstart.service - -[Service] -Environment=PODMAN_SYSTEMD_UNIT=%n -EnvironmentFile=%S/state/environment -# EnvironmentFile=%S/state/secrets/passwords.secret -Restart=always -TimeoutStopSec=70 -ExecStartPre=/bin/rm -f %t/mariadb-app.pid %t/mariadb-app.ctr-id -ExecStart=/usr/bin/podman run --conmon-pidfile %t/mariadb-app.pid \ - --cidfile %t/mariadb-app.ctr-id --cgroups=no-conmon \ - --pod-id-file %t/kickstart.pod-id --replace -d --name mariadb-app \ - --env-file=%S/state/environment \ - --volume mysql-data:/var/lib/mysql/:Z \ - --env MARIADB_ROOT_PASSWORD=Nethesis,1234 \ - --env MARIADB_DATABASE=kickstart \ - --env MARIADB_USER=kickstart \ - --env MARIADB_PASSWORD=kickstart \ - --env MARIADB_AUTO_UPGRADE=1 \ - ${MARIADB_IMAGE} \ - --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci -ExecStartPost=/usr/bin/podman exec mariadb-app /bin/bash -c 'printf "[client] \npassword=Nethesis,1234" > /root/.my.cnf' -ExecStartPost=/usr/bin/podman exec mariadb-app /bin/bash -c "while ! mysqladmin ping -h localhost -P 3306 -u root; do sleep 1; done" -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 -ExecReload=/usr/bin/podman kill -s HUP mariadb-app -SyslogIdentifier=%u -PIDFile=%t/mariadb-app.pid -Type=forking - -[Install] -WantedBy=default.target diff --git a/imageroot/update-module.d/20restart b/imageroot/update-module.d/20restart index ae0f791..6dfc8d8 100755 --- a/imageroot/update-module.d/20restart +++ b/imageroot/update-module.d/20restart @@ -12,4 +12,4 @@ set -e # Redirect any output to the journal (stderr) exec 1>&2 -systemctl --user try-restart kickstart.service +systemctl --user try-restart it-tools.service diff --git a/tests/kickstart.robot b/tests/it-tools.robot similarity index 76% rename from tests/kickstart.robot rename to tests/it-tools.robot index e1984f0..7320f4a 100644 --- a/tests/kickstart.robot +++ b/tests/it-tools.robot @@ -2,24 +2,24 @@ Library SSHLibrary *** Test Cases *** -Check if kickstart is installed correctly +Check if it-tools is installed correctly ${output} ${rc} = Execute Command add-module ${IMAGE_URL} 1 ... return_rc=True Should Be Equal As Integers ${rc} 0 &{output} = Evaluate ${output} Set Suite Variable ${module_id} ${output.module_id} -Check if kickstart can be configured +Check if it-tools can be configured ${rc} = Execute Command api-cli run module/${module_id}/configure-module --data '{}' ... return_rc=True return_stdout=False Should Be Equal As Integers ${rc} 0 -Check if kickstart works as expected - ${rc} = Execute Command curl -f http://127.0.0.1/kickstart/ +Check if it-tools works as expected + ${rc} = Execute Command curl -f http://127.0.0.1/it-tools/ ... return_rc=True return_stdout=False Should Be Equal As Integers ${rc} 0 -Check if kickstart is removed correctly +Check if it-tools is removed correctly ${rc} = Execute Command remove-module --no-preserve ${module_id} ... return_rc=True return_stdout=False Should Be Equal As Integers ${rc} 0 diff --git a/ui/public/i18n/en/translation.json b/ui/public/i18n/en/translation.json index b26b3bb..e767963 100644 --- a/ui/public/i18n/en/translation.json +++ b/ui/public/i18n/en/translation.json @@ -24,14 +24,14 @@ "title": "Settings", "configure_instance": "Configure {instance}", "save": "Save", - "kickstart_fqdn": "kickstart hostname (FQDN)", + "it-tools_fqdn": "it-tools hostname (FQDN)", "lets_encrypt": "Request LE Certificate", "http_to_https": "Force HTTPS", "enabled": "Enabled", "disabled": "Disabled", "advanced": "Advanced", "configuring": "Configuring", - "instance_configuration": "Configure kickstart", + "instance_configuration": "Configure it-tools", "domain_already_used_in_traefik": "Domain already used in traefik", "host_pattern": "Must be a valid fully qualified domain name", "host_format": "Must be a valid fully qualified domain name" diff --git a/ui/public/metadata.json b/ui/public/metadata.json index 305a6f5..1f34e0c 100644 --- a/ui/public/metadata.json +++ b/ui/public/metadata.json @@ -1,19 +1,19 @@ { - "name": "kickstart", + "name": "it-tools", "description": { - "en": "My kickstart module" + "en": "Useful tools for developer and people working in IT" }, - "categories": [], + "categories": ["development"], "authors": [ { - "name": "Name Surname", - "email": "author@yourmail.org" + "name": "Martin Bhuong", + "email": "martin@genius.ke" } ], "docs": { - "documentation_url": "https://docs.kickstart.com/", - "bug_url": "https://github.com/NethServer/dev", - "code_url": "https://github.com/author/ns8-kickstart" + "documentation_url": "https://docs.it-tools.com/", + "bug_url": "https://github.com/geniusdynamics/dev", + "code_url": "https://github.com/genius-dynamics/ns8-it-tools" }, - "source": "ghcr.io/nethserver/kickstart" + "source": "ghcr.io/geniusdynamics/it-tools" } diff --git a/ui/src/assets/module_default_logo.png b/ui/src/assets/module_default_logo.png index 29e55971a9003a4b75562b5a33063a07dbceda00..8240f325057a8330385c7eb3420e48185f2bd2a9 100644 GIT binary patch literal 14705 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 literal 4199 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 xJRo=2U(ilZ?HKmA4ed