commit ab89e9d4de08e028bd1875a972451dfaf977852c Author: Yavuz Aydın Date: Fri Nov 11 10:31:17 2022 +0100 Initial release diff --git a/README.md b/README.md new file mode 100644 index 0000000..538e89b --- /dev/null +++ b/README.md @@ -0,0 +1,77 @@ +DirectAdmin Scripts +========================= + +Various scripts which help administration of DirectAdmin servers easier. + +# da_php_version_selections.sh + +A script to show, save, and restore selection of the PHP version for each domain. Its intented use case is when there's a need to upgrade the PHP versions installed on the server, or change the default PHP version. It allows you to save the current version used by domains, and then after options.conf is updated, modify selections to ensure the same (if possible) version of PHP is used, even though the release number has changed. See comments in the script for more details. + +A typical use case/scenario would be: + +1. You save the current PHP selections: + ``` + da_php_version_selections.sh > ~/selections.txt + ``` +1. You update options.conf and rearrange PHP versions, or change the default +1. You update selections to make sure domains get the correct PHP version, + ``` + da_php_version_selections.sh selections.txt + ``` +1. You run `/usr/local/directadmin/custombuild/build rewrite_confs` + +# da_php_swap_version.sh + +Swap version index numbers in config. This might be helpful when changing the order of your php-fpm index numbers in the DirectAdmin configuration. + +In case version "1" has been requested, change configs with no version set, as "1" is the default. + +A typical use case/scenario would be: + +1. Check which PHP versions are installed in which order: + ``` + egrep php[1,2,3,4]_release= /usr/local/directadmin/custombuild/options.conf + ``` + Output: + ``` + php1_release=7.2 + php2_release=7.0 + php3_release=7.4 + php4_release=no + ``` +1. Let's make 7.4 the default PHP versions: + ``` + da_php_swap_version.sh 1 3 + ``` +1. Update DirectAdmin options and rebuild php: + ``` + /usr/local/directadmin/custombuild/build set php1_release 7.4 + /usr/local/directadmin/custombuild/build set php3_release 7.2 + /usr/local/directadmin/custombuild/build php n + ``` + +# da_php_update_version.sh + +Search for specific PHP version (1-4) and replace with specified version. If replacement of version "1" has been requested, change configs with no version set, as "1" is the default. + +A typical use case/scenario would be: + +1. Check which PHP versions are installed in which order: + ``` + egrep php[1,2,3,4]_release= /usr/local/directadmin/custombuild/options.conf + ``` + Output: + ``` + php1_release=7.2 + php2_release=7.0 + php3_release=7.4 + php4_release=no + ``` +1. We want to retire PHP 7.0, let's update config for all websites currently using PHP 7.0 to make use of PHP 7.4: + ``` + da_php_update_version.sh -s 2 -r 3 + ``` +1. Rewrite configurations: + ``` + /usr/local/directadmin/custombuild/build rewrite_confs + ``` diff --git a/da_php_swap_version.sh b/da_php_swap_version.sh new file mode 100755 index 0000000..3fe4be5 --- /dev/null +++ b/da_php_swap_version.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +# Swap version index numbers in config. This might be helpful when changing the +# order of your php-fpm index numbers in the DirectAdmin configuration. +# In case version "1" has been requested, change configs with no version +# set, as "1" is the default. + +set -euo pipefail +# helper functions +die() { echo "$*" >&2; exit 1;} +warn() { echo "$*" >&2; } + +usage="Usage: $0 " + +[ `id -nu` != "root" ] && die "Please execute as root" + +[ "$#" -ne 2 ] && die $usage +! [[ "$1" =~ ^[1-4]$ ]] && die $usage +! [[ "$2" =~ ^[1-4]$ ]] && die $usage + +version_swap1=$1 +version_swap2=$2 + +swap_version() { + local conf=$1 + local version_current + + [ -f "$conf" ] || die "File does not exist: $conf" + + # Get current version if set in config + set +e + version_current=$(grep -soP "php1_select=\K[0-9]" $conf) + set -e + [ $? -eq 2 ] && die "grep encountered a fatal error" + + if [ -z $version_current ]; then + # current version not found in config. assume "1" + version_current=1 + fi + + # Is this the version we're looking for? + if [ $version_current -eq $version_swap1 ]; then + # replace or add line + sed -i '/^php1_select=/{h;s/=.*/='$version_swap2'/};${x;/^$/{s//php1_select='$version_swap2'/;H};x}' "$conf" + echo "$conf: changed" + elif [ $version_current -eq $version_swap2 ]; then + # replace or add line + sed -i '/^php1_select=/{h;s/=.*/='$version_swap1'/};${x;/^$/{s//php1_select='$version_swap1'/;H};x}' "$conf" + echo "$conf: changed" + fi +} + +for f in /usr/local/directadmin/data/users/*/domains/*.conf; do + swap_version $f +done + +echo "To update the running configuration, please run: /usr/local/directadmin/custombuild/build rewrite_confs" diff --git a/da_php_update_version.sh b/da_php_update_version.sh new file mode 100755 index 0000000..7d6aee7 --- /dev/null +++ b/da_php_update_version.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +# Search for specific version (1-4) and replace with specified version. If +# replacement of version "1" has been requested, change configs with no version +# set, as "1" is the default. + +set -euo pipefail +# helper functions +die() { echo "$*" >&2; exit 1;} +warn() { echo "$*" >&2; } + +# Default values +confused=false +version_search=0 +version_replace=0 + +[ `id -nu` != "root" ] && die "Please execute as root" + +while getopts s:r:v c; do + case "$c" in + s) version_search="$OPTARG";; + r) version_replace="$OPTARG";; + *) confused=true;; + esac +done + +shift `expr $OPTIND - 1` + +$confused || [ "$version_search" -eq 0 -o "$version_replace" -eq 0 ] && die "Usage: -s -r " +! [[ "$version_search" =~ ^[1-4]$ ]] && die "Search version should be between 1-4" +! [[ "$version_replace" =~ ^[1-4]$ ]] && die "Replacement version should be between 1-4" + +replace_version() { + local conf=$1 + local version_current + + [ -f "$conf" ] || die "File does not exist: $conf" + + # Get current version if set in config + set +e + version_current=$(grep -soP "php1_select=\K[0-9]" $conf) + set -e + [ $? -eq 2 ] && die "grep encountered a fatal error" + + if [ -z $version_current ]; then + # current version not found in config. assume "1" + #echo "$conf has no version set, assume 1" + version_current=1 + fi + + # Is this the version we're looking for? + if [ $version_current -eq $version_search ]; then + # replace or add line + sed -i '/^php1_select=/{h;s/=.*/='$version_replace'/};${x;/^$/{s//php1_select='$version_replace'/;H};x}' "$conf" + echo "$conf: changed" + fi +} + +for f in /usr/local/directadmin/data/users/*/domains/*.conf; do + replace_version $f +done + +echo "To update the running configuration, please run: /usr/local/directadmin/custombuild/build rewrite_confs" diff --git a/da_php_version_selections.sh b/da_php_version_selections.sh new file mode 100755 index 0000000..adcf23b --- /dev/null +++ b/da_php_version_selections.sh @@ -0,0 +1,243 @@ +#!/bin/bash + +# A script to save and restore selection of actual PHP version for each domain. +# +# Repository: https://gitlab.com/nordhost/da-scripts + +# Copyright (C) 2021 Kristian Rønningen + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Usage: +# php-version-selections +# +# Ran without arguments, the script will print the current PHP selection for +# each domain. This output can be redirected to a file ("selections_file") to be +# used as input to the script later. +# +# Ran with a filename as the only argument, the script will try to ensure the +# desired version of PHP is selected for the domain, regardless of the order of +# the versions in options.conf. This can be useful if you want to for example +# change the current default version, but want to let domains still use the same +# version, even if they were just using the default one. It will also allow you +# to reorder the PHP versions in options.conf if you want to, and still let +# domains use the same PHP version afterwards. +# +# If a domain has selected to use a PHP version that no longer exist among the +# four available versions, it will fall back to use the default version, +# whatever it may be. +# +# A typical use case/scenario would be: +# +# 1) You save the current PHP selections, +# `php-version-selections > ~/selections.txt` +# 2) You update options.conf and rearrange PHP versions, or change the default +# 3) You update selections to make sure domains get the correct PHP version, +# `php-versions-selections selections.txt` +# 4) You run `/usr/local/directadmin/custombuild/build rewrite_confs` +# +# NOTE: +# * Error detection might not be present in all steps. Use at your own risk. +# * Domains that are domain pointers will not have their own config file, and +# will therefore return "wrerror" +# +if [ ! -r "/etc/virtual/domainowners" ]; then + echo "Error: Can't read /etc/virtual/domainowners" + exit 1 +fi + +if [ ! -r "/usr/local/directadmin/custombuild/options.conf" ]; then + echo "Error: Can't read /usr/local/directadmin/custombuild/options.conf" + exit 1 +fi + +function getAvailableReleases() { + # Fetch available releases as defined for DirectAdmin's custombuild + php_release[1]=$(grep -oP "^php1_release=\K.*(?=$)" /usr/local/directadmin/custombuild/options.conf) + php_release[2]=$(grep -oP "^php2_release=\K.*(?=$)" /usr/local/directadmin/custombuild/options.conf) + php_release[3]=$(grep -oP "^php3_release=\K.*(?=$)" /usr/local/directadmin/custombuild/options.conf) + php_release[4]=$(grep -oP "^php4_release=\K.*(?=$)" /usr/local/directadmin/custombuild/options.conf) +} + +function getLongestDomainName() { + # Find the longest domain name, used for padding output later + domain_max_length=$(cat /etc/virtual/domainowners | cut -d":" -f1 | wc -L) +} + +function printPhpSelections() { + for domain in $(cat /etc/virtual/domainowners | cut -d":" -f1); do + domainconffile=$(ls -1 /usr/local/directadmin/data/users/*/domains/${domain}.conf 2>&1 | head -1) + if [ ! -r "${domainconffile}" ]; then + # Domain has no config, and will use the default PHP version + # (php1_release), whatever it might be. + domain_active_version="${php_release[1]}:0" + domain_active_version_info="no config - using default" + else + # Fetch the php1_select for the domain + php_select[1]=$(grep -oP "^php1_select=\K.*(?=$)" ${domainconffile}) + + if [ -z "${php_select[1]}" ]; then + # Config has no php_select setting, and the domain will use the default PHP + # version (php1_release), whatever it might be. + domain_active_version="${php_release[1]}:0" + domain_active_version_info="no selection - using default" + else + domain_active_version="${php_release[${php_select[1]}]}:${php_select[1]}" + domain_active_version_info="selected version" + fi + fi + printf "%-$((domain_max_length+2))s %$((${#php_release[1]}+3))s %s\n" \ + "${domain}" \ + "${domain_active_version}" \ + "(${domain_active_version_info})" + done +} + +function setDomainPhpSelection() { + # Expected arguments: + # $1 = Domain config file, full path + # $2 = The new php selection number (not version) + local domainconffile accountdir domainname + domainconffile="${1}" + + if [ -w "${domainconffile}" ]; then + # Update (or add) the php selection with the new release number + sed -i.backup_php_version_selections "/^php1_select=/{h;s/=.*/=${2}/};\${x;/^$/{s//php1_select=${2}/;H};x}" "${domainconffile}" + if [ "${?}" -eq 0 ]; then + echo "success" + else + echo "failure" + fi + else + # There's no config file for this domain. See if the domain is listed as + # a pointer for any other domain under this account. + accountdir="$(dirname ${domainconffile})" + domainname="$(basename ${domainconffile%.conf})" + grep -q "^${domainname//[.]/\\.}=" "${accountdir}/"*.pointers + if [ ${?} -eq 0 ]; then + # We found a match for the domain in a .pointers file + echo "pointer" + else + # It's not pointer, might be some other problem. Report as error so + # someone can manually check what's going on. + echo "wrerror" + fi + fi +} + +function setPhpSelections() { + for domain in $(cat /etc/virtual/domainowners | cut -d":" -f1); do + domain_user=$(grep -oP "^${domain//[.]/\\.}: \K.+(?=$)" /etc/virtual/domainowners) + domain_config_file="/usr/local/directadmin/data/users/${domain_user}/domains/${domain}.conf" + # Look up the stored selections for this domain + domain_selected_version=$(grep -oP "^${domain//[.]/\\.} +\K[^:]+(?=:.*$)" "${selections_file}") + if [ ${?} -ne 0 ]; then + # If grep exited with non-zero, it likely means the domain doesn't + # exist in the selections_file, so we'll skip any further processing + # of this domain. + # domain.com 7.2:2 -> 7.2:3 changeresult (info) + printf "%-$((domain_max_length+2))s %s\n" \ + "${domain}" \ + "Skipping - domain not in selections file" + continue + fi + domain_selected_release=$(grep -oP "^${domain//[.]/\\.} +[^:]+:\K[0-9](?=.*$)" "${selections_file}") + domain_wanted_version="${domain_selected_version}:${domain_selected_release}" + + # Find out which selection this version is now + domain_selected_release_new="" + for key in "${!php_release[@]}"; do + if [ "${domain_selected_version}" = "${php_release[${key}]}" ]; then + # This is the release selection we want. If the key is "1", then + # it's the default. If the domain_selected_release is 0, then we + # don't have to change anything, since the default is the same + # version. + if [ ${domain_selected_release} -eq 0 -a ${key} -eq 1 ]; then + domain_selected_release_new=0 + else + domain_selected_release_new=${key} + fi + fi + done + + if [ -z "${domain_selected_release_new}" ]; then + # The selected version no longer exist among the four options, so + # fall back to the default (php1_release) release/version. + # Must update the domain config. + domain_selected_release_new=1 + domain_getting_version="${php_release[${domain_selected_release_new}]}:${domain_selected_release_new}" + domain_getting_version_info="default fallback - selected version no longer exists" + domain_release_change_result=$(setDomainPhpSelection "${domain_config_file}" "${domain_selected_release_new}") + elif [ "${domain_selected_release}" != "${domain_selected_release_new}" ]; then + # The version exists, but is now a different release number in the + # list. + # Must update the domain config. + domain_getting_version="${php_release[${domain_selected_release_new}]}:${domain_selected_release_new}" + domain_getting_version_info="version kept, selection changed" + domain_release_change_result=$(setDomainPhpSelection "${domain_config_file}" "${domain_selected_release_new}") + elif [ ${domain_selected_release_new} -eq 0 ]; then + # The version existed, and is (still) the default version. Nothing + # changes. No need to update anything. + domain_getting_version="${php_release[1]}:${domain_selected_release_new}" + domain_getting_version_info="default version kept, default selection kept" + domain_release_change_result="nochange" + else + # The version existed, and it's the same release as before, but not + # the default. No need to update anything. + domain_getting_version="${php_release[${domain_selected_release_new}]}:${domain_selected_release_new}" + domain_getting_version_info="version kept, selection kept" + domain_release_change_result="nochange" + fi + + # domain.com 7.2:2 -> 7.2:3 changeresult (info) + printf "%-$((domain_max_length+2))s %$((${#php_release[1]}+3))s -> %-$((${#php_release[1]}+3))s %-9s %s\n" \ + "${domain}" \ + "${domain_wanted_version}" \ + "${domain_getting_version}" \ + "${domain_release_change_result}" \ + "(${domain_getting_version_info})" + done + + echo "" + echo "You will want to run /usr/local/directadmin/custombuild/build rewrite_confs now" + echo "to ensure all domains get their correct PHP version active." +} + +getAvailableReleases +getLongestDomainName + +# If there's an argument passed to the script, we assume it's the selections +# file, and we want the script to try to ensure the active selections match +# those described in the selections file. If there are no arguments, assume we +# want to create the selections list. +if [ ${#} -eq 0 ]; then + printPhpSelections +else + selections_file="${1}" + if [ ! -r "${selections_file}" ]; then + echo "Error: Can't read the file \"${selections_file}\". Pass the filename as the first argument." + exit 1 + fi + echo "WARNING: Running this script will make changes to the following files:" + echo "/usr/local/directadmin/data/users//domains/.conf" + echo "In case it goes horribly wrong, please take a backup first." + read -p "Type 'RUN' in uppercase to proceed: " runit + if [ "${runit}" = "RUN" ]; then + echo + setPhpSelections + else + echo "Aborting script." + exit + fi +fi