diff --git a/panelctl.sh b/panelctl.sh index 0369cc4..72f2264 100644 --- a/panelctl.sh +++ b/panelctl.sh @@ -17,7 +17,6 @@ PANEL_GROUP="${PANEL_GROUP:-panelroutes}" # as KEY=VALUE words (passed to compose via env(1), never sourced). CURRENT_APP="" COMPOSE_ARGS=() -ORPHAN_ARGS=() APP_ENV_ARGS=() APP_ENV_KEYS=() @@ -199,7 +198,6 @@ load_app() { local manifest manifest="$(app_manifest "${name}")" [[ -f "${manifest}" ]] || fail "app '${name}' does not exist" - unset APP_COMPOSE_PROJECT # shellcheck disable=SC1090 source "${manifest}" @@ -237,20 +235,10 @@ app_ports_override() { echo "${STACKS_DIR}/$1/.panel-ports.yaml" } -# The compose project the app's containers belong to: the app's name, unless -# the manifest keeps an older one (see adopt_legacy_project). -compose_project() { - echo "${APP_COMPOSE_PROJECT:-${CURRENT_APP}}" -} - # The app's compose file followed by whichever generated overrides exist. refresh_compose_args() { local override - COMPOSE_ARGS=(-p "$(compose_project)" -f "${APP_COMPOSE_FILE}") - # Other git apps may share a kept legacy project; their containers would - # look like orphans. - ORPHAN_ARGS=(--remove-orphans) - [[ "$(compose_project)" == "${CURRENT_APP}" ]] || ORPHAN_ARGS=() + COMPOSE_ARGS=(-f "${APP_COMPOSE_FILE}") for override in "$(app_ports_override "${CURRENT_APP}")" "$(app_env_override "${CURRENT_APP}")"; do if [[ -f "${override}" ]]; then COMPOSE_ARGS+=(-f "${override}") @@ -609,56 +597,6 @@ cmd_render_route() { log info "rendered route ${route_file}" } -# Before panelctl passed -p, compose named the project after the compose -# file's directory, so every git app (repo/compose.yaml) shared the project -# "repo". Move the app's old containers out of the way so they are recreated -# under its own name. Named volumes are prefixed with the project name, so an -# app whose containers use them keeps its old project instead. -adopt_legacy_project() { - [[ -z "${APP_COMPOSE_PROJECT:-}" ]] || return 0 - local dir id project legacy="" volumes - local ids=() - dir="$(cd "$(dirname "${APP_COMPOSE_FILE}")" 2>/dev/null && pwd -P)" || return 0 - - while IFS='|' read -r id project; do - [[ -n "${id}" && -n "${project}" && "${project}" != "${CURRENT_APP}" ]] || continue - ids+=("${id}") - legacy="${project}" - done < <(run_podman ps --all --filter "label=com.docker.compose.project.working_dir=${dir}" \ - --format '{{.ID}}|{{index .Labels "com.docker.compose.project"}}' 2>/dev/null || true) - [[ ${#ids[@]} -gt 0 ]] || return 0 - - volumes="$(run_podman inspect --format '{{range .Mounts}}{{if eq .Type "volume"}}{{.Name}} {{end}}{{end}}' "${ids[@]}" 2>/dev/null | xargs || true)" - if [[ -n "${volumes}" ]]; then - echo "APP_COMPOSE_PROJECT=\"${legacy}\"" >>"$(app_manifest "${CURRENT_APP}")" - APP_COMPOSE_PROJECT="${legacy}" - refresh_compose_args - echo "Keeping compose project '${legacy}', because the app's containers use named volumes (${volumes})" - log warning "app '${CURRENT_APP}' keeps compose project '${legacy}' because its containers use named volumes" - return 0 - fi - - echo "Moving the app's containers from compose project '${legacy}' to '${CURRENT_APP}'" - run_podman rm --force "${ids[@]}" >/dev/null || fail "could not remove the old containers" - # The shared pod goes away once no other app's containers are left in it. - run_podman pod rm "pod_${legacy}" >/dev/null 2>&1 || true -} - -# True when a container of the app runs an older image than its tag now -# points at, e.g. after a rebuild. podman-compose only recreates containers -# when the compose file itself changes, so without this a push that only -# changes code would build a new image and keep running the old one. -containers_outdated() { - local id image current - while IFS='|' read -r id image; do - [[ -n "${id}" && -n "${image}" ]] || continue - current="$(run_podman image inspect --format '{{.Id}}' "${image}" 2>/dev/null)" || continue - [[ "${current}" == "${id}"* || "${id}" == "${current}"* ]] || return 0 - done < <(run_podman ps --all --filter "label=com.docker.compose.project=$(compose_project)" \ - --format '{{.ImageID}}|{{.Image}}' 2>/dev/null || true) - return 1 -} - cmd_deploy() { local name="$1" validate_name "${name}" @@ -669,21 +607,10 @@ cmd_deploy() { cmd_render_route "${name}" prepare_ports_override "${name}" prepare_env_override "${name}" - adopt_legacy_project # Stream compose output as it happens (the panel shows it live in the # deployment log) and keep a copy in the journal. - if ! run_compose "${COMPOSE_ARGS[@]}" build 2>&1 | tee >(journal_copy); then - log err "Deployment failed for app '${name}'" - fail "image build failed" - fi - - local up_args=(up -d --no-build "${ORPHAN_ARGS[@]}") - if containers_outdated; then - echo "Images changed, recreating the app's containers" - up_args+=(--force-recreate) - fi - if ! run_compose "${COMPOSE_ARGS[@]}" "${up_args[@]}" 2>&1 | tee >(journal_copy); then + if ! run_compose "${COMPOSE_ARGS[@]}" up -d --build --remove-orphans 2>&1 | tee >(journal_copy); then log err "Deployment failed for app '${name}'" fail "compose up failed" fi @@ -698,12 +625,11 @@ cmd_restart() { log info "Restarting app '${name}'" - adopt_legacy_project - run_compose "${COMPOSE_ARGS[@]}" down "${ORPHAN_ARGS[@]}" || fail "compose down failed" + run_compose "${COMPOSE_ARGS[@]}" down --remove-orphans || fail "compose down failed" prepare_ports_override "${name}" prepare_env_override "${name}" - if ! run_compose "${COMPOSE_ARGS[@]}" up -d --build "${ORPHAN_ARGS[@]}" 2>&1; then + if ! run_compose "${COMPOSE_ARGS[@]}" up -d --build --remove-orphans 2>&1; then fail "compose up failed during restart" fi @@ -715,7 +641,7 @@ cmd_stop() { validate_name "${name}" load_app "${name}" - run_compose "${COMPOSE_ARGS[@]}" down "${ORPHAN_ARGS[@]}" || fail "compose down failed" + run_compose "${COMPOSE_ARGS[@]}" down --remove-orphans || fail "compose down failed" log info "stopped app '${name}'" } @@ -816,7 +742,7 @@ cmd_remove() { validate_name "${name}" load_app "${name}" - run_compose "${COMPOSE_ARGS[@]}" down "${ORPHAN_ARGS[@]}" 2>/dev/null || true + run_compose "${COMPOSE_ARGS[@]}" down --remove-orphans 2>/dev/null || true # Remove this app's block from the aggregate routes file. local route_file @@ -952,7 +878,7 @@ cmd_volume_clear() { load_app "${name}" log info "clearing volume data for app '${name}'" - run_compose "${COMPOSE_ARGS[@]}" down "${ORPHAN_ARGS[@]}" 2>/dev/null || true + run_compose "${COMPOSE_ARGS[@]}" down --remove-orphans 2>/dev/null || true local data_dir="${APP_VOLUME_DIR}/data" if [[ -d "${data_dir}" ]]; then