diff --git a/README.md b/README.md index f3ebe55..ee622bc 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,15 @@ FEATURES * [x] files or commands from container within * [x] inner command completion from container within * [x] colored completions (link, directories...) by reusing inputrc bindings +* [x] advanced completion for miaou-{start,stop,destroy} according to container state TODO: ----- -* [ ] miaou-exec refactoring needed! +* [ ] install + * [ ] MIAOU_INCUS_DIR +* [ ] Template erb+bash + * [ ] Tempalte erb+ruby-on-shell +* [ ] TOOLBOX +* [ ] RUBY From Host diff --git a/lib/functions.bash b/lib/functions.bash deleted file mode 100644 index 93fb7a4..0000000 --- a/lib/functions.bash +++ /dev/null @@ -1,60 +0,0 @@ -## library of useful functions, usually prefixed with '_' - -## -## ARRAY Functions -## - -function _array_contains { - local -n array=$1 - local element=$2 - [[ " ${array[@]} " =~ " ${element} " ]] && return 0 || return 1 -} - -function _array_intersect { - local -n arr1=$1 - local -n arr2=$2 - local -n result=$3 - - declare -A include - for item in "${arr2[@]}"; do include["$item"]=1; done - - result=() - for item in "${arr1[@]}"; do [[ -n ${include["$item"]} ]] && result+=("$item"); done -} - -function _array_subtract { - local -n arr1=$1 # First array - local -n arr2=$2 # Array to subtract - local -n result=$3 # Output array - - [[ ${#arr2[@]} == 0 ]] && result=("${arr1[@]}") && return - - declare -A exclude - for item in "${arr2[@]}"; do exclude["$item"]=1; done - - result=() - for item in "${arr1[@]}"; do [[ -z ${exclude["$item"]} ]] && result+=("$item"); done -} - -## -## TEXT Functions -## - -function _pluralize_simple { - echo -n "$1 " - [[ $1 -eq 1 || $1 -eq -1 ]] && echo ${2} || echo ${2}s -} - -## -## READ Functions -## - -function _confirm_destructive { - local message="${1:-This cannot be undone!}" - echo "⚠️ WARNING: $message" - read -p "Type YES to confirm: " response - case "$response" in - [yY][eE][sS] | [yY]) return 0 ;; - *) echo "canceled!" && return 1 ;; - esac -} diff --git a/lib/miaou.completion b/lib/miaou.completion index dfc6a34..28a2eb9 100644 --- a/lib/miaou.completion +++ b/lib/miaou.completion @@ -5,128 +5,128 @@ MIAOU_INCUS_DIR=${MIAOU_INCUS_DIR:-/opt/miaou-incus} # FUNCTIONS function _incus_container { - incus list --format csv --columns n type=CONTAINER + incus list --format csv --columns n type=CONTAINER } function _incus_running_container { - incus list --format csv --columns n type=CONTAINER state=RUNNING + incus list --format csv --columns n type=CONTAINER state=RUNNING } function _incus_stopped_container { - incus list --format csv --columns n type=CONTAINER state=STOPPED + incus list --format csv --columns n type=CONTAINER state=STOPPED } function _active_users { - echo root - miaou-exec "$container" -- awk -F: '$3 >= 1000 && $7 !~ /nologin|false/ {print $1}' /etc/passwd + echo root + miaou-exec "$container" -- awk -F: '$3 >= 1000 && $7 !~ /nologin|false/ {print $1}' /etc/passwd } function _miaou_login { - local cur="${COMP_WORDS[COMP_CWORD]}" - local prev="${COMP_WORDS[COMP_CWORD - 1]}" - local container="${COMP_WORDS[1]}" - - case $COMP_CWORD in - 1) - # first argument — containers - COMPREPLY=($(compgen -W "$(_incus_running_container)" -- "$cur")) - ;; - 2) - # second argument - options - COMPREPLY=($(compgen -W "--user -u" -- "$cur")) - ;; - 3) - if [[ $prev =~ ^(--user|-u) ]]; then - # user expected - COMPREPLY=($(compgen -W "$(_active_users "$container")" -- "$cur")) - fi - ;; - esac + local cur="${COMP_WORDS[COMP_CWORD]}" + local prev="${COMP_WORDS[COMP_CWORD - 1]}" + local container="${COMP_WORDS[1]}" + + case $COMP_CWORD in + 1) + # first argument — containers + COMPREPLY=($(compgen -W "$(_incus_running_container)" -- "$cur")) + ;; + 2) + # second argument - options + COMPREPLY=($(compgen -W "--user -u" -- "$cur")) + ;; + 3) + if [[ $prev =~ ^(--user|-u) ]]; then + # user expected + COMPREPLY=($(compgen -W "$(_active_users "$container")" -- "$cur")) + fi + ;; + esac } function _miaou_exec() { - local cur="${COMP_WORDS[COMP_CWORD]}" - local prev="${COMP_WORDS[COMP_CWORD - 1]}" - local container="${COMP_WORDS[1]}" - - # find '--' position - local dashdash_pos=0 - local i - for ((i = 0; i < ${#COMP_WORDS[@]}; i++)); do - [[ ${COMP_WORDS[$i]} == "--" ]] && dashdash_pos=$i - done - - # complete running container names - if ((COMP_CWORD == 1)); then - # first argument — containers - COMPREPLY=($(compgen -W "$(_incus_running_container)" -- "$cur")) - return - fi - - if ((COMP_CWORD == 2)); then - # second argument - options - COMPREPLY=($(compgen -W "--" -- "$cur")) - return - fi - - if ((COMP_CWORD == 3)); then - # command or file from inside container - # echo -e "\nCOMMAND or FILE from CONTAINER\n" >&2 - - COMPREPLY_COMMANDS=($( - incus exec "$container" -- bash << EOF + local cur="${COMP_WORDS[COMP_CWORD]}" + local prev="${COMP_WORDS[COMP_CWORD - 1]}" + local container="${COMP_WORDS[1]}" + + # find '--' position + local dashdash_pos=0 + local i + for ((i = 0; i < ${#COMP_WORDS[@]}; i++)); do + [[ ${COMP_WORDS[$i]} == "--" ]] && dashdash_pos=$i + done + + # complete running container names + if ((COMP_CWORD == 1)); then + # first argument — containers + COMPREPLY=($(compgen -W "$(_incus_running_container)" -- "$cur")) + return + fi + + if ((COMP_CWORD == 2)); then + # second argument - options + COMPREPLY=($(compgen -W "--" -- "$cur")) + return + fi + + if ((COMP_CWORD == 3)); then + # command or file from inside container + # echo -e "\nCOMMAND or FILE from CONTAINER\n" >&2 + + COMPREPLY_COMMANDS=($( + incus exec "$container" -- bash << EOF bind -f /etc/inputrc 2>/dev/null source /etc/bash_completion compgen -c -- "$cur" EOF - )) - COMPREPLY_FILES=($( - incus exec "$container" -- bash << EOF + )) + COMPREPLY_FILES=($( + incus exec "$container" -- bash << EOF bind -f /etc/inputrc 2>/dev/null source /etc/bash_completion compgen -f -- "$cur" EOF - )) + )) - COMPREPLY=(${COMPREPLY_COMMANDS[@]} ${COMPREPLY_FILES[@]}) - if [[ ${#COMPREPLY_FILES[@]} -gt 0 ]]; then - compopt -o filenames - compopt -o nospace - fi + COMPREPLY=(${COMPREPLY_COMMANDS[@]} ${COMPREPLY_FILES[@]}) + if [[ ${#COMPREPLY_FILES[@]} -gt 0 ]]; then + compopt -o filenames + compopt -o nospace + fi - # echo -e "\nCOMPREPLY=( ${COMPREPLY[@]} ) FILES=${#COMPREPLY_FILES[@]}\n" >&2 + # echo -e "\nCOMPREPLY=( ${COMPREPLY[@]} ) FILES=${#COMPREPLY_FILES[@]}\n" >&2 - return - fi + return + fi - if ((COMP_CWORD > 3)); then + if ((COMP_CWORD > 3)); then - command=${COMP_WORDS[dashdash_pos + 1]} - # echo -e "\nCOMMAND:$command from CONTAINER\n" >&2 + command=${COMP_WORDS[dashdash_pos + 1]} + # echo -e "\nCOMMAND:$command from CONTAINER\n" >&2 - completion_command=$( - incus exec "$container" -- bash << EOF + completion_command=$( + incus exec "$container" -- bash << EOF source /etc/bash_completion [[ -f /usr/share/bash-completion/completions/$command ]] && source /usr/share/bash-completion/completions/$command complete -p "$command" 2>/dev/null | grep -oP '(?<=-F )\S+' EOF - ) - if [[ -n $completion_command ]]; then - # Remove first $dashdash_pos items - COMP_WORDS=("${COMP_WORDS[@]:dashdash_pos+1}") - COMP_CWORD=$((COMP_CWORD - dashdash_pos - 1)) - COMP_LINE="${COMP_WORDS[@]}" - COMP_POINT=${#COMP_LINE} - COMP_POINT=$((COMP_POINT + 1)) - - # _comp_debug completion_command $completion_command - # _comp_debug prev $prev - # _comp_debug cur $cur - # _comp_debug COMP_WORDS "(${COMP_WORDS[@]})" - # _comp_debug COMP_CWORD $COMP_CWORDS - - COMPREPLY=($( - incus exec "$container" -- bash << EOF + ) + if [[ -n $completion_command ]]; then + # Remove first $dashdash_pos items + COMP_WORDS=("${COMP_WORDS[@]:dashdash_pos+1}") + COMP_CWORD=$((COMP_CWORD - dashdash_pos - 1)) + COMP_LINE="${COMP_WORDS[@]}" + COMP_POINT=${#COMP_LINE} + COMP_POINT=$((COMP_POINT + 1)) + + # _comp_debug completion_command $completion_command + # _comp_debug prev $prev + # _comp_debug cur $cur + # _comp_debug COMP_WORDS "(${COMP_WORDS[@]})" + # _comp_debug COMP_CWORD $COMP_CWORDS + + COMPREPLY=($( + incus exec "$container" -- bash << EOF bind -f /etc/inputrc 2>/dev/null source /etc/bash_completion for i in /etc/bash_completion.d/*; do source \$i; done @@ -142,84 +142,100 @@ EOF $completion_command 2>/dev/null echo \${COMPREPLY[@]} EOF - )) - if [[ $completion_command == '_comp_complete_longopt' ]]; then - compopt -o filenames - compopt -o nospace - fi - - else - # _comp_debug "NO completion_command JUST plain files and dirs" - - compopt -o filenames - compopt -o nospace - COMPREPLY=($( - incus exec "$container" -- bash << EOF + )) + if [[ $completion_command == '_comp_complete_longopt' ]]; then + compopt -o filenames + compopt -o nospace + fi + + else + # _comp_debug "NO completion_command JUST plain files and dirs" + + compopt -o filenames + compopt -o nospace + COMPREPLY=($( + incus exec "$container" -- bash << EOF bind -f /etc/inputrc 2>/dev/null source /etc/bash_completion compgen -f "$cur" 2>/dev/null EOF - )) - fi - fi + )) + fi + fi } function _miaou_ls { - local cur="${COMP_WORDS[COMP_CWORD]}" - if [[ $cur =~ ^- ]]; then - # options - COMPREPLY=(--vm) - elif ((COMP_CWORD == 1)); then - # containers - COMPREPLY=(--vm $(compgen -W "$(_incus_container)" -- "$cur")) - fi + local cur="${COMP_WORDS[COMP_CWORD]}" + if [[ $cur =~ ^- ]]; then + # options + COMPREPLY=(--vm) + elif ((COMP_CWORD == 1)); then + # containers + COMPREPLY=(--vm $(compgen -W "$(_incus_container)" -- "$cur")) + fi } function _comp_debug { - echo -e "\nDEBUG: $@" >&2 + echo -e "\nDEBUG: $@" >&2 } function _miaou_start { - local cur="${COMP_WORDS[COMP_CWORD]}" + local cur="${COMP_WORDS[COMP_CWORD]}" - # containers... - local suggestions=($(compgen -W "$(_incus_stopped_container)" -- "$cur")) - local previous_containers=("${COMP_WORDS[@]:1:${#COMP_WORDS[@]}-2}") # drop first and last items - _array_subtract suggestions previous_containers COMPREPLY + # containers... + local suggestions=($(compgen -W "$(_incus_stopped_container)" -- "$cur")) + local previous_containers=("${COMP_WORDS[@]:1:${#COMP_WORDS[@]}-2}") # drop first and last items + _array_subtract suggestions previous_containers COMPREPLY } function _miaou_stop { - local cur="${COMP_WORDS[COMP_CWORD]}" + local cur="${COMP_WORDS[COMP_CWORD]}" - # containers... - local suggestions=($(compgen -W "$(_incus_running_container)" -- "$cur")) - local previous_containers=("${COMP_WORDS[@]:1:${#COMP_WORDS[@]}-2}") # drop first and last items - _array_subtract suggestions previous_containers COMPREPLY + # containers... + local suggestions=($(compgen -W "$(_incus_running_container)" -- "$cur")) + local previous_containers=("${COMP_WORDS[@]:1:${#COMP_WORDS[@]}-2}") # drop first and last items + _array_subtract suggestions previous_containers COMPREPLY } function _miaou_destroy { - local cur suggestions previous_words - - cur="${COMP_WORDS[COMP_CWORD]}" - if [[ $cur =~ ^- ]]; then - suggestions=(--yes --force) - else - _array_contains COMP_WORDS --force && suggestions=($(_incus_container)) || suggestions=($(_incus_stopped_container)) - [[ ${#suggestions[@]} == 0 ]] && suggestions=(--force) - fi - suggestions=($(compgen -W "${suggestions[*]}" -- "$cur")) - previous_words=("${COMP_WORDS[@]:1:${#COMP_WORDS[@]}-2}") # drop first and last items - _array_subtract suggestions previous_words COMPREPLY + local cur suggestions previous_words + + cur="${COMP_WORDS[COMP_CWORD]}" + if [[ $cur =~ ^- ]]; then + suggestions=(--yes --force) + else + _array_contains COMP_WORDS --force && suggestions=($(_incus_container)) || suggestions=($(_incus_stopped_container)) + [[ ${#suggestions[@]} == 0 ]] && suggestions=(--force) + fi + suggestions=($(compgen -W "${suggestions[*]}" -- "$cur")) + previous_words=("${COMP_WORDS[@]:1:${#COMP_WORDS[@]}-2}") # drop first and last items + _array_subtract suggestions previous_words COMPREPLY +} + +function _miaou_recipe { + local cur="${COMP_WORDS[COMP_CWORD]}" + + # containers... + if [[ $COMP_CWORD == 1 ]]; then + COMPREPLY=($(compgen -W "$(_incus_running_container)" -- "$cur")) + elif [[ $COMP_CWORD == 2 ]]; then + COMPREPLY=($(compgen -f -- "$cur")) + compopt -o filenames + elif [[ $COMP_CWORD == 3 ]]; then + COMPREPLY=($(compgen -W "--" -- "$cur")) + fi } # MAIN -# shellcheck source=/opt/miaou-incus/lib/functions.bash -source "$MIAOU_INCUS_DIR/lib/functions.bash" +# shellcheck source=/opt/miaou-bash/lib/functions.bash +source "$MIAOU_BASH_DIR/lib/functions.bash" + complete -F _miaou_login "miaou-login" complete -F _miaou_exec "miaou-exec" complete -F _miaou_ls "miaou-ls" complete -F _miaou_start "miaou-start" complete -F _miaou_stop "miaou-stop" complete -F _miaou_destroy "miaou-destroy" +complete -F _miaou_recipe "miaou-recipe" diff --git a/recipes/wordpress.recipe b/recipes/wordpress.recipe index 943775b..0caf491 100644 --- a/recipes/wordpress.recipe +++ b/recipes/wordpress.recipe @@ -2,10 +2,9 @@ # CONSTANTS +UPLOAD_MAX_SIZE=${UPLOAD_MAX_SIZE-256M} #TODO: allow passing environment variables from `miaou-recipe` FORCE=false -PHP_VERSION=8.4 -UPLOAD_MAX_SIZE=2G -WP_NAME='' +WP_NAME= # FUNCTIONS @@ -23,18 +22,21 @@ function parse_options { --force | -f) FORCE=true ;; + -*) + echo >&2 "ERROR: unknown option <$1>" && usage && exit 3 + ;; *) if [[ -z $WP_NAME ]]; then WP_NAME=$1 else - echo >&2 "Unknown option: $1" && usage && exit 2 + echo >&2 "ERROR: unknown argument <$1>" && usage && exit 2 fi ;; esac shift 1 # Move to the next argument done - [[ -z $WP_NAME ]] && usage && exit 1 || true + [[ -z $WP_NAME ]] && echo >&2 "ERROR: expecting mandatory argument {WP_NAME}" && usage && exit 2 || true } function install_mariadb { @@ -47,11 +49,15 @@ function install_mariadb { } function install_php { - local php_service="php$PHP_VERSION-fpm" + local php_version=php --version | head -n1 | cut -d' ' -f2 | grep -o '^[[:digit:]]*\.[[:digit:]]*' + local php_service="php$php_version-fpm" + if $FORCE || ! systemctl is-active "$php_service" --quiet; then apt-get install -y php-fpm php-mysql php-curl php-dom php-imagick php-mbstring php-zip php-gd php-intl - sed -i "s/^post_max_size = 8M/post_max_size = $UPLOAD_MAX_SIZE/g" /etc/php/8.4/fpm/php.ini - sed -i "s/^upload_max_filesize = 2M/upload_max_filesize = $UPLOAD_MAX_SIZE/g" /etc/php/8.4/fpm/php.ini + php_version=php --version | head -n1 | cut -d' ' -f2 | grep -o '^[[:digit:]]*\.[[:digit:]]*' + + sed -i "s/^post_max_size = 8M/post_max_size = $UPLOAD_MAX_SIZE/g" /etc/php/$php_version/fpm/php.ini + sed -i "s/^upload_max_filesize = 2M/upload_max_filesize = $UPLOAD_MAX_SIZE/g" /etc/php/$php_version/fpm/php.ini systemctl enable "$php_service" --now echo "$php_service installed successfully!" else @@ -112,7 +118,10 @@ EOF # MAIN +set -Eue -o pipefail parse_options "$@" +exit 0 + install_mariadb install_php # install_wordpress diff --git a/tools/miaou-create b/tools/miaou-create index 9c51e1b..48e3bfc 100755 --- a/tools/miaou-create +++ b/tools/miaou-create @@ -14,150 +14,149 @@ CONTAINER= # FUNCTIONS function usage { - echo "$(basename "$0") " + echo "$(basename "$0") " } function humanize_ago { - local seconds=$(($(date +%s) - $(date -d "$1" +%s))) - - local days=$((seconds / 86400)) - local hours=$(((seconds % 86400) / 3600)) - local minutes=$(((seconds % 3600) / 60)) - - if ((days > 365)); then - echo "$((days / 365)) year(s) ago" - elif ((days > 30)); then - echo "$((days / 30)) month(s) ago" - elif ((days > 0)); then - echo "$days day(s) ago" - elif ((hours > 0)); then - echo "$hours hour(s) ago" - elif ((minutes > 0)); then - echo "$minutes minute(s) ago" - else - echo "$seconds second(s) ago" - fi + local seconds=$(($(date +%s) - $(date -d "$1" +%s))) + + local days=$((seconds / 86400)) + local hours=$(((seconds % 86400) / 3600)) + local minutes=$(((seconds % 3600) / 60)) + + if ((days > 365)); then + echo "$((days / 365)) year(s) ago" + elif ((days > 30)); then + echo "$((days / 30)) month(s) ago" + elif ((days > 0)); then + echo "$days day(s) ago" + elif ((hours > 0)); then + echo "$hours hour(s) ago" + elif ((minutes > 0)); then + echo "$minutes minute(s) ago" + else + echo "$seconds second(s) ago" + fi } function parse_options { - while [[ $# -gt 0 ]]; do - case "$1" in - --help | -h) - usage && exit 0 - ;; - *) - if [[ -z $CONTAINER ]]; then - CONTAINER=$1 - else - echo >&2 "Unknown option: $1" && usage && exit 2 - fi - ;; - esac - - shift 1 # Move to the next argument - done - [[ -n $CONTAINER ]] || (usage && exit 1) + while [[ $# -gt 0 ]]; do + case "$1" in + --help | -h) + usage && exit 0 + ;; + *) + if [[ -z $CONTAINER ]]; then + CONTAINER=$1 + else + echo >&2 "Unknown option: $1" && usage && exit 2 + fi + ;; + esac + + shift 1 # Move to the next argument + done + [[ -n $CONTAINER ]] || (usage && exit 1) } function mount_miaou_bash { - printenv MIAOU_BASH_DIR > /dev/null || (echo >&2 "Warn: environment variable MIAOU_BASH_DIR is missing!" && return) + printenv MIAOU_BASH_DIR > /dev/null || (echo >&2 "Warn: environment variable MIAOU_BASH_DIR is missing!" && return) - local target="$1" - local optional_project=${2:-} - [[ -n $optional_project ]] && optional_project="--project $optional_project" + local target="$1" + local optional_project=${2:-} + [[ -n $optional_project ]] && optional_project="--project $optional_project" - incus $optional_project config device add $target MIAOU-BASH disk source=$MIAOU_BASH_DIR path=/opt/miaou-bash readonly=true | grep -q 'Device MIAOU-BASH added' - incus $optional_project config set $target environment.PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/miaou-bash/tools + incus $optional_project config device add $target MIAOU-BASH disk source=$MIAOU_BASH_DIR path=/opt/miaou-bash readonly=true | grep -q 'Device MIAOU-BASH added' + # incus $optional_project config set $target environment.PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/miaou-bash/tools } function build_sandbox_project { - if ! incus project show $PROJECT_SANDBOX > /dev/null; then - incus project create $PROJECT_SANDBOX - incus --project $PROJECT_SANDBOX profile device add default root disk path=/ pool=default - incus --project $PROJECT_SANDBOX profile device add default eth0 nic name=eth0 network=incusbr0 - fi + if ! incus project show $PROJECT_SANDBOX > /dev/null; then + incus project create $PROJECT_SANDBOX + incus --project $PROJECT_SANDBOX profile device add default root disk path=/ pool=default + incus --project $PROJECT_SANDBOX profile device add default eth0 nic name=eth0 network=incusbr0 + fi } function refresh_template { - if incus --project "$PROJECT_SANDBOX" info "$TEMPLATE_SANDBOX" | grep '^Status: STOPPED'; then - incus --project "$PROJECT_SANDBOX" start "$TEMPLATE_SANDBOX" - fi - incus --project "$PROJECT_SANDBOX" exec "$TEMPLATE_SANDBOX" -- bash << EOF + if incus --project "$PROJECT_SANDBOX" info "$TEMPLATE_SANDBOX" | grep '^Status: STOPPED'; then + incus --project "$PROJECT_SANDBOX" start "$TEMPLATE_SANDBOX" + fi + incus --project "$PROJECT_SANDBOX" exec "$TEMPLATE_SANDBOX" -- bash << EOF apt-get update apt-get dist-upgrade -y apt-get install -y curl /opt/miaou-bash/install.sh EOF - incus --project "$PROJECT_SANDBOX" stop "$TEMPLATE_SANDBOX" - local image_date=$(incus --project "$PROJECT_SANDBOX" list "$TEMPLATE_SANDBOX" -f compact,noheader -cl) - echo "template refreshed at: $image_date" + incus --project "$PROJECT_SANDBOX" stop "$TEMPLATE_SANDBOX" + local image_date=$(incus --project "$PROJECT_SANDBOX" list "$TEMPLATE_SANDBOX" -f compact,noheader -cl) + echo "template refreshed at: $image_date" } function build_template_from_scratch { - build_sandbox_project - echo "building template from scratch..." - incus --project "$PROJECT_SANDBOX" launch "$MIAOU_IMAGE" "$TEMPLATE_SANDBOX" - incus --project "$PROJECT_SANDBOX" file delete "$TEMPLATE_SANDBOX"/etc/apt/sources.list - incus --project "$PROJECT_SANDBOX" file push --uid 0 --gid 0 --mode 644 --create-dirs /etc/apt/sources.list.d/debian.sources "$TEMPLATE_SANDBOX"/etc/apt/sources.list.d/debian.sources - cat << EOF | incus --project "$PROJECT_SANDBOX" file push --uid 0 --gid 0 --mode 644 --create-dirs - "$TEMPLATE_SANDBOX"/etc/systemd/resolved.conf.d/10-disable-ipv4-listener.conf + build_sandbox_project + echo "building template from scratch..." + incus --project "$PROJECT_SANDBOX" launch "$MIAOU_IMAGE" "$TEMPLATE_SANDBOX" + incus --project "$PROJECT_SANDBOX" file delete "$TEMPLATE_SANDBOX"/etc/apt/sources.list + incus --project "$PROJECT_SANDBOX" file push --uid 0 --gid 0 --mode 644 --create-dirs /etc/apt/sources.list.d/debian.sources "$TEMPLATE_SANDBOX"/etc/apt/sources.list.d/debian.sources + cat << EOF | incus --project "$PROJECT_SANDBOX" file push --uid 0 --gid 0 --mode 644 --create-dirs - "$TEMPLATE_SANDBOX"/etc/systemd/resolved.conf.d/10-disable-ipv4-listener.conf [Resolve] LLMNR=no DNSStubListener=no EOF - mount_miaou_bash "$TEMPLATE_SANDBOX" "$PROJECT_SANDBOX" - refresh_template - echo "template:"$TEMPLATE_SANDBOX" from project:$PROJECT_SANDBOX built successfully!" + mount_miaou_bash "$TEMPLATE_SANDBOX" "$PROJECT_SANDBOX" + refresh_template + echo "template:"$TEMPLATE_SANDBOX" from project:$PROJECT_SANDBOX built successfully!" } function prepare_template_for_quick_creation { - local image_date=$(incus list "$TEMPLATE_SANDBOX" -f compact,noheader -cl --project "$PROJECT_SANDBOX") - if [[ -z $image_date ]]; then - build_template_from_scratch - else - local true_date=$(date -d "$image_date" +%s) - local expiration_date=$(date -d "$TEMPLATE_REFRESH_DELAY ago" +%s) - if ((true_date < expiration_date)); then - echo "template exists $(humanize_ago "$image_date"), needs a refresh..." - refresh_template - else - : - # echo "template already exists $(humanize_ago "$image_date")!" - fi - fi + local image_date=$(incus list "$TEMPLATE_SANDBOX" -f compact,noheader -cl --project "$PROJECT_SANDBOX") + if [[ -z $image_date ]]; then + build_template_from_scratch + else + local true_date=$(date -d "$image_date" +%s) + local expiration_date=$(date -d "$TEMPLATE_REFRESH_DELAY ago" +%s) + if ((true_date < expiration_date)); then + echo "template exists $(humanize_ago "$image_date"), needs a refresh..." + refresh_template + else + : + # echo "template already exists $(humanize_ago "$image_date")!" + fi + fi } function customize_host { - local target="$1" - local domain=$(incus network get incusbr0 dns.domain) - domain=${domain:-incus} - cat << EOF | incus file push --uid 0 --gid 0 --mode 644 --create-dirs - $target/etc/hosts -127.0.1.1 $target.$domain $target -127.0.0.1 localhost -EOF + local target domain + target="$1" + domain=$(incus network get incusbr0 dns.domain) + domain=${domain:-incus} + + printf "127.0.1.1\t$target.$domain $target\n127.0.0.1\tlocalhost\n" | incus file push - $target/etc/hosts + echo "$target.$domain" | incus file push - $target/etc/hostname } function assert_not_sandboxing { - [[ $(incus project get-current) == "$PROJECT_SANDBOX" ]] \ - && echo ERROR: actual sandboxing project, please switch back to your 'default' project >&2 \ - && exit 30 \ - || true + [[ $(incus project get-current) == "$PROJECT_SANDBOX" ]] \ + && echo ERROR: actual sandboxing project, please switch back to your 'default' project >&2 \ + && exit 30 \ + || true } function create { - if incus --project "$PROJECT_SANDBOX" info "$TEMPLATE_SANDBOX" | grep '^Status: RUNNING'; then - incus --project "$PROJECT_SANDBOX" stop "$TEMPLATE_SANDBOX" - fi - incus --project "$PROJECT_SANDBOX" copy --instance-only --refresh "$TEMPLATE_SANDBOX" "$CONTAINER" --target-project $(incus project get-current) - incus file delete "$CONTAINER/etc/machine-id" - incus config unset "$CONTAINER" volatile.eth0.hwaddr - incus start "$CONTAINER" - customize_host "$CONTAINER" + if incus --project "$PROJECT_SANDBOX" info "$TEMPLATE_SANDBOX" | grep '^Status: RUNNING'; then + incus --project "$PROJECT_SANDBOX" stop "$TEMPLATE_SANDBOX" + fi + incus --project "$PROJECT_SANDBOX" copy --instance-only "$TEMPLATE_SANDBOX" "$CONTAINER" --target-project $(incus project get-current) + incus file delete "$CONTAINER/etc/machine-id" + incus config unset "$CONTAINER" volatile.eth0.hwaddr + incus start "$CONTAINER" + customize_host "$CONTAINER" } # MAIN -set -Eue -set -o pipefail +set -Eueo pipefail parse_options "$@" assert_not_sandboxing diff --git a/tools/miaou-destroy b/tools/miaou-destroy index e6174b4..11f03fd 100755 --- a/tools/miaou-destroy +++ b/tools/miaou-destroy @@ -2,7 +2,7 @@ # CONSTANTS -MIAOU_INCUS_DIR=${MIAOU_INCUS_DIR:-/opt/miaou-incus} +ARGS=("$@") BASEDIR=$(dirname "$0") CONTAINERS=() YES=false @@ -14,21 +14,6 @@ function usage { echo "$(basename "$0") ... [--yes|-y] [--force|-f]" } -function flatten_short_options { - local -n result=$1 - shift - result=() - for word in "$@"; do - [[ $word == -- ]] && break - if [[ $word =~ ^-[a-z][a-z] ]]; then - word=${word:1} - for ((i = 0; i < ${#word}; i++)); do result+=("-${word:i:1}"); done - else - result+=("$word") - fi - done -} - function parse_options { while [[ $# -gt 0 ]]; do case "$1" in @@ -48,8 +33,7 @@ function parse_options { CONTAINERS+=("$1") ;; esac - - shift 1 # Move to the next argument + shift done [[ ${#CONTAINERS[@]} == 0 ]] && usage && exit 1 || true @@ -72,11 +56,12 @@ function destroy { # MAIN -set -Eue -o pipefail +set -Eueo pipefail + +# shellcheck source=/opt/miaou-bash/lib/functions.bash +source "$MIAOU_BASH_DIR/lib/functions.bash" -# shellcheck source=/opt/miaou-incus/lib/functions.bash -source "$MIAOU_INCUS_DIR/lib/functions.bash" +_flatten_short_options ARGS +parse_options "${ARGS[@]}" -flatten_short_options flat "$@" -parse_options "${flat[@]}" destroy diff --git a/tools/miaou-recipe b/tools/miaou-recipe index 256208f..67b57b3 100755 --- a/tools/miaou-recipe +++ b/tools/miaou-recipe @@ -69,7 +69,7 @@ function show_success { # MAIN -set -Eue +set -Eueo pipefail parse_options "$@" recipe $QUIET || show_success