From a80d7d7ba6dfbb71d1acf6763b30f175eaa02057 Mon Sep 17 00:00:00 2001 From: pvincent Date: Thu, 2 Apr 2026 16:29:44 +0400 Subject: [PATCH] miaou-create template sandbox --- .vscode/settings.json | 9 ++- README.md | 3 +- tools/miaou-create | 166 +++++++++++++++++++++++++++++------------- 3 files changed, 126 insertions(+), 52 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 00b322b..8b88530 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -23,6 +23,11 @@ "**/*.txt", "**/*.mdown", "**/*.md", - "**/*.container" - ] + "**/*.container", + "**/miaou-*", + ], + "todohighlight.enableDiagnostics": true, + "todohighlight.toggleURI": true, + "bashIde.enableSourceErrorDiagnostics": true, + "bashIde.includeAllWorkspaceSymbols": false } \ No newline at end of file diff --git a/README.md b/README.md index 65fa41a..e2bafb1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ miaou-incus =========== -incus with lots of convention \ No newline at end of file +incus customized along opinionated conventions plus additional tools + diff --git a/tools/miaou-create b/tools/miaou-create index af605a9..7f93824 100755 --- a/tools/miaou-create +++ b/tools/miaou-create @@ -3,84 +3,152 @@ # CONSTANTS BASEDIR=$(dirname "$0") -DEBIAN='images:debian/13' +MIAOU_IMAGE=images:debian/13 APT_ARCHIVES=/var/cache/apt/archives -CONTAINER='' +PROJECT_SANDBOX=sandbox +TEMPLATE_SANDBOX=miaou-debian13-template +TEMPLATE_REFRESH_DELAY="7 days" + +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 } 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 create { + incus --project "$PROJECT_SANDBOX" copy "$TEMPLATE_SANDBOX" "$CONTAINER" --target-project $(incus project get-current) + incus file delete "$CONTAINER/etc/machine-id" + incus start "$CONTAINER" + customize_host "$CONTAINER" +} +function mount_miaou_bash { + [[ -v MIAOU_BASH_DIR ]] && echo >&2 "Warn: variable MIAOU_BASH_DIR missing!" && return + 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 } -# cold changes -function before_start { - if [[ -v MIAOU_BASH_DIR ]]; then - incus config device add $CONTAINER MIAOU-BASH disk source=$MIAOU_BASH_DIR path=/opt/miaou-bash readonly=true | grep -q 'Device MIAOU-BASH added' - incus config set $CONTAINER environment.PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/miaou-bash/tools - else - echo >&2 "Warn: variable MIAOU_BASH_DIR missing!" - fi +function build_sandbox_project { + incus project show $PROJECT_SANDBOX > /dev/null || incus project create $PROJECT_SANDBOX +} - incus config device add $CONTAINER MIAOU-HOSTED-ARCHIVES disk source=$APT_ARCHIVES path=/var/cache/apt-hosted-archives readonly=true | grep -q 'Device MIAOU-HOSTED-ARCHIVES added' - incus file delete $CONTAINER/etc/apt/sources.list - incus file push --uid 0 --gid 0 --mode 644 --create-dirs /etc/apt/sources.list.d/debian.sources $CONTAINER/etc/apt/sources.list.d/debian.sources +function refresh_template { + incus --project "$PROJECT_SANDBOX" start "$TEMPLATE_SANDBOX" + 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" +} - cat << EOF | incus file push --uid 0 --gid 0 --mode 644 --create-dirs - $CONTAINER/etc/systemd/resolved.conf.d/10-disable-ipv4-listener.conf +function build_template_from_scratch { + build_sandbox_project + echo "building image from scratch..." + 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" + incus --project "$PROJECT_SANDBOX" create "$MIAOU_IMAGE" "$TEMPLATE_SANDBOX" + refresh_template + echo "image:"$TEMPLATE_SANDBOX" from project:$PROJECT_SANDBOX built successfully!" } -# hot changes -function after_start { - # FIXME: should be done in some other way - incus exec "$CONTAINER" -- apt-get update - incus exec "$CONTAINER" -- apt-get install -y curl - - incus exec "$CONTAINER" -- /opt/miaou-bash/install.sh +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 domain=$(incus network get incusbr0 dns.domain) - domain=${domain:-incus} - cat << EOF | incus file push --uid 0 --gid 0 --mode 644 --create-dirs - $CONTAINER/etc/hosts -127.0.1.1 $CONTAINER.$domain $CONTAINER +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 } -function create { - incus create $DEBIAN $CONTAINER - before_start - incus start $CONTAINER - after_start +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 } # MAIN set -Eue -parse_options $* +parse_options "$@" + +assert_not_sandboxing +prepare_template_for_quick_creation create echo Success