From 979398e398e45c08bd50dc78b72a63341f5339b8 Mon Sep 17 00:00:00 2001 From: Matthias Stecher Date: Sat, 24 Oct 2020 09:05:22 +0200 Subject: [PATCH] Initial __nextcloud type This type should work, but there are still many things to do here to work nice and well. Things that currently not work (well): - not all parameters work for now - nextcloud installations in subfolders (e.g. slashes in the object id) --- type/__nextcloud/explorer/config | 28 +++ type/__nextcloud/explorer/installdir | 16 ++ type/__nextcloud/explorer/version | 19 ++ type/__nextcloud/explorer/webroot | 34 +++ type/__nextcloud/gencode-remote | 209 ++++++++++++++++++ type/__nextcloud/manifest | 132 +++++++++++ type/__nextcloud/map-conf-changes.sh | 196 ++++++++++++++++ type/__nextcloud/parameter/boolean | 1 + .../parameter/default/database-type | 1 + type/__nextcloud/parameter/default/group | 1 + type/__nextcloud/parameter/default/mode | 1 + type/__nextcloud/parameter/default/user | 1 + type/__nextcloud/parameter/optional | 13 ++ type/__nextcloud/parameter/optional_multiple | 1 + type/__nextcloud/parameter/required | 2 + 15 files changed, 655 insertions(+) create mode 100755 type/__nextcloud/explorer/config create mode 100755 type/__nextcloud/explorer/installdir create mode 100755 type/__nextcloud/explorer/version create mode 100755 type/__nextcloud/explorer/webroot create mode 100755 type/__nextcloud/gencode-remote create mode 100755 type/__nextcloud/manifest create mode 100755 type/__nextcloud/map-conf-changes.sh create mode 100644 type/__nextcloud/parameter/boolean create mode 100644 type/__nextcloud/parameter/default/database-type create mode 100644 type/__nextcloud/parameter/default/group create mode 100644 type/__nextcloud/parameter/default/mode create mode 100644 type/__nextcloud/parameter/default/user create mode 100644 type/__nextcloud/parameter/optional create mode 100644 type/__nextcloud/parameter/optional_multiple create mode 100644 type/__nextcloud/parameter/required diff --git a/type/__nextcloud/explorer/config b/type/__nextcloud/explorer/config new file mode 100755 index 0000000..998264e --- /dev/null +++ b/type/__nextcloud/explorer/config @@ -0,0 +1,28 @@ +#!/bin/sh -e +# __nextcloud/explorer/config + +# Checks the nextcloud configuration + + +# Get the installdir +user="$( cat "$__object/parameter/user" )" +installdir="$( "$__type_explorer/installdir" )" + +# Check if the tools are available +if [ -d "$installdir" ]; then + cd "$installdir" + + # if those files exist, everything should be good + if [ -f "occ" ] && [ -f "config/config.php" ]; then + # dump out config instead of fuzz every possible option through + # `occ config:system:get`. Or parse through the whole json or + # yaml-like output of `occ config:list system --private`. + php -r 'require("lib/private/Config.php"); $config = new OC\Config("config/"); + function printv($key, $value) {printf("%s = %s\n", $key, $value);} + foreach($config->getKeys() as $key){ + $value = $config->getValue($key); + if(is_array($value)) foreach($value as $n => $in) printv($n."|".$key, $in); + else printv($key, $value); + };' + fi +fi diff --git a/type/__nextcloud/explorer/installdir b/type/__nextcloud/explorer/installdir new file mode 100755 index 0000000..7b34f2e --- /dev/null +++ b/type/__nextcloud/explorer/installdir @@ -0,0 +1,16 @@ +#!/bin/sh -e +# __nextcloud/explorer/installdir + +# Detects the directory nextcloud should be installed to. + + +# by parameter or auto-detection +webroot="$( "$__type_explorer/webroot" )" +if [ -z "$webroot" ]; then + echo "no installdir given and no webroot directory found" >&2 + echo "no place to install found; set it via --webroot" >&2 + exit 1 +fi + +# assemble directory with the object id +printf "%s/%s\n" "$webroot" "$__object_id" diff --git a/type/__nextcloud/explorer/version b/type/__nextcloud/explorer/version new file mode 100755 index 0000000..fc79206 --- /dev/null +++ b/type/__nextcloud/explorer/version @@ -0,0 +1,19 @@ +#!/bin/sh -e +# __nextcloud/explorer/version + +# Check the currently installed version. Outputs nothing if nothing found. + + +# Get the install directory +installdir="$( "$__type_explorer/installdir" )" + +# Check if the installation directory exists +if [ -d "$installdir" ]; then + cd "$installdir" + + # if those files exist, everything should be good + if [ -f "occ" ] && [ -f "version.php" ]; then + # detect php version with the version file + php -r 'require("version.php"); print($OC_VersionString);' + fi +fi diff --git a/type/__nextcloud/explorer/webroot b/type/__nextcloud/explorer/webroot new file mode 100755 index 0000000..7eab286 --- /dev/null +++ b/type/__nextcloud/explorer/webroot @@ -0,0 +1,34 @@ +#!/bin/sh -e +# __nextcloud/explorer/webroot + +# Detects the webroot if any + + +# Just check if there is some directory and echo + exit on success +# +# Arguments: +# 1: the directory to check +check_dir() { + if [ -d "$1" ]; then + echo "$1" + exit + fi +} + + +# Check the user choice +parameter="$__object/parameter/webroot" +if [ -f "$parameter" ]; then + cat "$parameter" + exit +fi + +# Maybe checking standard webserver configs .. + +# Check if there are default directories +check_dir "/srv/www" +check_dir "/var/www/html" +check_dir "/var/www" + + +# do nothing if no webroot found diff --git a/type/__nextcloud/gencode-remote b/type/__nextcloud/gencode-remote new file mode 100755 index 0000000..60d9b42 --- /dev/null +++ b/type/__nextcloud/gencode-remote @@ -0,0 +1,209 @@ +#!/bin/sh -e +# __nextcloud/gencode-remote + +# Install if not installed + +# Legacy: +# curl -sS -L '$nextcloud_uri' | tar xj --strip-components=1 nextcloud/ + + +# Call the nextcloud occ script as the designed user. Maybe this can be a bit +# more effictive with user switching, but currently the easiest way of doing +# it. +# +# All arguments are directly passed to occ (injection alarm ;-) ) +occ() { + # su creates a new shell, so it does not affect the current session + # will not use -q as it supresses errors, too + cat << SHELL +su -s /bin/sh -l "$user" -- -e <> "$__messages_out" + +# Apply some misc to the installation folder. +elif [ "$install" ]; then + cat << REMOTE +chown '$user':'$group' -R '$installdir' +REMOTE +fi + + +# Check if the nextcloud application needs to be installed. +# This checks the state of the configuration, not of the directory. +if ! grep -q -F "installed = 1" "$__object/explorer/config"; then + # argument construction + occ_install_args="" + + # Database + db_setup() { + if ! [ -f "$__object/parameter/db-host" ]; then + echo "no hostname given! can't proceed." >&2 + exit 3 + fi + occ_install_args="$occ_install_args --database '$1'" + occ_install_args="$occ_install_args --database-host '$(cat "$__object/parameter/db-host")'" + + db_name="$__object/parameter/database-name" + if [ -f "$db_name" ]; then + occ_install_args="$occ_install_args --database-name '$(cat "$db_name")'" + fi + db_user="$__object/parameter/database-user" + if [ -f "$db_user" ]; then + occ_install_args="$occ_install_args --database-user '$(cat "$db_user")'" + fi + db_pass="$__object/parameter/database-password" + if [ -f "$db_pass" ]; then + occ_install_args="$occ_install_args --database-pass '$(cat "$db_pass")'" + fi + db_prefix="$__object/parameter/database-prefix" + if [ -f "$db_prefix" ]; then + occ_install_args="$occ_install_args --database-table-prefix '$(cat "$db_prefix")'" + fi + } + + database_type="$(cat "$__object/parameter/database-type")" + case "$database_type" in + sqlite|sqlite3) + occ_install_args="$occ_install_args --database sqlite" + ;; + mysql|mariadb) + db_setup mysql + ;; + pgsql|postgres|postgresql) + db_setup pgsql + ;; + + *) + printf "Database type '%s' is unkown!\n" "" >&2 + exit 3 + ;; + esac + + # Admin stuff + occ_install_args="$occ_install_args --admin-pass '$(cat "$__object/parameter/admin-password")'" + + admin_user="$__object/parameter/admin-user" + if [ -f "$admin_user" ]; then + occ_install_args="$occ_install_args --admin-user '$(cat "$admin_user")'" + fi + admin_email="$__object/parameter/admin-email" + if [ -f "$admin_email" ]; then + occ_install_args="$occ_install_args --admin-email '$(cat "$admin_email")'" + fi + + # Data directory + datadir="$__object/parameter/datadir" + if [ -f "$datadir" ]; then + occ_install_args="$occ_install_args --data-dir '$(cat "$datadir")'" + fi + + + # Execute the install command + occ maintenance:install $occ_install_args + + # send install message + echo installed >> "$__messages_out" +fi + + +# Handle the config +mkdir "$__object/files" +"$__type/map-conf-changes.sh" > "$__object/files/conf-cmds" + +# only print if there are changes listed +if [ -s "$__object/files/conf-cmds" ]; then + # save that we did changes + changes="yes" + + # print change commands incl. the switch of user context + # using -e to abort if the commands failed + printf "su -s /bin/sh -l '%s' -- -e << 'SU'\n" "$user" + printf "cd '%s'\n" "$installdir" + cat "$__object/files/conf-cmds" + printf "SU\n" + + # print a message + echo config >> "$__messages_out" +fi + + +# Check if this is the fist install +if [ "$install" ]; then + # do some convert stuff etc. + + # variable accessible from the last $install if-clause + case "$database_type" in + mysql|mariadb) + # only available for mysql + occ db:convert-mysql-charset + ;; + esac + + occ db:convert-filecache-bigint +fi + +# Disable maintainer mode +if [ "$install" ] || [ "$upgrade" ] || [ "$changes" ]; then + occ maintenance:mode --off +fi diff --git a/type/__nextcloud/manifest b/type/__nextcloud/manifest new file mode 100755 index 0000000..f6b8865 --- /dev/null +++ b/type/__nextcloud/manifest @@ -0,0 +1,132 @@ +#!/bin/sh -e +# __nextcloud/manifest + + +# Version compare function original from __sensible_editor +# +# Arguments: +# 1: version of which $2 should be checked against +# 2: version which should be bigger than or equal with $1 +# +# Return code: +# 0: $1 is bigger than $2 +# 1-n: $1 is smaller than or equal $2 +version_ge() { + printf "%s" "$1" | awk -F '[^0-9.]' -v target="$2" ' + function max(x, y) { return x > y ? x : y } + BEGIN { + getline + nx = split($1, x, ".") + ny = split(target, y, ".") + for (i = 1; i <= max(nx, ny); ++i) { + diff = int(x[i]) - int(y[i]) + if (diff == 0) continue + exit (diff < 0) + } + exit 1 + }'; return $? +} + + +# Check support status +os="$(cat "$__global/explorer/os")" + +case "$os" in + debian|ubuntu) + # PHP main + __package php-cli + # to unpack the package + __package bzip2 + # install misc packages for nextcloud + __package ffmpeg + + # PHP modules + for package in php-gd php-json php-mysql php-curl php-mbstring php-intl \ + php-imagick php-xml php-zip php-bz2 php-bcmath php-gmp + do + require="__package/php-cli" __package $package + done + + # check support database additions (but don't remove junk of old ones) + case "$(cat "$__object/parameter/database-type")" in + sqlite|sqlite3) + __package php-sqlite3 + ;; + mysql|mariadb) + __package php-mysql + ;; + pgsql|postgres|postgresql) + __package php-pgsql + ;; + esac + ;; + + # unkown distro - what to install? + *) + printf "unkown %s, don't know what to install ..\n" "$os" >&2 + echo "checkout the __nextcloud/manifest to contribute a working package list" >&2 + exit 1 + ;; +esac + + +# Get the user and group +mode="$(cat "$__object/parameter/mode")" +user="$(cat "$__object/parameter/user")" +group="$(cat "$__object/parameter/group")" + +# Get the installation directory +webroot="$(cat "$__object/explorer/webroot")" +installdir="$(cat "$__object/explorer/installdir")" + +# Set permissions after the nextcloud installation/upgrade is done +# FIXME maybe less strict if some parameter is not given by the user? +# permissions also partily set via the gencode-remote +require="__nextcloud/$__object_id" __directory "$installdir" \ + --mode "$mode" --owner "$user" --group "$group" + + +# Get version information +version_is="$( cat "$__object/explorer/version" )" +version_should="$( cat "$__object/parameter/version" )" +# The version URI +nextcloud_uri="https://download.nextcloud.com/server/releases/nextcloud-${version_should}.tar.bz2" +nextcloud_sum="${nextcloud_uri}.sha256" + + +# Only check if there is a current installation +if [ "$version_is" ]; then + # Block downgrades as there are may caused from the automatic upgrader + # if the current version is higher than the version that should be installed + if version_ge "$version_is" "$version_should"; then + # it's an error if the current version is higher than the one that should be installed + printf "The current nextcloud version '%s' is higher than the version that should be installed (%s)\n" \ + "$version_is" "$version_should" >&2 + printf "Please bump the nextcloud version to '%s' or higher!\n" "$version_is" >&2 + exit 2 + fi + + # Set destination to a temporary directory + destination="$webroot/.$__object_id" +else + # Set destination to the real destination + destination="$webroot/$__object_id" +fi + +# Upgrade the nextcloud version +if [ "$version_is" != "$version_should" ]; then + updatedir="$( dirname "$installdir" )" + + # Be sure the parent directory exists for installation + __directory "$updatedir" --parents + + require="__directory$updatedir" \ + __download "$updatedir/nextcloud.tar.bz2" \ + --url "$nextcloud_uri" \ + --sum "sha256:$(curl -sS -L "$nextcloud_sum" | awk '{print $1}')" # must be a required parameter?? + + require="__download$updatedir/nextcloud.tar.bz2" \ + __unpack "$updatedir/nextcloud.tar.bz2" \ + --tar-strip 1 \ + --destination "$destination" +fi diff --git a/type/__nextcloud/map-conf-changes.sh b/type/__nextcloud/map-conf-changes.sh new file mode 100755 index 0000000..8a00ac6 --- /dev/null +++ b/type/__nextcloud/map-conf-changes.sh @@ -0,0 +1,196 @@ +#!/bin/sh -e +# __nextcloud/map-conf-changes.sh + + +# The environment variable "$install" should be set if nextcloud was installed +# now. This changes the behaviour to not trust gathered values from the +# explorer. + + +# Test if the value exists as given. +# +# Arguments: +# 1: The nextcloud config name +# 2: The value that should be set +# +# Return code: +# 0: value exactly matched +# 1: value not matched or do not exist +testparam() { + # short-circuit after installation; the explorer may not be valid + if [ "$install" ]; then return 1; fi + + if grep -q -F "$1 = $2" "$__object/explorer/config"; then + return 0 + else + return 1 + fi +} + +# Test if the parameter is somehow set. +# +# Arguments: +# 1: The nextcloud config name +# +# Return code: +# 0: param exists +# 1: param not found +paramexist() { + # short-circuit after installation; the explorer may not be valid + if [ "$install" ]; then return 0; fi + + if grep -q "^$1 = " "$__object/explorer/config"; then + return 0 + else + return 1 + fi +} + +# Base for the basic function types. +# +# Arguments: +# 1: cdist type parameter name +# 2: nextcloud config name +# 3: occ printf pattern to set the value +conf_base() { + if [ -f "$__object/parameter/$1" ]; then + value="$(cat "$__object/parameter/$1")" + if ! testparam "$2" "$value"; then + # set it because it does not exist + printf "php occ config:system:$3\n" "$2" "$value" + fi + else + if paramexist "$2"; then + # remove it because it exists + printf "php occ config:system:delete '%s'\n" "$2" + fi + fi +} + +# Set's the cdist parameter value to nextcloud as specific value. +# +# Arguments: +# 1: cdist type parameter name +# 2: nextcloud config name +conf_string() { + conf_base "$1" "$2" "set '%s' --type=string --value='%s'" +} +conf_number() { + conf_base "$1" "$2" "set '%s' --type=integer --value='%s'" +} +conf_decimal() { + conf_base "$1" "$2" "set '%s' --type=double --value='%s'" +} + +# Sets the nextcloud configuration option after a boolean cdist parameter. +# +# Arguments: +# 1: cdist type parameter name +# 2: nextcloud config name +conf_boolean() { + # map parameter to a php boolean (are outputted as 0 or 1) + if [ -f "$__object/parameter/$1" ]; then + testval="1" + value="true" + else + testval="0" + value="false" + fi + + if ! testparam "$2" "$testval"; then + # set it if does not already exist + printf "php occ config:system:set '%s' --type=boolean --value=%s\n" "$2" "$value" + fi +} + +# Corrects the array after all values given by the parameter. Values not given +# to this type will be removed. +# +# Arguments: +# 1: cdist type parameter name +# 2: nextcloud config name +conf_array() { + if [ -f "$__object/parameter/$1" ]; then + # reset array if installation is fresh + if [ "$install" ]; then + # just remove everything, because we don't know it + printf "php occ config:system:delete '%s' || true\n" "$2" + + # counter is zero for sure + counter=0 + + # else, default behaviour of the array + else + # save counter of the next free index + counter=$( awk -v FS=" = " -v name="$2" ' + BEGIN { counter = 0 } + split($1, header, "|") == 2 && header[1] ~ /^[[:digit:]]+$/ && header[2] == name \ + { if(counter < header[1]) counter = header[1] } + END { print counter + 1 } + ' "$__object/explorer/config" + ) + + # create a file which contains all lines not already resolved by this function + _dir="$__object/files/conf-arrays" + mkdir -p "$_dir" + grep "^[[:digit:]]*|$2 = " "$__object/explorer/config" > "$_dir/$2" || true # ignore not found + fi + + # iterate through every value + while read -r value; do + # check every value if he exists + if ! grep -q "^[[:digit:]]*|$2 = $value$" "$__object/explorer/config"; then + # add this value + printf "php occ config:system:set '%s' '%s' --type=string --value='%s'\n" \ + "$2" "$(( counter ))" "$value" + counter=$(( counter + 1 )) + fi + + if [ -z "$install" ]; then + # removes it from the list of unhandled values + grep -v "^[[:digit:]]*|$2 = $value$" "$_dir/$2" > "$_dir/$2_tmp" || true # ignore not found + mv "$_dir/$2_tmp" "$_dir/$2" # because we can't do `cat foo > foo` + fi + done < "$__object/parameter/$1" + + if [ -z "$install" ]; then + # interate through the leftover values + # remove them, as they should not exist (at least can be) + while read -r start equal value; do + # remove those specific elements from the array + printf "php occ config:system:delete '%s' '%s' --error-if-not-exists\n" \ + "$2" "$( printf "%s" "$start" | awk -F'|' '{print $1}' )" + done < "$_dir/$2" + fi + else + # remove everything because we don't know which was set by the user + if paramexist "$2"; then + # remove the whole array + printf "php occ config:system:delete '%s'\n" "$2" + fi + fi +} + +# Set the install variable if nextcloud was not installed before this type. +if ! testparam installed 1; then + install="yes" +fi + + +# Map all parameters + +# Generate the config changes + +# misc +conf_array host trusted_domains + +# Already set via the installer +if [ -z "$install" ]; then + # db + conf_string database-type dbtype + conf_string database-host dbhost # FIXME host included here (takes port also) + conf_string database-name dbname + conf_string database-user dbuser + conf_string database-password dbpassword + conf_string database-prefix dbtableprefix +fi diff --git a/type/__nextcloud/parameter/boolean b/type/__nextcloud/parameter/boolean new file mode 100644 index 0000000..0853f49 --- /dev/null +++ b/type/__nextcloud/parameter/boolean @@ -0,0 +1 @@ +install-only diff --git a/type/__nextcloud/parameter/default/database-type b/type/__nextcloud/parameter/default/database-type new file mode 100644 index 0000000..8b2f60c --- /dev/null +++ b/type/__nextcloud/parameter/default/database-type @@ -0,0 +1 @@ +sqlite3 diff --git a/type/__nextcloud/parameter/default/group b/type/__nextcloud/parameter/default/group new file mode 100644 index 0000000..5bbad18 --- /dev/null +++ b/type/__nextcloud/parameter/default/group @@ -0,0 +1 @@ +www-data diff --git a/type/__nextcloud/parameter/default/mode b/type/__nextcloud/parameter/default/mode new file mode 100644 index 0000000..20610ea --- /dev/null +++ b/type/__nextcloud/parameter/default/mode @@ -0,0 +1 @@ +755 diff --git a/type/__nextcloud/parameter/default/user b/type/__nextcloud/parameter/default/user new file mode 100644 index 0000000..5bbad18 --- /dev/null +++ b/type/__nextcloud/parameter/default/user @@ -0,0 +1 @@ +www-data diff --git a/type/__nextcloud/parameter/optional b/type/__nextcloud/parameter/optional new file mode 100644 index 0000000..cd09af4 --- /dev/null +++ b/type/__nextcloud/parameter/optional @@ -0,0 +1,13 @@ +mode +user +group +webroot +database-type +database-host +database-name +database-user +database-password +database-prefix +admin-user +admin-email +data-directory diff --git a/type/__nextcloud/parameter/optional_multiple b/type/__nextcloud/parameter/optional_multiple new file mode 100644 index 0000000..c70dc2d --- /dev/null +++ b/type/__nextcloud/parameter/optional_multiple @@ -0,0 +1 @@ +host diff --git a/type/__nextcloud/parameter/required b/type/__nextcloud/parameter/required new file mode 100644 index 0000000..3e83467 --- /dev/null +++ b/type/__nextcloud/parameter/required @@ -0,0 +1,2 @@ +version +admin-password