From 4b491ed2d4216b0f39dd1c9c3f86c35d07da357a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gardais=20J=C3=A9r=C3=A9my?= Date: Mon, 15 Nov 2021 11:14:13 +0100 Subject: [PATCH] New script to upgrade an LXC template Test if it's a Proxmox host Call define_vars function Verify if the ct_id is available on the host Add color to important value in DEBUG mode Function to verify current LXC container state New function to start the container Add option to define sleep_delay Function to upgrade the container Keep output only if DEBUG mode Function to stop the container error_message function and exit if CT is running Working script to upgrade an LXC CT (a template) --- proxmox/proxmox.template.debian.upgrade.sh | 351 +++++++++++++++++++++ 1 file changed, 351 insertions(+) create mode 100755 proxmox/proxmox.template.debian.upgrade.sh diff --git a/proxmox/proxmox.template.debian.upgrade.sh b/proxmox/proxmox.template.debian.upgrade.sh new file mode 100755 index 0000000..ef7ec7c --- /dev/null +++ b/proxmox/proxmox.template.debian.upgrade.sh @@ -0,0 +1,351 @@ +#!/bin/sh +# +# This script will try to upgrade an LXC Debian template +# 1. Start the LXC container if available +# 2. Run some script to upgrade the container +# 3. Stop the container + +# This script can be call by a cronjob (eg. daily, weekly,…) + +# Vars {{{ +readonly PROGNAME=$(basename "${0}") +readonly PROGDIR=$(readlink -m $(dirname "${0}")) +readonly ARGS="${*}" +readonly NBARGS="${#}" +[ -z "${DEBUG}" ] && DEBUG=1 +## Export DEBUG for sub-script +export DEBUG + +readonly CT_ID_DEFAULT="199121" +readonly SLEEP_DELAY_DEFAULT="5" + +## Colors +readonly PURPLE='\033[1;35m' +readonly RED='\033[0;31m' +readonly RESET='\033[0m' +readonly COLOR_DEBUG="${PURPLE}" +# }}} +usage() { # {{{ + + cat <<- EOF +usage: $PROGNAME [-d|-h|-i|-s] + +Start and upgrade an LXC container for Debian template + +EXAMPLES : + - Upgrade default LXC container (${CT_ID_DEFAULT}) : + ${PROGNAME} + + - Specify the container ID : + ${PROGNAME} --id 666 + +OPTIONS : + -d,--debug + Enable debug messages. + + -h,--help + Print this help message. + + -i,--id + Choose a different LXC container ID (default ${CT_ID_DEFAULT}). + + -s,--sleep + Set a different delay to test container between each + different state (default: ${SLEEP_DELAY_DEFAULT}). + + EOF + +} +# }}} +debug_message() { # {{{ + + local_message="${1}" + + ## Print message if DEBUG is enable (=0) + [ "${DEBUG}" -eq "0" ] && printf '\e[1;35m%-6b\e[m\n' "DEBUG − ${PROGNAME} : ${local_message}" + + return 0 +} +# }}} +error_message() { # {{{ + + local_error_message="${1}" + local_error_code="${2}" + + ## Print message if DEBUG is enable (=0) + [ "${DEBUG}" -eq "0" ] && printf '%b\n' "ERROR − ${PROGNAME} : ${RED}${local_error_message}${RESET}" + + exit "${local_error_code:=66}" +} +# }}} +define_vars() { # {{{ + + ## If ct_id wasn't defined (argument) {{{ + if [ -z "${ct_id}" ]; then + ## Use default value + readonly ct_id="${CT_ID_DEFAULT}" + fi + ## }}} + + ## If sleep_delay wasn't defined (argument) {{{ + if [ -z "${sleep_delay}" ]; then + ## Use default value + readonly sleep_delay="${SLEEP_DELAY_DEFAULT}" + fi + ## }}} + +} +# }}} +is_proxmox_absent() { # {{{ + + ## By default, Proxmox is absent on an host + return_is_proxmox_absent="0" + + ## Check if the system runs on a PVE kernel + if ! uname --kernel-release -- | grep --quiet -- "pve"; + then + return_is_proxmox_absent="0" + debug_message "is_proxmox_absent − \ +Proxmox is ${RED}absent${COLOR_DEBUG} on this host." + else + return_is_proxmox_absent="1" + debug_message "is_proxmox_absent − \ +Proxmox seems ${RED}present${COLOR_DEBUG} on this host." + fi + + return "${return_is_proxmox_absent}" + +} +# }}} +is_lxc_container_absent() { # {{{ + + local_ct_id="${1}" + + ## By default, the LXC container is absent from the current host + return_is_lxc_container_absent="0" + + ## Check if the system runs on a PVE kernel + if ! pct list -- | grep --quiet "${local_ct_id}"; + then + return_is_lxc_container_absent="0" + debug_message "is_lxc_container_absent − \ +The LXC container (${RED}${local_ct_id}${COLOR_DEBUG}) is ${RED}absent${COLOR_DEBUG} from this host." + else + return_is_lxc_container_absent="1" + debug_message "is_lxc_container_absent − \ +The LXC container (${RED}${local_ct_id}${COLOR_DEBUG}) is ${RED}present${COLOR_DEBUG} on this host." + fi + + return "${return_is_lxc_container_absent}" + +} +# }}} +is_lxc_container_state() { # {{{ + + local_ct_id="${1}" + local_ct_state="${2}" + + ## Compare the status of the LXC container with argument + if pct status "${local_ct_id}" -- | grep --quiet --word-regexp "${local_ct_state}"; + then + return_is_lxc_container_state="0" + debug_message "is_lxc_container_state − \ +The LXC container (${RED}${local_ct_id}${COLOR_DEBUG}) is in ${RED}${local_ct_state}${COLOR_DEBUG} state." + else + return_is_lxc_container_state="1" + debug_message "is_lxc_container_state − \ +The LXC container (${RED}${local_ct_id}${COLOR_DEBUG}) is not in ${RED}${local_ct_state}${COLOR_DEBUG} state." + fi + + return "${return_is_lxc_container_state}" + +} +# }}} +start_lxc_container() { # {{{ + + local_ct_id="${1}" + + ## By default, the container is not running + return_start_lxc_container="1" + + ## Start LXC container state + pct start "${local_ct_id}" || exit 1 + + ## Wait a little for the container to start + sleep "${sleep_delay}" + + ## Verify LXC container status + if is_lxc_container_state "${local_ct_id}" "running"; + then + return_start_lxc_container="0" + debug_message "start_lxc_container − \ +LXC container ${RED}${local_ct_id}${COLOR_DEBUG} is now ${RED}running${COLOR_DEBUG}." + else + return_start_lxc_container="1" + debug_message "start_lxc_container − \ +LXC container ${RED}${local_ct_id}${COLOR_DEBUG} is still ${RED}stopped${COLOR_DEBUG}." + fi + + return "${return_start_lxc_container}" + +} +# }}} +stop_lxc_container() { # {{{ + + local_ct_id="${1}" + + ## By default, the container is running + return_stop_lxc_container="1" + + ## Stop LXC container state + pct stop "${local_ct_id}" || exit 1 + + ## Wait a little for the container to stop + sleep "${sleep_delay}" + + ## Verify LXC container status + if is_lxc_container_state "${local_ct_id}" "stopped"; + then + return_stop_lxc_container="0" + debug_message "stop_lxc_container − \ +LXC container ${RED}${local_ct_id}${COLOR_DEBUG} is now ${RED}stopped${COLOR_DEBUG}." + else + return_stop_lxc_container="1" + debug_message "stop_lxc_container − \ +LXC container ${RED}${local_ct_id}${COLOR_DEBUG} is still ${RED}running${COLOR_DEBUG}." + fi + + return "${return_stop_lxc_container}" + +} +# }}} +upgrade_container() { # {{{ + + local_ct_id="${1}" + + ## Keep output if DEBUG mode is activated + if [ "${DEBUG}" -eq "0" ]; then + pct exec "${local_ct_id:-/dev/null}" -- bash -c "wget https://git.ipr.univ-rennes1.fr/cellinfo/scripts/raw/master/proxmox/proxmox.template.debian.sh --output-document=/tmp/proxmox.template.debian.sh" || exit 2 + pct exec "${local_ct_id:-/dev/null}" -- bash -c "chmod +x /tmp/proxmox.template.debian.sh" || exit 2 + pct exec "${local_ct_id:-/dev/null}" -- bash -c "/tmp/proxmox.template.debian.sh" || exit 2 + else + pct exec "${local_ct_id:-/dev/null}" -- bash -c "wget --quiet https://git.ipr.univ-rennes1.fr/cellinfo/scripts/raw/master/proxmox/proxmox.template.debian.sh --output-document=/tmp/proxmox.template.debian.sh" || exit 2 + pct exec "${local_ct_id:-/dev/null}" -- bash -c "chmod +x /tmp/proxmox.template.debian.sh" || exit 2 + pct exec "${local_ct_id:-/dev/null}" -- bash -c "/tmp/proxmox.template.debian.sh" > /dev/null 2>&1 || exit 2 + fi + +} +# }}} + +main() { # {{{ + + ## If Proxmox is not yet available on this host {{{ + ### Exit + is_proxmox_absent \ + && exit 0 + ## }}} + + ## Define all vars + define_vars + + ## If the LXC container ID is absent from this host {{{ + ### Exit + is_lxc_container_absent "${ct_id}" \ + && exit 0 + ## }}} + + ## If the LXC container ID is already running {{{ + ### Exit with error message + is_lxc_container_state "${ct_id}" "running" \ + && error_message "LXC container (${ct_id}) is already running. \ +Please power it off if you don't have any work in progress." "3" + ## }}} + + ## If the LXC container ID is stopped {{{ + ### Try to start the container + is_lxc_container_state "${ct_id}" "stopped" \ + && start_lxc_container "${ct_id}" + ## }}} + + ## Try to upgrade the container {{{ + ### And re-stop the container + ### Then exit with success the script + upgrade_container "${ct_id}" \ + && stop_lxc_container "${ct_id}" \ + && exit 0 + ## }}} + +} +# }}} + +# Manage arguments # {{{ +# This code can't be in a function due to argument management + +if [ ! "${NBARGS}" -eq "0" ]; then + + manage_arg="0" + + ## If the first argument is not an option + if ! printf -- '%s' "${1}" | grep -q -E -- "^-+"; + then + ## Print help message and exit + printf '%b\n' "${RED}Invalid option: ${1}${RESET}" + printf '%b\n' "---" + usage + + exit 1 + fi + + # Parse all options (start with a "-") one by one + while printf -- '%s' "${1}" | grep -q -E -- "^-+"; do + + case "${1}" in + -d|--debug ) ## debug + DEBUG=0 + ;; + -h|--help ) ## help + usage + ## Exit after help informations + exit 0 + ;; + -i|--id ) ## Use given CT ID + ## Move to the next argument + shift + ## Define ct_id + readonly ct_id="${1}" + ;; + -s|--sleep ) ## Use given sleeping delay + ## Move to the next argument + shift + ## Define sleep_delay + readonly sleep_delay="${1}" + ;; + * ) ## unknow option + printf '%b\n' "${RED}Invalid option: ${1}${RESET}" + printf '%b\n' "---" + usage + exit 1 + ;; + esac + + debug_message "Arguments management − \ +${RED}${1}${COLOR_DEBUG} option managed." + + ## Move to the next argument + shift + manage_arg=$((manage_arg+1)) + + done + + debug_message "Arguments management − \ +${RED}${manage_arg}${COLOR_DEBUG} argument(s) successfully managed." +else + debug_message "Arguments management − \ +No arguments/options to manage." +fi + +# }}} + +main + +exit 255