Browse Source

flatten_short_options from miaou-bash

main
pvincent 2 weeks ago
parent
commit
182b0e9df3
  1. 8
      README.md
  2. 60
      lib/functions.bash
  3. 292
      lib/miaou.completion
  4. 25
      recipes/wordpress.recipe
  5. 197
      tools/miaou-create
  6. 31
      tools/miaou-destroy
  7. 2
      tools/miaou-recipe

8
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

60
lib/functions.bash

@ -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
}

292
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"

25
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

197
tools/miaou-create

@ -14,150 +14,149 @@ CONTAINER=
# FUNCTIONS
function usage {
echo "$(basename "$0") <CONTAINER_NAME>"
echo "$(basename "$0") <CONTAINER_NAME>"
}
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

31
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") <CONTAINER_NAME>... [--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

2
tools/miaou-recipe

@ -69,7 +69,7 @@ function show_success {
# MAIN
set -Eue
set -Eueo pipefail
parse_options "$@"
recipe
$QUIET || show_success
Loading…
Cancel
Save