[sysadm] [dd-ctl] improvements and simplifications
Amongst other things: - Consolidates other scripts into dd-ctl - Notably: securize_conf.sh and sysadm/debian_docker_and_compose.sh are due for deletion - gives dd-ctl a better structure for future maintainability - libffi-dev is needed on Debian buster, which is the recommended OS - Installs the dictionaries as a prerequisite for securize This paves the way to a simpler installation
parent
dafd45612e
commit
f5c9334aac
376
dd-ctl
376
dd-ctl
|
@ -1,40 +1,101 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
if [ ! -d "custom" ]; then echo "You need to copy custom.sample to custom folder and adapt it to your needs." && exit 1; fi
|
|
||||||
if [ ! -f "digitaldemocratic.conf" ]; then echo "You need to copy digitaldemocratic.conf.sample to digitaldemocratic.conf and adapt" && exit 1; fi
|
|
||||||
|
|
||||||
OPERATION="$1"
|
OPERATION="$1"
|
||||||
if [ -z "$OPERATION" ]; then
|
|
||||||
set +x
|
help() {
|
||||||
echo "Missing command."
|
cat <<-EOF
|
||||||
echo " Example: ./dd.ctl [operation]"
|
Example: ./dd.ctl [operation] [arguments]
|
||||||
echo " Update repository: ./dd-ctl repo-update [branch-name] (defaults to master)"
|
|
||||||
echo " Bring the current project up: ./dd-ctl all"
|
For a new installation, you usually will want to run:
|
||||||
echo " Build the compose files: ./dd-ctl build"
|
./dd-ctl repo-update
|
||||||
echo " Regenerate docker-compose.yml from conf: ./dd-ctl yml"
|
./dd-ctl prerequisites
|
||||||
echo " Build the devel compose files: ./dd-ctl build-devel"
|
./dd-ctl securize
|
||||||
echo " Start the project when stopped: ./dd-ctl up"
|
./dd-ctl all
|
||||||
echo " Stop the project when started: ./dd-ctl down"
|
./dd-ctl saml
|
||||||
echo " Apply customizations: ./dd-ctl customize"
|
|
||||||
echo " Update SAML certificates: ./dd-ctl saml"
|
|
||||||
echo " Upgrade plugins: ./dd-ctl upgrade-plugins"
|
Generate adminer.yml to access DBs: ./dd-ctl adminer
|
||||||
echo " Branding (custom/img, custom/menu): ./dd-ctl branding"
|
Bring the current project up: ./dd-ctl all
|
||||||
echo " Restart api if changes applied (development): ./dd-ctl restart-api"
|
Branding (custom/img, custom/menu): ./dd-ctl branding
|
||||||
echo " Generate adminer.yml to access DBs: ./dd-ctl adminer"
|
Build the compose files: ./dd-ctl build
|
||||||
echo " Rescan nextcloud data folders: ./dd-ctl nextcloud-scan"
|
Build the devel compose files: ./dd-ctl build-devel
|
||||||
exit 1
|
Apply customizations: ./dd-ctl customize
|
||||||
|
Stop the project when started: ./dd-ctl down
|
||||||
|
Rescan nextcloud data folders: ./dd-ctl nextcloud-scan
|
||||||
|
Install all prerequisites for installation: ./dd-ctl prerequisites
|
||||||
|
Update repository: ./dd-ctl repo-update [branch-name] (defaults to master)
|
||||||
|
Restart api if changes applied (development): ./dd-ctl restart-api
|
||||||
|
Update SAML certificates: ./dd-ctl saml
|
||||||
|
Set secure passwords in digitaldemocratic.conf: ./dd-ctl securize
|
||||||
|
Set a config variable in digitaldemocratic.conf: ./dd-ctl setconf VARIABLE [VALUE]
|
||||||
|
Start the project when stopped: ./dd-ctl up
|
||||||
|
Upgrade plugins: ./dd-ctl upgrade-plugins
|
||||||
|
Regenerate docker-compose.yml from conf: ./dd-ctl yml
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
# Help messages
|
||||||
|
if [ -z "$OPERATION" ] || [ "$OPERATION" = "-h" ] || [ "$OPERATION" = "--help" ]; then
|
||||||
|
test -n "$OPERATION" || printf "Missing command.\n\n"
|
||||||
|
help
|
||||||
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
BRANCH="$2"
|
# Sanity checks
|
||||||
if [ -z "$BRANCH" ]; then
|
if [ "$OPERATION" != "prerequisites" ]; then
|
||||||
BRANCH="master"
|
if [ ! -d "custom" ]; then
|
||||||
|
echo "You need to copy custom.sample to custom folder and adapt it to your needs."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ ! -f "digitaldemocratic.conf" ]; then
|
||||||
|
echo "You need to copy digitaldemocratic.conf.sample to digitaldemocratic.conf and adapt"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
BRANCH="${2:-master}"
|
||||||
|
|
||||||
|
|
||||||
cp digitaldemocratic.conf .env
|
cp digitaldemocratic.conf .env
|
||||||
CUSTOM_PATH=$(pwd)
|
CUSTOM_PATH=$(pwd)
|
||||||
. ./.env
|
. ./.env
|
||||||
|
|
||||||
|
prerequisites_docker(){
|
||||||
|
# Remove uncompatible docker packages
|
||||||
|
for pkg in docker docker-engine docker.io containerd runc; do
|
||||||
|
if dpkg -s "${pkg}" >/dev/null; then
|
||||||
|
apt-get remove -y "${pkg}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Install upstream-docker repo pre-requisites
|
||||||
|
apt-get install -y \
|
||||||
|
apt-transport-https \
|
||||||
|
ca-certificates \
|
||||||
|
curl \
|
||||||
|
gnupg-agent \
|
||||||
|
software-properties-common \
|
||||||
|
git \
|
||||||
|
unzip \
|
||||||
|
libffi-dev
|
||||||
|
|
||||||
|
curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -
|
||||||
|
add-apt-repository \
|
||||||
|
"deb [arch=amd64] https://download.docker.com/linux/debian \
|
||||||
|
$(lsb_release -cs) \
|
||||||
|
stable"
|
||||||
|
apt-get update -y
|
||||||
|
# docker-ce must be used instead of the one from the distro
|
||||||
|
apt-get install -y docker-ce docker-ce-cli containerd.io
|
||||||
|
|
||||||
|
apt-get install -y python3-pip
|
||||||
|
# docker-compose > 1.28 is required, latest will be installed
|
||||||
|
pip3 install docker-compose
|
||||||
|
}
|
||||||
|
prerequisites_pwd(){
|
||||||
|
apt-get install -y dictionaries-common wamerican
|
||||||
|
}
|
||||||
|
|
||||||
update_repo(){
|
update_repo(){
|
||||||
git fetch && git checkout $BRANCH
|
git fetch && git checkout $BRANCH
|
||||||
git submodule update --init --recursive
|
git submodule update --init --recursive
|
||||||
|
@ -483,117 +544,170 @@ configure_nextcloud_logo(){
|
||||||
docker exec -u www-data isard-apps-nextcloud-app php occ config:app:set theming cachebuster --value="$(expr $cachebuster + 1 )"
|
docker exec -u www-data isard-apps-nextcloud-app php occ config:app:set theming cachebuster --value="$(expr $cachebuster + 1 )"
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ "$OPERATION" = "repo-update" ]; then
|
genpwd() {
|
||||||
update_repo
|
if [ ! -f /usr/share/dict/words ]; then
|
||||||
fi
|
prerequisites_pwd > /dev/null
|
||||||
|
fi
|
||||||
|
shuf -n3 /usr/share/dict/words | tr -d "\n" | tr -d "'"
|
||||||
|
}
|
||||||
|
|
||||||
if [ "$OPERATION" = "build" ]; then
|
securize() {
|
||||||
build
|
for dd_var in \
|
||||||
fi
|
SMTP_PASSWORD \
|
||||||
|
ADMINAPP_PASSWORD \
|
||||||
|
DDADMIN_PASSWORD \
|
||||||
|
KEYCLOAK_PASSWORD \
|
||||||
|
KEYCLOAK_DB_PASSWORD \
|
||||||
|
POSTGRES_PASSWORD \
|
||||||
|
MARIADB_PASSWORD \
|
||||||
|
MOODLE_POSTGRES_PASSWORD \
|
||||||
|
MOODLE_ADMIN_PASSWORD \
|
||||||
|
NEXTCLOUD_POSTGRES_PASSWORD \
|
||||||
|
NEXTCLOUD_ADMIN_PASSWORD \
|
||||||
|
ETHERPAD_POSTGRES_PASSWORD \
|
||||||
|
ETHERPAD_ADMIN_PASSWORD \
|
||||||
|
WORDPRESS_MARIADB_PASSWORD \
|
||||||
|
WORDPRESS_ADMIN_PASSWORD \
|
||||||
|
IPA_ADMIN_PWD; do
|
||||||
|
setconf "${dd_var}" "$(genpwd)"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
if [ "$OPERATION" = "yml" ]; then
|
setconf() {
|
||||||
cp digitaldemocratic.conf .env
|
dd_var="$(echo "$1" | tr "[:lower:]" "[:upper:]")"
|
||||||
CUSTOM_PATH=$(pwd)
|
dd_val="$2"
|
||||||
. ./.env
|
dd_line="$(printf '%s="%s"' "${dd_var:?}" "${dd_val}")"
|
||||||
build_compose
|
if grep -qE "^${dd_var:?}=" digitaldemocratic.conf; then
|
||||||
fi
|
# Found uncommented, replace in-place
|
||||||
|
sed -i'' -E "s!^${dd_var:?}=.*\$!${dd_line}!" digitaldemocratic.conf
|
||||||
|
elif grep -qE "^#[[:space:]]*${dd_var:?}=" digitaldemocratic.conf; then
|
||||||
|
# Found commented, replace in-place
|
||||||
|
sed -i'' -E "s!^#[[:space:]]*${dd_var:?}=.*\$!${dd_line}!" digitaldemocratic.conf
|
||||||
|
else
|
||||||
|
# Not found, append
|
||||||
|
echo "${dd_line}" >> digitaldemocratic.conf
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
if [ "$OPERATION" = "build-devel" ]; then
|
# Argument handling
|
||||||
build_compose_develop
|
case "$OPERATION" in
|
||||||
fi
|
build)
|
||||||
|
build
|
||||||
|
;;
|
||||||
|
build-devel)
|
||||||
|
build_compose_develop
|
||||||
|
;;
|
||||||
|
adminer)
|
||||||
|
extras_adminer
|
||||||
|
;;
|
||||||
|
all)
|
||||||
|
build
|
||||||
|
up
|
||||||
|
|
||||||
if [ "$OPERATION" = "up" ]; then
|
wait_for_moodle
|
||||||
up
|
upgrade_plugins_moodle
|
||||||
fi
|
upgrade_plugins_nextcloud
|
||||||
|
upgrade_plugins_wp
|
||||||
|
|
||||||
if [ "$OPERATION" = "down" ]; then
|
setup_nextcloud
|
||||||
down
|
setup_wordpress
|
||||||
fi
|
setup_moodle
|
||||||
|
|
||||||
if [ "$OPERATION" = "customize" ]; then
|
setup_keycloak
|
||||||
up
|
saml_certificates
|
||||||
wait_for_moodle
|
|
||||||
setup_nextcloud
|
|
||||||
setup_wordpress
|
|
||||||
setup_moodle
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$OPERATION" = "saml" ]; then
|
cat <<-EOF
|
||||||
up
|
|
||||||
wait_for_moodle
|
|
||||||
setup_keycloak
|
|
||||||
saml_certificates
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$OPERATION" = "all" ]; then
|
#### After install ####
|
||||||
build
|
- SSO in moodle should be active. You can go to: https://moodle.$DOMAIN
|
||||||
up
|
If it fails, regenerate and lock certificate in moodle SAML2 connector as a local admin.
|
||||||
|
After that run ./dd-ctl saml
|
||||||
|
- SSO in nextcloud should be active. You can go to: https://nextcloud.$DOMAIN
|
||||||
|
- SSO in wordpress should be active. You should go to https://wp.$DOMAIN/wp-admin//plugins.php
|
||||||
|
|
||||||
wait_for_moodle
|
#### Update customizations ####
|
||||||
upgrade_plugins_moodle
|
- ./dd-ctl customize
|
||||||
upgrade_plugins_nextcloud
|
EOF
|
||||||
upgrade_plugins_wp
|
;;
|
||||||
|
branding)
|
||||||
setup_nextcloud
|
up
|
||||||
setup_wordpress
|
wait_for_moodle
|
||||||
setup_moodle
|
update_logos_and_menu
|
||||||
|
;;
|
||||||
setup_keycloak
|
customize)
|
||||||
saml_certificates
|
up
|
||||||
|
wait_for_moodle
|
||||||
echo "\n\n"
|
setup_nextcloud
|
||||||
echo " #### After install ####"
|
setup_wordpress
|
||||||
echo " - SSO in moodle should be active. You can go to: https://moodle.$DOMAIN"
|
setup_moodle
|
||||||
echo " If it fails, regenerate and lock certificate in moodle SAML2 connector as a local admin."
|
;;
|
||||||
echo " After that run ./dd-ctl saml"
|
down)
|
||||||
echo " - SSO in nextcloud should be active. You can go to: https://nextcloud.$DOMAIN"
|
down
|
||||||
echo " - SSO in wordpress should be active. You should go to https://wp.$DOMAIN/wp-admin//plugins.php "
|
;;
|
||||||
|
nextcloud-scan)
|
||||||
echo "\n\n"
|
nextcloud_scan
|
||||||
echo " #### Update customizations ####"
|
;;
|
||||||
echo " - ./dd-ctl customize"
|
pgtuner)
|
||||||
fi
|
extras_pgtuner
|
||||||
|
;;
|
||||||
if [ "$OPERATION" = "branding" ]; then
|
prerequisites)
|
||||||
up
|
prerequisites_docker
|
||||||
wait_for_moodle
|
prerequisites_pwd
|
||||||
update_logos_and_menu
|
;;
|
||||||
fi
|
repo-update)
|
||||||
|
update_repo
|
||||||
if [ "$OPERATION" = "upgrade-plugins" ]; then
|
;;
|
||||||
up
|
reset-data|reset-1714)
|
||||||
wait_for_moodle
|
cat <<-EOF
|
||||||
upgrade_plugins_moodle
|
# Following commands RESET ALL DATA except for certificates
|
||||||
upgrade_plugins_nextcloud
|
# execute them only if you know what you are doing
|
||||||
upgrade_plugins_wp
|
# This *will* result in DATA LOSS
|
||||||
fi
|
"$0" down
|
||||||
|
rm -rf /opt/digitaldemocratic/backup
|
||||||
if [ "$OPERATION" = "restart-api" ]; then
|
rm -rf /opt/digitaldemocratic/data/*
|
||||||
up
|
rm -rf /opt/digitaldemocratic/db/*
|
||||||
wait_for_moodle
|
rm -rf '$SRC_FOLDER/avatars'
|
||||||
docker restart isard-sso-api
|
rm -rf '$SRC_FOLDER/moodle'
|
||||||
fi
|
rm -rf '$SRC_FOLDER/nextcloud'
|
||||||
|
rm -rf '$SRC_FOLDER/wordpress'
|
||||||
if [ "$OPERATION" = "adminer" ]; then
|
EOF
|
||||||
extras_adminer
|
;;
|
||||||
fi
|
restart-api)
|
||||||
|
up
|
||||||
if [ "$OPERATION" = "pgtuner" ]; then
|
wait_for_moodle
|
||||||
extras_pgtuner
|
docker restart isard-sso-api
|
||||||
fi
|
;;
|
||||||
|
saml)
|
||||||
if [ "$OPERATION" = "reset-1714" ]; then
|
up
|
||||||
echo "Resetting all but certificates"
|
wait_for_moodle
|
||||||
down
|
setup_keycloak
|
||||||
rm -rf /opt/digitaldemocratic/backup
|
saml_certificates
|
||||||
rm -rf /opt/digitaldemocratic/data/*
|
;;
|
||||||
rm -rf /opt/digitaldemocratic/db/*
|
securize)
|
||||||
rm -rf $SRC_FOLDER/avatars
|
securize
|
||||||
rm -rf $SRC_FOLDER/moodle
|
;;
|
||||||
rm -rf $SRC_FOLDER/nextcloud
|
setconf)
|
||||||
rm -rf $SRC_FOLDER/wordpress
|
setconf "$2" "$3"
|
||||||
fi
|
;;
|
||||||
|
up)
|
||||||
if [ "$OPERATION" = "nextcloud-scan" ]; then
|
up
|
||||||
nextcloud_scan
|
;;
|
||||||
fi
|
upgrade-plugins)
|
||||||
|
up
|
||||||
|
wait_for_moodle
|
||||||
|
upgrade_plugins_moodle
|
||||||
|
upgrade_plugins_nextcloud
|
||||||
|
upgrade_plugins_wp
|
||||||
|
;;
|
||||||
|
yml)
|
||||||
|
cp digitaldemocratic.conf .env
|
||||||
|
CUSTOM_PATH=$(pwd)
|
||||||
|
. ./.env
|
||||||
|
build_compose
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf "Unknown command '%s'\n\n" "$OPERATION" >&2
|
||||||
|
help >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
|
@ -1,50 +1,10 @@
|
||||||
#!/bin/sh
|
#!/bin/sh -eu
|
||||||
apt install dictionaries-common wamerican -y
|
|
||||||
|
|
||||||
PWD=$(shuf -n3 /usr/share/dict/words | tr -d "\n" | tr -d "'")
|
cd "$(dirname "$0")"
|
||||||
sed -i "/^SMTP_PASSWORD=/c\SMTP_PASSWORD=$PWD" digitaldemocratic.conf
|
./dd-ctl securize
|
||||||
|
|
||||||
PWD=$(shuf -n3 /usr/share/dict/words | tr -d "\n" | tr -d "'")
|
cat >&2 <<EOF
|
||||||
sed -i "/^ADMINAPP_PASSWORD=/c\ADMINAPP_PASSWORD=$PWD" digitaldemocratic.conf
|
|
||||||
|
|
||||||
PWD=$(shuf -n3 /usr/share/dict/words | tr -d "\n" | tr -d "'")
|
This script will be removed!
|
||||||
sed -i "/^DDADMIN_PASSWORD=/c\DDADMIN_PASSWORD=$PWD" digitaldemocratic.conf
|
Please run './dd-ctl securize' in the future.
|
||||||
|
EOF
|
||||||
PWD=$(shuf -n3 /usr/share/dict/words | tr -d "\n" | tr -d "'")
|
|
||||||
sed -i "/^KEYCLOAK_PASSWORD=/c\KEYCLOAK_PASSWORD=$PWD" digitaldemocratic.conf
|
|
||||||
|
|
||||||
PWD=$(shuf -n3 /usr/share/dict/words | tr -d "\n" | tr -d "'")
|
|
||||||
sed -i "/^KEYCLOAK_DB_PASSWORD=/c\KEYCLOAK_DB_PASSWORD=$PWD" digitaldemocratic.conf
|
|
||||||
|
|
||||||
PWD=$(shuf -n3 /usr/share/dict/words | tr -d "\n" | tr -d "'")
|
|
||||||
sed -i "/^POSTGRES_PASSWORD=/c\POSTGRES_PASSWORD=$PWD" digitaldemocratic.conf
|
|
||||||
|
|
||||||
PWD=$(shuf -n3 /usr/share/dict/words | tr -d "\n" | tr -d "'")
|
|
||||||
sed -i "/^MARIADB_PASSWORD=/c\MARIADB_PASSWORD=$PWD" digitaldemocratic.conf
|
|
||||||
|
|
||||||
PWD=$(shuf -n3 /usr/share/dict/words | tr -d "\n" | tr -d "'")
|
|
||||||
sed -i "/^MOODLE_POSTGRES_PASSWORD=/c\MOODLE_POSTGRES_PASSWORD=$PWD" digitaldemocratic.conf
|
|
||||||
|
|
||||||
PWD=$(shuf -n3 /usr/share/dict/words | tr -d "\n" | tr -d "'")
|
|
||||||
sed -i "/^MOODLE_ADMIN_PASSWORD=/c\MOODLE_ADMIN_PASSWORD=$PWD" digitaldemocratic.conf
|
|
||||||
|
|
||||||
PWD=$(shuf -n3 /usr/share/dict/words | tr -d "\n" | tr -d "'")
|
|
||||||
sed -i "/^NEXTCLOUD_POSTGRES_PASSWORD=/c\NEXTCLOUD_POSTGRES_PASSWORD=$PWD" digitaldemocratic.conf
|
|
||||||
|
|
||||||
PWD=$(shuf -n3 /usr/share/dict/words | tr -d "\n" | tr -d "'")
|
|
||||||
sed -i "/^NEXTCLOUD_ADMIN_PASSWORD=/c\NEXTCLOUD_ADMIN_PASSWORD=$PWD" digitaldemocratic.conf
|
|
||||||
|
|
||||||
PWD=$(shuf -n3 /usr/share/dict/words | tr -d "\n" | tr -d "'")
|
|
||||||
sed -i "/^ETHERPAD_POSTGRES_PASSWORD=/c\ETHERPAD_POSTGRES_PASSWORD=$PWD" digitaldemocratic.conf
|
|
||||||
|
|
||||||
PWD=$(shuf -n3 /usr/share/dict/words | tr -d "\n" | tr -d "'")
|
|
||||||
sed -i "/^ETHERPAD_ADMIN_PASSWORD=/c\ETHERPAD_ADMIN_PASSWORD=$PWD" digitaldemocratic.conf
|
|
||||||
|
|
||||||
PWD=$(shuf -n3 /usr/share/dict/words | tr -d "\n" | tr -d "'")
|
|
||||||
sed -i "/^WORDPRESS_MARIADB_PASSWORD=/c\WORDPRESS_MARIADB_PASSWORD=$PWD" digitaldemocratic.conf
|
|
||||||
|
|
||||||
PWD=$(shuf -n3 /usr/share/dict/words | tr -d "\n" | tr -d "'")
|
|
||||||
sed -i "/^WORDPRESS_ADMIN_PASSWORD=/c\WORDPRESS_ADMIN_PASSWORD=$PWD" digitaldemocratic.conf
|
|
||||||
|
|
||||||
PWD=$(shuf -n3 /usr/share/dict/words | tr -d "\n" | tr -d "'")
|
|
||||||
sed -i "/^IPA_ADMIN_PWD=/c\IPA_ADMIN_PWD=$PWD" digitaldemocratic.conf
|
|
||||||
|
|
|
@ -1,21 +1,10 @@
|
||||||
apt-get remove docker docker-engine docker.io containerd runc
|
#!/bin/sh -eu
|
||||||
apt-get install -y \
|
|
||||||
apt-transport-https \
|
|
||||||
ca-certificates \
|
|
||||||
curl \
|
|
||||||
gnupg-agent \
|
|
||||||
software-properties-common \
|
|
||||||
git \
|
|
||||||
unzip
|
|
||||||
curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -
|
|
||||||
add-apt-repository \
|
|
||||||
"deb [arch=amd64] https://download.docker.com/linux/debian \
|
|
||||||
$(lsb_release -cs) \
|
|
||||||
stable"
|
|
||||||
apt-get update -y
|
|
||||||
apt-get install -y docker-ce docker-ce-cli containerd.io
|
|
||||||
|
|
||||||
apt install python3-pip -y
|
cd "$(dirname "$0")/.."
|
||||||
pip3 install docker-compose
|
./dd-ctl prerequisites
|
||||||
|
|
||||||
apt install dictionaries-common wamerican -y
|
cat >&2 <<EOF
|
||||||
|
|
||||||
|
This script will be removed!
|
||||||
|
Please run './dd-ctl prerequisites' in the future.
|
||||||
|
EOF
|
||||||
|
|
Loading…
Reference in New Issue