diff --git a/.forgejo/workflows/prerelease.yml b/.forgejo/workflows/prerelease.yml index 03fb7e6..1869374 100644 --- a/.forgejo/workflows/prerelease.yml +++ b/.forgejo/workflows/prerelease.yml @@ -42,40 +42,27 @@ jobs: goarch: ${{ matrix.goarch }} binari: ${{ matrix.binaries }} secrets: inherit - # Scripts et units systemd publiés comme assets de release : deploy.sh les - # installe depuis la release, plus depuis la branche. Ajouter une entrée ici - # suffit à livrer un nouveau fichier. - upload-assets: + upload-scripts: runs-on: docker needs: [set-release-target] strategy: matrix: - include: - - path: scripts/run-dnsmasq-in-netns.sh - name: run-dnsmasq-in-netns.sh - - path: systemd/agent.service - name: agent.service - - path: systemd/dnsmasq@.service - name: dnsmasq@.service - - path: systemd/metadata@.service - name: metadata@.service + script: + - run-dnsmasq-in-netns.sh steps: - uses: actions/checkout@v3 - name: Move asset run: | mkdir -p "dist" - cp "${{ matrix.path }}" dist/ - - name: Upload asset + cp scripts/${{ matrix.script }} dist/ + - name: Upload script uses: actions/upload-artifact@v3 with: - name: ${{ matrix.name }}-${{ needs.set-release-target.outputs.release_cible }} - path: dist/${{ matrix.name }} + name: ${{ matrix.script }}-${{ needs.set-release-target.outputs.release_cible }} + path: dist/${{ matrix.script }} prerelease: runs-on: docker - # upload-assets est dans les needs : sans lui, le job release peut appeler - # download-artifact avant la fin des uploads et publier une release - # incomplète (scripts et units manquants de façon non déterministe). - needs: [set-release-target, build, upload-assets] + needs: [set-release-target, build] uses: ./.forgejo/workflows/release.yml with: tag: ${{ needs.set-release-target.outputs.release_cible }} diff --git a/scripts/bootstrap_kvm.sh b/scripts/bootstrap_kvm.sh deleted file mode 100755 index e239b7c..0000000 --- a/scripts/bootstrap_kvm.sh +++ /dev/null @@ -1,169 +0,0 @@ -#!/bin/bash -# -# Préparation d'un host au profil kvm : paquets, kernel, réseau de base. -# -# Ce fichier n'est pas exécutable seul : il est *sourcé* par deploy.sh quand -# --bootstrap est demandé, et réutilise ses helpers (run, info, warn, die, -# exec_with_dry_run, FLAGS_TRUE). Conséquences : -# - aucun effet de bord au chargement : uniquement des définitions, -# - aucune variable globale de deploy.sh redéfinie ici (SCRIPT_PATH, TAG, -# BIN_PATH, ASSETS…) : le sourcing les écraserait, -# - pas de `set -e` ni de garde `BASH_SOURCE` en fin de fichier. -# -# Contrat : tout bootstrap_.sh expose bootstrap_host() avec cette -# signature. deploy.sh n'a rien à savoir du contenu du profil. -# -# L'host est stateless (root sur tmpfs) : rien de ce qui suit ne survit à un -# reboot, deploy.sh --bootstrap est rejoué à chaque démarrage. - -KVM_PACKAGES="qemu-system-x86 ovmf dnsmasq ebtables iptables nfs-common jq curl" - -kvm_packages () { - local DRY_RUN="${1}" - local WITH_PACKAGES="${2}" - - [[ ${WITH_PACKAGES} -eq ${FLAGS_TRUE} ]] || { info "paquets : ignorés (--nopackages)"; return 0; } - - info "paquets" - run "${DRY_RUN}" "DEBIAN_FRONTEND=noninteractive apt-get update" - run "${DRY_RUN}" "DEBIAN_FRONTEND=noninteractive apt-get install -y ${KVM_PACKAGES}" - - # Le dnsmasq système prendrait le port 53 en concurrence des instances - # dnsmasq@ lancées par l'agent dans les netns. - run "${DRY_RUN}" "systemctl disable --now dnsmasq.service || true" - run "${DRY_RUN}" "systemctl mask dnsmasq.service" -} - -kvm_kernel () { - local DRY_RUN="${1}" - - info "kernel" - - # modprobe AVANT sysctl : les clés net.bridge.* n'existent pas tant que - # br_netfilter n'est pas chargé, et sysctl --system échouerait. - run "${DRY_RUN}" "modprobe br_netfilter" - run "${DRY_RUN}" "echo br_netfilter > /etc/modules-load.d/two.conf" - - # bridge-nf-call-iptables est requis par le DNAT metadata (169.254.169.254, - # cf. internal/iptables) : sans lui, iptables ne voit pas le trafic bridgé - # des VMs. Contrepartie : tout le trafic inter-VM traverse les tables nat. - run "${DRY_RUN}" "printf 'net.ipv4.ip_forward = 1\nnet.bridge.bridge-nf-call-iptables = 1\n' > /etc/sysctl.d/90-two.conf" - run "${DRY_RUN}" "sysctl --system >/dev/null" -} - -# Bridge vide, up, sans STP. -kvm_ensure_bridge () { - local DRY_RUN="${1}" - local NAME="${2}" - - if ! ip link show dev "${NAME}" >/dev/null 2>&1 - then - run "${DRY_RUN}" "ip link add name '${NAME}' type bridge" - fi - run "${DRY_RUN}" "ip link set dev '${NAME}' type bridge stp_state 0" - run "${DRY_RUN}" "ip link set up dev '${NAME}'" -} - -kvm_network () { - local DRY_RUN="${1}" - local WITH_NETWORK="${2}" - local UPLINK="${3}" - local BRIDGE="${4}" - local PUBLIC_BRIDGE="${5}" - local ROLLBACK_DELAY="${6}" - local MASTER ADDR_JSON IP PREFIX GW MIGRATE MIGRATE_SCRIPT - - [[ ${WITH_NETWORK} -eq ${FLAGS_TRUE} ]] || { info "réseau : ignoré (--nonetwork)"; return 0; } - - info "réseau" - - # Bridge public : créé à vide, réservé pour un usage futur. Aucune adresse, - # aucun esclave, pas référencé dans la config agent. - kvm_ensure_bridge "${DRY_RUN}" "${PUBLIC_BRIDGE}" - - MASTER="" - [[ ${DRY_RUN} -ne ${FLAGS_TRUE} ]] && MASTER=$(ip -j link show dev "${UPLINK}" | jq -r '.[0].master // ""') - if [[ "${MASTER}" == "${BRIDGE}" ]] - then - info " ${UPLINK} déjà esclave de ${BRIDGE} — migration ignorée" - kvm_ensure_bridge "${DRY_RUN}" "${BRIDGE}" - return 0 - fi - - # IP, préfixe et gateway dérivés de l'uplink : rien en dur. Le filtre - # inet/global évite de tomber sur une IPv6 ou une adresse de lien. - if [[ ${DRY_RUN} -eq ${FLAGS_TRUE} ]] - then - IP=""; PREFIX=""; GW="" - else - ADDR_JSON=$(ip -j addr show dev "${UPLINK}") - IP=$(echo "${ADDR_JSON}" | jq -r '[.[0].addr_info[] | select(.family=="inet" and .scope=="global")][0].local // ""') - PREFIX=$(echo "${ADDR_JSON}" | jq -r '[.[0].addr_info[] | select(.family=="inet" and .scope=="global")][0].prefixlen // ""') - GW=$(ip -j route show default dev "${UPLINK}" | jq -r '.[0].gateway // ""') - - [[ -n "${IP}" && -n "${PREFIX}" ]] || die "aucune adresse IPv4 globale sur ${UPLINK}" - [[ -n "${GW}" ]] || die "aucune route par défaut via ${UPLINK}" - fi - - info " ${UPLINK} : ${IP}/${PREFIX} gw ${GW} → ${BRIDGE}" - - # Cette étape coupe le réseau de l'host si elle échoue à mi-parcours, sans - # console de secours. Deux garde-fous : - # - un rollback armé avant d'y toucher : rien n'étant écrit sur disque, un - # reboot ramène la configuration d'origine. Désarmé si le test passe. - # - la séquence tourne sous systemd et non dans la session SSH : une - # coupure de SSH ne l'interrompt plus à mi-chemin. - run "${DRY_RUN}" "systemctl stop two-net-rollback.timer 2>/dev/null || true" - run "${DRY_RUN}" "systemd-run --collect --unit=two-net-rollback --on-active=${ROLLBACK_DELAY} systemctl reboot" - - MIGRATE=$(cat </dev/null 2>&1 || ip link add name '${BRIDGE}' type bridge -ip link set dev '${BRIDGE}' type bridge stp_state 0 -ip link set up dev '${BRIDGE}' -ip link set '${UPLINK}' master '${BRIDGE}' -ip addr add '${IP}/${PREFIX}' dev '${BRIDGE}' -ip route replace default via '${GW}' dev '${BRIDGE}' -ip addr del '${IP}/${PREFIX}' dev '${UPLINK}' -pkill dhclient || true -EOF -) - - if [[ ${DRY_RUN} -eq ${FLAGS_TRUE} ]] - then - echo "# systemd-run --wait --collect --service-type=oneshot --unit=two-net-migrate /bin/bash <<'EOF'" - echo "${MIGRATE}" | sed -e 's/^/# /' - echo "# EOF" - else - MIGRATE_SCRIPT=$(mktemp /run/two-net-migrate.XXXXXX) - printf '%s\n' "${MIGRATE}" > "${MIGRATE_SCRIPT}" - systemctl reset-failed two-net-migrate.service 2>/dev/null || true - systemd-run --wait --collect --service-type=oneshot --unit=two-net-migrate \ - /bin/bash "${MIGRATE_SCRIPT}" \ - || die "migration réseau échouée — rollback armé dans ${ROLLBACK_DELAY}s (reboot)" - rm -f "${MIGRATE_SCRIPT}" - - # Vérification de connectivité avant de désarmer : seul critère qui - # distingue un succès d'un host qu'on vient d'isoler. - ping -c 2 -W 2 "${GW}" >/dev/null 2>&1 \ - || die "gateway ${GW} injoignable après migration — rollback armé dans ${ROLLBACK_DELAY}s (reboot)" - fi - - run "${DRY_RUN}" "systemctl stop two-net-rollback.timer 2>/dev/null || true" - info " rollback désarmé" -} - -# Point d'entrée appelé par deploy.sh --bootstrap. -bootstrap_host () { - local DRY_RUN="${1}" - local WITH_PACKAGES="${2}" - local WITH_NETWORK="${3}" - local UPLINK="${4}" - local BRIDGE="${5}" - local PUBLIC_BRIDGE="${6}" - local ROLLBACK_DELAY="${7}" - - kvm_packages "${DRY_RUN}" "${WITH_PACKAGES}" - kvm_kernel "${DRY_RUN}" - kvm_network "${DRY_RUN}" "${WITH_NETWORK}" "${UPLINK}" "${BRIDGE}" "${PUBLIC_BRIDGE}" "${ROLLBACK_DELAY}" -} diff --git a/scripts/deploy.sh b/scripts/deploy.sh old mode 100755 new mode 100644 index 32b8599..7256505 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -10,12 +10,6 @@ case "${unameOut}" in esac SCRIPT_PATH="scripts/deploy.sh" -UNIT_DIR="/etc/systemd/system" -SCRIPTS_DIR="/opt/two/scripts" - -info () { echo "== ${1}"; } -warn () { echo "!! ${1}" >&2; } -die () { echo "!! ${1}" >&2; exit 1; } exec_with_dry_run () { if [[ ${1} -eq ${FLAGS_TRUE} ]]; then @@ -24,7 +18,7 @@ exec_with_dry_run () { eval "${2}" 2> /tmp/error || \ { echo -e "failed with following error"; - local output; output=$(cat /tmp/error | sed -e "s/^/ error -> /g"); + output=$(cat /tmp/error | sed -e "s/^/ error -> /g"); echo -e "${output}"; return 1; } @@ -32,296 +26,126 @@ exec_with_dry_run () { return 0 } -run () { - exec_with_dry_run "${1}" "${2}" || die "échec : ${2}" -} - check_latest_script () { - local REMOTE_URL="${1}" - local LOCAL_PATH="${2}" - local REMOTE_SUM LOCAL_SUM + REMOTE_URL="${1}" + LOCAL_PATH="${2}" - REMOTE_SUM=$(curl --silent "${REMOTE_URL}" | sha256sum) - LOCAL_SUM=$(cat ${LOCAL_PATH} | sha256sum) + REMOTE=$(curl --silent "${REMOTE_URL}" | sha256sum) + LOCAL=$(cat ${LOCAL_PATH} | sha256sum) - [[ "${REMOTE_SUM}" == "${LOCAL_SUM}" ]] || return 1 + [[ "${REMOTE}" == "${LOCAL}" ]] || return 1 return 0 } +# Liste les units actives correspondant à un motif, une par ligne. +# Sortie vide si aucune ne tourne — ce n'est pas une erreur. list_active_units () { - local PATTERN="${1}" + PATTERN="${1}" systemctl list-units --state=active --no-legend --plain "${PATTERN}" 2>/dev/null \ | awk '{print $1}' || true } -# Units non instanciables du profil (agent.service) : celles qu'on arrête et -# démarre nommément. -profile_main_units () { - local unit - for unit in $(profile_units "${1}") - do - case "${unit}" in - *@.service) continue ;; - *) echo "${unit}" ;; - esac - done -} - -active_instances () { - local unit - for unit in $(profile_units "${1}") - do - case "${unit}" in - *@.service) list_active_units "${unit%@.service}@*" ;; - esac - done -} - stop_services () { - local DRY_RUN="${1}" - local PROFILE="${2}" - local INSTANCES="${3}" - local unit + DRY_RUN="${1}" + METADATA_UNITS="${2}" + DNSMASQ_UNITS="${3}" - for unit in $(profile_main_units "${PROFILE}") - do - run "${DRY_RUN}" "systemctl stop '${unit}'" - done + # L'agent en premier : il pilote les autres units, on ne veut pas qu'il + # observe leur disparition. + exec_with_dry_run "${DRY_RUN}" "systemctl stop agent.service" - for unit in ${INSTANCES} + for unit in ${METADATA_UNITS} ${DNSMASQ_UNITS} do - run "${DRY_RUN}" "systemctl stop '${unit}'" + exec_with_dry_run "${DRY_RUN}" "systemctl stop '${unit}'" done } start_services () { - local DRY_RUN="${1}" - local PROFILE="${2}" - local INSTANCES="${3}" - local unit + DRY_RUN="${1}" + METADATA_UNITS="${2}" + DNSMASQ_UNITS="${3}" - for unit in ${INSTANCES} + # Ordre inverse de l'arrêt : les dépendances d'abord, l'agent en dernier. + for unit in ${DNSMASQ_UNITS} ${METADATA_UNITS} do - exec_with_dry_run "${DRY_RUN}" "systemctl start '${unit}'" \ - || warn "démarrage de ${unit} en échec — poursuite" + exec_with_dry_run "${DRY_RUN}" "systemctl start '${unit}'" done - for unit in $(profile_main_units "${PROFILE}") + exec_with_dry_run "${DRY_RUN}" "systemctl start agent.service" +} + +download_binaries () { + DRY_RUN="${1}" + TAG="${2}" + GIT_SERVER="${3}" + REPO_PATH="${4}" + + #'.[0].assets.[].browser_download_url' + [[ "${TAG}" == "" ]] && TAG=$(curl --silent "${GIT_SERVER}api/v1/repos/${REPO_PATH}releases/?limit=1" | jq -r '.[0].tag_name') + echo "Deploy ${TAG} binaries" + + BIN_PATH="/opt/two/${TAG}/bin/" + LN_PATH="/opt/two/bin/" + + exec_with_dry_run "${DRY_RUN}" "mkdir -p \"${BIN_PATH}\"" + exec_with_dry_run "${DRY_RUN}" "mkdir -p \"${LN_PATH}\"" + + ASSETS=$(curl --silent "${GIT_SERVER}api/v1/repos/${REPO_PATH}releases/tags/${TAG}" | jq -c '.assets[]') + + # Téléchargement d'abord, dans le répertoire versionné : aucun impact sur + # les services en cours, donc aucune raison de les arrêter pendant ce temps. + while read -r tmp do - run "${DRY_RUN}" "systemctl start '${unit}'" - done -} + [[ -z "${tmp}" ]] && continue + BINARY_NAME=$(echo "${tmp}" | jq -r '.name') + BINARY_URL=$(echo "${tmp}" | jq -r '.browser_download_url') + exec_with_dry_run "${DRY_RUN}" "curl --silent '${BINARY_URL}' -o '${BIN_PATH}${BINARY_NAME}'" + exec_with_dry_run "${DRY_RUN}" "chmod +x '${BIN_PATH}${BINARY_NAME}'" + done <<< "${ASSETS}" -profile_units () { - case "${1}" in - kvm) echo "agent.service dnsmasq@.service metadata@.service" ;; - intel) echo "" ;; - *) return 1 ;; - esac -} + # Les units actives sont relevées avant l'arrêt : c'est la seule façon de + # savoir lesquelles redémarrer ensuite (instances dnsmasq@ et metadata@). + METADATA_UNITS=$(list_active_units 'metadata@*') + DNSMASQ_UNITS=$(list_active_units 'dnsmasq@*') -profile_binaries () { - case "${1}" in - kvm) echo "agent metadata run-dnsmasq-in-netns.sh" ;; - intel) echo "" ;; - *) return 1 ;; - esac -} + stop_services "${DRY_RUN}" "${METADATA_UNITS}" "${DNSMASQ_UNITS}" -profile_bootstrap () { - case "${1}" in - kvm) echo "bootstrap_kvm.sh" ;; - intel) echo "" ;; - *) return 1 ;; - esac -} - -run_bootstrap () { - local DRY_RUN="${1}" - local PROFILE="${2}" - local GIT_SERVER="${3}" - local REPO_PATH="${4}" - local BRANCH="${5}" - local NAME BOOTSTRAP_URL - - NAME=$(profile_bootstrap "${PROFILE}") || die "profil inconnu : ${PROFILE}" - [[ -n "${NAME}" ]] || { info "bootstrap : rien à préparer pour le profil ${PROFILE}"; return 0; } - - BOOTSTRAP_URL="${GIT_SERVER}${REPO_PATH}raw/branch/${BRANCH}scripts/${NAME}" - info "bootstrap du profil ${PROFILE} (${SCRIPTS_DIR}/${NAME} ou ${BOOTSTRAP_URL})" - - # shellcheck source=/dev/null - [[ -f "${SCRIPTS_DIR}/${NAME}" ]] && . "${SCRIPTS_DIR}/${NAME}" || eval "$(curl --silent --fail "${BOOTSTRAP_URL}")" - - command -v bootstrap_host >/dev/null 2>&1 \ - || die "bootstrap_host() introuvable — ni ${SCRIPTS_DIR}/${NAME} ni ${BOOTSTRAP_URL} n'ont pu être chargés" - - bootstrap_host "${DRY_RUN}" "${FLAGS_packages}" "${FLAGS_network}" \ - "${FLAGS_uplink}" "${FLAGS_bridge}" "${FLAGS_pub_bridge}" "${FLAGS_rollback}" -} - -resolve_tag () { - local TAG="${1}" - local GIT_SERVER="${2}" - local REPO_PATH="${3}" - - [[ -n "${TAG}" ]] && { echo "${TAG}"; return 0; } - curl --silent "${GIT_SERVER}api/v1/repos/${REPO_PATH}releases/?limit=1" | jq -r '.[0].tag_name' -} - -release_assets () { - local GIT_SERVER="${1}" - local REPO_PATH="${2}" - local RELEASE_TAG="${3}" - - curl --silent "${GIT_SERVER}api/v1/repos/${REPO_PATH}releases/tags/${RELEASE_TAG}" | jq -c '.assets[]' -} - -asset_name () { - echo "${1}" | jq -r --arg s "${2}" 'select(.name == $s or (.name | startswith($s + "_"))) | .name' | head -1 -} - -asset_url () { - echo "${1}" | jq -r --arg n "${2}" 'select(.name == $n) | .browser_download_url' | head -1 -} - -fetch_assets () { - local DRY_RUN="${1}" - local PROFILE="${2}" - local ASSETS="${3}" - local unit short UNIT_URL BIN_URL FULL_NAME - - info "assets de la release ${TAG} pour le profil ${PROFILE}" - - run "${DRY_RUN}" "mkdir -p '${BIN_PATH}'" - run "${DRY_RUN}" "mkdir -p '${UNIT_PATH}'" - run "${DRY_RUN}" "mkdir -p '${LN_PATH}'" - - for unit in $(profile_units "${PROFILE}") + # Bascule des liens symboliques, services arrêtés : c'est la seule fenêtre + # d'indisponibilité réelle. + while read -r tmp do - UNIT_URL=$(asset_url "${ASSETS}" "${unit}") - [[ -n "${UNIT_URL}" ]] || die "unit absente de la release ${TAG} : ${unit}" - run "${DRY_RUN}" "curl --silent '${UNIT_URL}' -o '${UNIT_PATH}${unit}'" - done + [[ -z "${tmp}" ]] && continue + BINARY_NAME=$(echo "${tmp}" | jq -r '.name') + BINARY_SHORT_NAME=$(echo "${BINARY_NAME}" | cut -d_ -f 1) + exec_with_dry_run "${DRY_RUN}" "rm -f '${LN_PATH}${BINARY_SHORT_NAME}'" + exec_with_dry_run "${DRY_RUN}" "ln -s '${BIN_PATH}${BINARY_NAME}' '${LN_PATH}${BINARY_SHORT_NAME}'" + done <<< "${ASSETS}" - for short in $(profile_binaries "${PROFILE}") - do - FULL_NAME=$(asset_name "${ASSETS}" "${short}") - [[ -n "${FULL_NAME}" ]] || die "exécutable absent de la release ${TAG} : ${short}" - BIN_URL=$(asset_url "${ASSETS}" "${FULL_NAME}") - run "${DRY_RUN}" "curl --silent '${BIN_URL}' -o '${BIN_PATH}${FULL_NAME}'" - run "${DRY_RUN}" "chmod +x '${BIN_PATH}${FULL_NAME}'" - done -} - -install_units () { - local DRY_RUN="${1}" - local PROFILE="${2}" - local UNITS unit - - UNITS=$(profile_units "${PROFILE}") || die "profil inconnu : ${PROFILE}" - [[ -n "${UNITS}" ]] || { info "units : aucune pour le profil ${PROFILE}"; return 0; } - - info "units du profil ${PROFILE}" - - for unit in ${UNITS} - do - if [[ ${DRY_RUN} -ne ${FLAGS_TRUE} ]] && [[ ! -f "${UNIT_PATH}${unit}" ]] - then - die "unit absente des assets de la release ${TAG} : ${unit}" - fi - run "${DRY_RUN}" "install -m 0644 '${UNIT_PATH}${unit}' '${UNIT_DIR}/${unit}'" - done - - run "${DRY_RUN}" "systemctl daemon-reload" - - for unit in ${UNITS} - do - case "${unit}" in - *@.service) continue ;; - esac - run "${DRY_RUN}" "systemctl enable '${unit}'" - done -} - -switch_binaries () { - local DRY_RUN="${1}" - local PROFILE="${2}" - local ASSETS="${3}" - local BINARIES INSTANCES short FULL_NAME - - BINARIES=$(profile_binaries "${PROFILE}") - [[ -n "${BINARIES}" ]] || { info "bascule : aucun exécutable pour le profil ${PROFILE}"; return 0; } - - info "bascule des binaires" - - INSTANCES=$(active_instances "${PROFILE}") - - stop_services "${DRY_RUN}" "${PROFILE}" "${INSTANCES}" - - for short in ${BINARIES} - do - FULL_NAME=$(asset_name "${ASSETS}" "${short}") - run "${DRY_RUN}" "rm -f '${LN_PATH}${short}'" - run "${DRY_RUN}" "ln -s '${BIN_PATH}${FULL_NAME}' '${LN_PATH}${short}'" - done - - start_services "${DRY_RUN}" "${PROFILE}" "${INSTANCES}" + start_services "${DRY_RUN}" "${METADATA_UNITS}" "${DNSMASQ_UNITS}" } main () { [[ -f ./libs/shflags ]] && . ./libs/shflags || eval "$(curl --silent https://git.g3e.fr/H6N/tools/raw/branch/main/libs/shflags)" - DEFINE_boolean 'dryrun' false 'Enable dry-run mode' 'd' - DEFINE_boolean 'up_script' true 'Upgrade script' 's' - DEFINE_string 'git_server' 'https://git.g3e.fr/' 'Git Server' 'g' - DEFINE_string 'repo_path' 'syonad/two/' 'Path of repository' 'r' - DEFINE_string 'branch' 'main/' 'Branch name' 'b' - DEFINE_string 'tag' '' 'Tag name' 't' - DEFINE_string 'profile' 'kvm' 'Host profile: kvm' 'p' - DEFINE_boolean 'bootstrap' false 'Prepare the host (packages, kernel, network)' 'i' - DEFINE_boolean 'packages' true 'Install profile packages during --bootstrap' 'k' - DEFINE_boolean 'network' true 'Configure bridges during --bootstrap' 'n' - DEFINE_string 'uplink' 'eno1' 'Physical uplink interface' 'u' - DEFINE_string 'bridge' 'br-000000' 'Main bridge, uplink is enslaved to it' 'B' - DEFINE_string 'pub_bridge' 'br-public' 'Reserved empty bridge' 'P' - DEFINE_integer 'rollback' 120 'Rollback reboot delay in seconds' 'R' + DEFINE_boolean 'dryrun' false 'Enable dry-run mode' 'd' + DEFINE_boolean 'up_script' true 'Upgrade script' 's' + DEFINE_string 'git_server' 'https://git.g3e.fr/' 'Git Server' 'g' + DEFINE_string 'repo_path' 'syonad/two/' 'Path of repository' 'r' + DEFINE_string 'branch' 'main/' 'Branch name' 'b' + DEFINE_string 'tag' '' 'Tag name' 't' FLAGS "$@" || exit $? eval set -- "${FLAGS_ARGV}" - profile_units "${FLAGS_profile}" >/dev/null || die "profil inconnu : ${FLAGS_profile}" + SCRIPT_URL="${FLAGS_git_server}${FLAGS_repo_path}raw/branch/${FLAGS_branch}${SCRIPT_PATH}" + check_latest_script "${SCRIPT_URL}" "${0}" || ( + [[ ${FLAGS_up_script} -eq ${FLAGS_TRUE} ]] && \ + exec_with_dry_run "${FLAGS_dryrun}" "curl --silent '${SCRIPT_URL}' -o '${0}'" + exit 1 + ) - if [[ ${FLAGS_up_script} -eq ${FLAGS_TRUE} ]] - then - local SCRIPT_URL="${FLAGS_git_server}${FLAGS_repo_path}raw/branch/${FLAGS_branch}${SCRIPT_PATH}" - if ! check_latest_script "${SCRIPT_URL}" "${0}" - then - run "${FLAGS_dryrun}" "curl --silent '${SCRIPT_URL}' -o '${0}'" - die "script local différent de la branche ${FLAGS_branch} — mis à jour, relancer" - fi - fi - - [[ ${FLAGS_bootstrap} -eq ${FLAGS_TRUE} ]] && \ - run_bootstrap "${FLAGS_dryrun}" "${FLAGS_profile}" "${FLAGS_git_server}" "${FLAGS_repo_path}" "${FLAGS_branch}" - - local TAG BIN_PATH UNIT_PATH LN_PATH ASSETS - - TAG=$(resolve_tag "${FLAGS_tag}" "${FLAGS_git_server}" "${FLAGS_repo_path}") - [[ -n "${TAG}" && "${TAG}" != "null" ]] || die "impossible de déterminer la release à déployer" - - BIN_PATH="/opt/two/${TAG}/bin/" - UNIT_PATH="/opt/two/${TAG}/units/" - LN_PATH="/opt/two/bin/" - - ASSETS=$(release_assets "${FLAGS_git_server}" "${FLAGS_repo_path}" "${TAG}") - [[ -n "${ASSETS}" ]] || die "aucun asset dans la release ${TAG}" - - fetch_assets "${FLAGS_dryrun}" "${FLAGS_profile}" "${ASSETS}" - - install_units "${FLAGS_dryrun}" "${FLAGS_profile}" - switch_binaries "${FLAGS_dryrun}" "${FLAGS_profile}" "${ASSETS}" + download_binaries "${FLAGS_dryrun}" "${FLAGS_tag}" "${FLAGS_git_server}" "${FLAGS_repo_path}" } [[ "${BASH_SOURCE[0]}" == "${0}" ]] && (main "$@" || exit 1) -[[ "${BASH_SOURCE[0]}" == "" ]] && (main "$@" || exit 1) +[[ "${BASH_SOURCE[0]}" == "" ]] && (main "$@" || exit 1) \ No newline at end of file