diff --git a/home/bin/deboco b/home/bin/deboco new file mode 100755 index 0000000..6f7f70a --- /dev/null +++ b/home/bin/deboco @@ -0,0 +1,313 @@ +#!/usr/bin/env bash + +# set -o errexit + + +## Colors +readonly COLOR_RED='\033[0;31m' +readonly COLOR_GREEN='\033[0;32m' +readonly COLOR_YELLOW='\033[0;33m' +readonly COLOR_BLUE='\033[0;34m' +readonly COLOR_PURPLE='\033[1;35m' +readonly COLOR_RESET='\033[0m' + + +RETURNCODE_SUCCESS=0 +RETURNCODE_ERROR=1 + + + +log() +{ + local log_type="$1" # 'debug', 'info', 'warning' or 'error' + local message="$2" + local message_color='' + case "$log_type" in + 'error') + message_color="$COLOR_RED" + ;; + 'warning') + message_color="$COLOR_YELLOW" + ;; + 'info') + message_color="$COLOR_BLUE" + ;; + 'debug') + message_color="$COLOR_PURPLE" + ;; + *) + echo "unexpected log type $log_type" + exit "$RETURNCODE_ERROR" + esac + + printf "%b : %s\n" "${message_color}${log_type}${COLOR_RESET}" "$message" +} + +replace_in_file() +{ + local file_path="$1" + local searched_string="$2" + local replacement_string="$3" + + log 'debug' "replacing ${searched_string} with ${replacement_string} in $file_path" + + + local safe_searched_string=$(echo "$searched_string" | tr '"' '\"' | tr '$' '\$') + local safe_replacement_string=$(echo "$replacement_string" | tr '"' '\"' | tr '$' '\$') + # log 'debug' "safe_searched_string : $safe_searched_string" + + printf 'safe_searched_string: %b\n' "$safe_searched_string" + + grep -q "$safe_searched_string" "$file_path" + if [ $? != "$RETURNCODE_SUCCESS" ] + then + log 'error' "failed to find $safe_searched_string in $file_path" + return $RETURNCODE_ERROR + fi + + # log 'debug' "searching a separator" + + local sep='' + for sep in '/' '|' '@' + do + if $(echo "$safe_searched_string" | grep -q "$sep") || $(echo "$safe_replacement_string" | grep -q "$sep") + then + sep='' + else + # found a suitable separator for use in sed + log 'debug' "found separator: $sep" + break + fi + done + + + if [ "$sep" = '' ] + then + log 'error' "failed to find a sed separator suitable for $safe_searched_string and $safe_replacement_string" + fi + sed -i "s${sep}${safe_searched_string}${sep}${safe_replacement_string}${sep}" "$file_path" + + grep -q "$safe_replacement_string" "$file_path" + if [ $? != "$RETURNCODE_SUCCESS" ] + then + log 'error' "failed to find $safe_replacement_string in $file_path" + return $RETURNCODE_ERROR + fi +} + +controller__get_local_repos_path() +{ + local debops_controller_path="$1" + echo "${debops_controller_path}/ansible.debops.git" +} + +controller__get_reports_path() +{ + local debops_controller_path="$1" + echo "${debops_controller_path}/reports" +} + +controller__get_virtualenv_path() +{ + local debops_controller_path="$1" + echo "${debops_controller_path}/debops.venv" +} + + +controller__get_debops_env_path() +{ + local debops_controller_path="$1" + echo "${debops_controller_path}/debops-environment" +} + +deboco__init() +{ + local debops_controller_path="$1" + log 'info' "creating debobs controller in $debops_controller_path" + if [ "$debops_controller_path" = '' ] + then + log 'error' "wrong debops controller path: $debops_controller_path" + return "$RETURNCODE_ERROR" + fi + if [ -d "$debops_controller_path" ] + then + log 'error' "$debops_controller_path already exists" + return "$RETURNCODE_ERROR" + fi + local local_repos_path=$(controller__get_local_repos_path "$debops_controller_path") + local ipr_debops_url='https://git.ipr.univ-rennes.fr/cellinfo/ansible.debops' + log 'info' "cloning $ipr_debops_url into $local_repos_path" + git clone https://git.ipr.univ-rennes.fr/cellinfo/ansible.debops "$local_repos_path" + + local debops_env_path=$(controller__get_debops_env_path "$debops_controller_path") + + local debops_update_script_path="$local_repos_path/bin/update-debops.sh" + + local from_line='readonly DEBOPS_ENVIRONMENT_FILE="${HOME}/.config/debops/environment"' + # local from_line='readonly DEBOPS_ENVIRONMENT_FILE' + local to_line="readonly DEBOPS_ENVIRONMENT_FILE=${debops_env_path}" + log 'info' "replacing $from_line with $to_line in $debops_update_script_path so that the script uses a debops environment specific to this controller" + replace_in_file "$debops_update_script_path" "$from_line" "$to_line" + if [ $? != "$RETURNCODE_SUCCESS" ] + then + return $RETURNCODE_ERROR + fi + + local bug_3678_is_fixed='false' + if [ "$bug_3678_is_fixed" = 'false' ] + then + log 'warning' "disabling pip update in $debops_update_script_path because of https://bugzilla.ipr.univ-rennes.fr/show_bug.cgi?id=3678" + replace_in_file "$debops_update_script_path" \ + 'python -m pip install --quiet --requirement "${PIP_PKG_LIST}" --upgrade' \ + '# python -m pip install --quiet --requirement "${PIP_PKG_LIST}" --upgrade' + if [ $? != "$RETURNCODE_SUCCESS" ] + then + return $RETURNCODE_ERROR + fi + + replace_in_file "$debops_update_script_path" \ + '|| error_message "Error with pip packages upgrade ' \ + '# || error_message "Error with pip packages upgrade ' + if [ $? != "$RETURNCODE_SUCCESS" ] + then + return $RETURNCODE_ERROR + fi + fi + + local virtual_env_path=$(controller__get_virtualenv_path "$debops_controller_path") + # no need to call update-debops.sh since update-dev.sh does it + DEBOPS_VENV="$virtual_env_path" "$local_repos_path/bin/update-dev.sh" +} + +deboco__update() +{ + local debops_controller_path="$1" + log 'info' "updating debobs controller in $debops_controller_path" + + reports_path="$(controller__get_reports_path "$debops_controller_path")" + mkdir -p "${reports_path}" + report_file_path=${reports_path}/$(date --iso=seconds)-init-${target_host_fqdn} + + local local_repos_path=$(controller__get_local_repos_path "$debops_controller_path") + local virtual_env_path=$(controller__get_virtualenv_path "$debops_controller_path") + + log info "updating repository $local_repos_path" + pushd "$local_repos_path" + git pull | tee --append ${report_file_path} + popd + + log info "updating debops itself in $virtual_env_path" + DEBOPS_VENV="$virtual_env_path" "$local_repos_path/bin/update-dev.sh" | tee --append ${report_file_path} +} + +deboco__configure_machine() +{ + local debops_controller_path="$1" + local target_host_fqdn="$2" # the machine on which we want to install debops bootstrap, eg alambix-108.ipr.univ-rennes.fr + log 'info' "configuring $machine_fqdn using debobs controller $debops_controller_path" + + local error_code=$RETURNCODE_SUCCESS + + reports_path="$(controller__get_reports_path "$debops_controller_path")" + mkdir -p "${reports_path}" + report_file_path=${reports_path}/$(date --iso=seconds)-init-${target_host_fqdn} + echo "installing debops bootstrap on ${target_host_fqdn} (report stored in ${report_file_path})" + + local local_repos_path=$(controller__get_local_repos_path "$debops_controller_path") + local virtual_env_path=$(controller__get_virtualenv_path "$debops_controller_path") + + pushd "$local_repos_path" + source "$virtual_env_path/bin/activate" + ANS_HOST=$(echo ${target_host_fqdn} | sed -E 's/\.univ-rennes[1]?\.fr$//') + log 'debug' "ANS_HOST=${ANS_HOST}" + debops run bootstrap-ldap -l "${ANS_HOST:-/dev/null}" | tee --append ${report_file_path} + if [ $? = "$RETURNCODE_SUCCESS" ] + then + log 'info' "debops bootstrap installed successfully. Now applying the configuration on ${target_host_fqdn}" + debops run site --limit "${ANS_HOST:-/dev/null}" | tee --append ${report_file_path} + if [ $? != "$RETURNCODE_SUCCESS" ] + then + log 'error' 'debops run site failed' + error_code="$RETURNCODE_ERROR" + fi + else + log 'error' 'debops run bootstrap-ldap failed' + error_code="$RETURNCODE_ERROR" + fi + deactivate + popd + return "$error_code" +} + +deboco__update_machine() +{ + local debops_controller_path="$1" + local machine_fqdn="$2" # eg alambix-108.ipr.univ-rennes.fr + log 'info' "updating $machine_fqdn using debobs controller $debops_controller_path" + + local error_code=$RETURNCODE_SUCCESS + + reports_path="$(controller__get_reports_path "$debops_controller_path")" + mkdir -p "${reports_path}" + report_file_path=${reports_path}/$(date --iso=seconds)-init-${target_host_fqdn} + echo "installing debops bootstrap on ${target_host_fqdn} (report stored in ${report_file_path})" + + local local_repos_path=$(controller__get_local_repos_path "$debops_controller_path") + local virtual_env_path=$(controller__get_virtualenv_path "$debops_controller_path") + + pushd "$local_repos_path" + source "$virtual_env_path/bin/activate" + ANS_HOST=$(echo ${target_host_fqdn} | sed -E 's/\.univ-rennes[1]?\.fr$//') + log 'debug' "ANS_HOST=${ANS_HOST}" + debops run site --limit "${ANS_HOST:-/dev/null}" | tee --append ${report_file_path} + if [ $? != "$RETURNCODE_SUCCESS" ] + then + log 'error' 'debops run site failed' + error_code="$RETURNCODE_ERROR" + fi + deactivate + popd + return "$error_code" +} + +deboco_print_usage() +{ + echo "$0 performs a debops controller operation" + echo + echo "usage:" + echo " $0 " + echo + echo "where:" + echo " is one of:" + echo " init " + echo " creates a debops controller in " + echo + echo " update " + echo " updates the debops controller in " + echo + echo " configure-machine " + echo " configures the machine using the debops controller in " + echo + echo " update-machine " + echo " updates the machine using the debops controller in " +} + +deboco() +{ + local command_name="$1" + shift + if type "deboco__${command_name}" >/dev/null 2>&1 + then + "deboco__${command_name}" "$@" + return $? + else + log 'error' "unknown command: ${command_name}" + deboco_print_usage + return "$RETURNCODE_ERROR" + fi +} + + +deboco $@ + +