kampodine 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +118 -0
- package/README.md +72 -9
- package/cli.js +21 -1
- package/kampodine.md +13 -3
- package/package.json +1 -1
- package/scripts/backup.sh +290 -0
- package/scripts/bluegreen.sh +21 -1
- package/scripts/common.sh +644 -0
- package/scripts/config.sh +247 -0
- package/scripts/deploy-lifecycle.sh +266 -0
- package/scripts/deploy.sh +136 -18
- package/scripts/dns.sh +17 -0
- package/scripts/env.sh +23 -9
- package/scripts/image-import.sh +9 -0
- package/scripts/metrics.sh +127 -0
- package/scripts/migrate.sh +39 -5
- package/scripts/status.sh +132 -12
- package/scripts/vm-prepare.sh +20 -6
package/scripts/status.sh
CHANGED
|
@@ -1,44 +1,164 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# status.sh — one command: what is LIVE (through
|
|
3
|
-
#
|
|
2
|
+
# status.sh — one command: deployment count (ledger), what is LIVE (through
|
|
3
|
+
# the proxy), the VM's disk/image/service state (with --host), and the
|
|
4
|
+
# blue/green pair view.
|
|
4
5
|
#
|
|
5
6
|
# Usage:
|
|
6
|
-
# kampodine status
|
|
7
|
+
# kampodine status [--host root@<ip>] [--ssh-key <path>]
|
|
7
8
|
#
|
|
8
|
-
#
|
|
9
|
+
# Without --host: live health + the deployment count (all hosts). With
|
|
10
|
+
# --host: adds VM disk usage (LOUD warning above 90%), the sha-tagged image
|
|
11
|
+
# count with a reclaimable-by-prune estimate, and service states
|
|
12
|
+
# (kampodine-api, kamal-proxy, walshipper if present).
|
|
13
|
+
#
|
|
14
|
+
# Env: APP_HOST_HEADER (default: app.example.com), KAMPODINE_HOST,
|
|
15
|
+
# KAMPODINE_SSH_KEY, OCI_PROFILE, OCI_COMPARTMENT.
|
|
9
16
|
set -euo pipefail
|
|
10
17
|
HERE="$(cd "$(dirname "$0")" && pwd)"
|
|
11
|
-
|
|
18
|
+
# shellcheck source=common.sh
|
|
19
|
+
source "$HERE/common.sh"
|
|
20
|
+
|
|
21
|
+
HOST_HEADER="${PROFILE_PROXY_HOST:-${APP_HOST_HEADER:-app.example.com}}"
|
|
22
|
+
IMAGE="127.0.0.1:5000/kampodine-api"
|
|
23
|
+
DISK_PATH="/var/lib/containers"
|
|
24
|
+
KAMPODINE_HOST="${KAMPODINE_HOST:-}"
|
|
25
|
+
if [ -n "${KAMPODINE_SSH_KEY:-}" ]; then
|
|
26
|
+
SSH_KEY="$KAMPODINE_SSH_KEY"
|
|
27
|
+
else
|
|
28
|
+
SSH_KEY=""
|
|
29
|
+
fi
|
|
30
|
+
PROFILE_FLAG=""
|
|
31
|
+
HOST_FLAG=""
|
|
32
|
+
KEY_FLAG=""
|
|
33
|
+
VERBOSE=0
|
|
12
34
|
|
|
13
35
|
say() { printf '%s\n' "$*"; }
|
|
14
36
|
die() { printf '[status] FAIL: %s\n' "$*" >&2; exit 1; }
|
|
15
37
|
usage() {
|
|
16
38
|
cat <<'EOF'
|
|
17
39
|
Usage:
|
|
18
|
-
kampodine status
|
|
40
|
+
kampodine status [--host root@<ip>] [--profile <name>] [--ssh-key <path>] [--verbose]
|
|
19
41
|
|
|
20
42
|
Examples:
|
|
21
|
-
kampodine status
|
|
43
|
+
kampodine status # deployments (ledger) + live health + blue/green pair
|
|
44
|
+
kampodine status --host root@203.0.113.10 # + VM disk usage, image/prune estimate, service states
|
|
45
|
+
kampodine status --profile prod # resolve host/key from a config profile
|
|
46
|
+
kampodine status --host root@203.0.113.10 --verbose # + the full metrics snapshot
|
|
47
|
+
# (load, memory, disk breakdown, containers, top procs)
|
|
22
48
|
|
|
23
|
-
Env: APP_HOST_HEADER (default app.example.com),
|
|
49
|
+
Env: APP_HOST_HEADER (default app.example.com), KAMPODINE_HOST,
|
|
50
|
+
KAMPODINE_SSH_KEY, KAMPODINE_PROFILE, OCI_PROFILE, OCI_COMPARTMENT.
|
|
24
51
|
EOF
|
|
25
52
|
exit 0
|
|
26
53
|
}
|
|
27
54
|
|
|
28
55
|
while [[ $# -gt 0 ]]; do
|
|
29
56
|
case "$1" in
|
|
57
|
+
--host) HOST_FLAG="$2"; KAMPODINE_HOST="$2"; shift 2 ;;
|
|
58
|
+
--ssh-key) KEY_FLAG="$2"; SSH_KEY="$2"; shift 2 ;;
|
|
59
|
+
--profile) PROFILE_FLAG="$2"; shift 2 ;;
|
|
60
|
+
--verbose) VERBOSE=1; shift ;;
|
|
30
61
|
-h|--help) usage ;;
|
|
31
62
|
*) die "unknown argument: $1 (--help)" ;;
|
|
32
63
|
esac
|
|
33
64
|
done
|
|
34
65
|
|
|
35
|
-
|
|
36
|
-
|
|
66
|
+
# profile resolution (flag > KAMPODINE_PROFILE > defaultProfile); an explicit
|
|
67
|
+
# --host/--ssh-key flag always beats the profile
|
|
68
|
+
profile_resolve "$PROFILE_FLAG" "$HOST_FLAG" "$KEY_FLAG"
|
|
69
|
+
SSH_KEY="${KEY_FLAG:-${KAMPODINE_SSH_KEY:-}}"
|
|
70
|
+
|
|
71
|
+
# --- deployment count (the owner's "total deployments", always visible) -------
|
|
72
|
+
if [[ -n "$KAMPODINE_HOST" ]]; then
|
|
73
|
+
say "== deployments (ledger: $(ledger_file)) =="
|
|
74
|
+
ledger_total_line "$(ledger_count "$KAMPODINE_HOST")" "deployments to $KAMPODINE_HOST"
|
|
75
|
+
else
|
|
76
|
+
say "== deployments (ledger: $(ledger_file)) =="
|
|
77
|
+
ledger_total_line "$(ledger_count)" "across all hosts — pass --host root@<ip> for VM state"
|
|
78
|
+
if [[ $VERBOSE -eq 1 ]]; then
|
|
79
|
+
say "metrics snapshot: needs a target — add --host root@<ip> (or --profile <name>)"
|
|
80
|
+
fi
|
|
81
|
+
fi
|
|
82
|
+
say
|
|
83
|
+
|
|
84
|
+
say "== live (through the proxy: https://$HOST_HEADER) =="
|
|
85
|
+
if body="$(curl -sf -m 8 "https://$HOST_HEADER/api/auth/ok" 2>/dev/null)"; then
|
|
37
86
|
say "HEALTH OK: $body"
|
|
38
|
-
say "build-id : $(curl -sf -m 8 "https://$
|
|
87
|
+
say "build-id : $(curl -sf -m 8 "https://$HOST_HEADER/build-id.txt" 2>/dev/null || echo unreachable)"
|
|
39
88
|
else
|
|
40
89
|
say "UNREACHABLE or unhealthy — check the VM (ssh) and kamal-proxy"
|
|
41
90
|
fi
|
|
91
|
+
|
|
92
|
+
if [[ -n "$KAMPODINE_HOST" ]]; then
|
|
93
|
+
SSH_ARGS=(-o ConnectTimeout=10 -o BatchMode=yes)
|
|
94
|
+
[[ -n "$SSH_KEY" ]] && SSH_ARGS+=(-i "$SSH_KEY")
|
|
95
|
+
# $1 is a composed remote command — client-side expansion is the design.
|
|
96
|
+
# shellcheck disable=SC2029
|
|
97
|
+
vm() { ssh "${SSH_ARGS[@]}" "$KAMPODINE_HOST" "$1"; }
|
|
98
|
+
if [[ "$(uname -s)" == "Darwin" ]]; then
|
|
99
|
+
SSH_AUTH_SOCK="$(launchctl getenv SSH_AUTH_SOCK 2>/dev/null || true)"
|
|
100
|
+
export SSH_AUTH_SOCK
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
say
|
|
104
|
+
say "== VM ($KAMPODINE_HOST) =="
|
|
105
|
+
df_out="$(vm "df -P $DISK_PATH 2>/dev/null" || true)"
|
|
106
|
+
pct="$(disk_pct_from_df "$df_out")"
|
|
107
|
+
case "$(disk_verdict "$pct" "")" in
|
|
108
|
+
ok) say "disk : ${pct}% used on $DISK_PATH" ;;
|
|
109
|
+
warn)
|
|
110
|
+
say "disk : ${pct}% used on $DISK_PATH"
|
|
111
|
+
say "WARNING : VM disk above 90% — old sha-tagged deploy images pile up (~1GB each); reclaim: kampodine deploy prune --dry-run"
|
|
112
|
+
;;
|
|
113
|
+
*) say "disk : unknown (df unreadable)" ;;
|
|
114
|
+
esac
|
|
115
|
+
|
|
116
|
+
images_raw="$(vm "podman images --format '{{.Tag}}|{{.CreatedAt}}|{{.Size}}' $IMAGE 2>/dev/null" || true)"
|
|
117
|
+
images="$(printf '%s\n' "$images_raw" | grep -E '^[0-9a-f]{7,40}\|' || true)"
|
|
118
|
+
running="$(vm "podman ps --format '{{.Image}}' 2>/dev/null" || true)"
|
|
119
|
+
img_count="$(printf '%s\n' "$images" | grep -c . || true)"
|
|
120
|
+
reclaim="$(prune_select "$images" "$running" 2 || true)"
|
|
121
|
+
reclaim_n="0"
|
|
122
|
+
reclaim_tags="(none)"
|
|
123
|
+
reclaim_size="~0 MB"
|
|
124
|
+
if [[ -n "$reclaim" ]]; then
|
|
125
|
+
reclaim_n="$(printf '%s\n' "$reclaim" | grep -c . || true)"
|
|
126
|
+
reclaim_tags="$(printf '%s\n' "$reclaim" | cut -d'|' -f1 | paste -sd, -)"
|
|
127
|
+
reclaim_size="$(sum_sizes_human "$(printf '%s\n' "$reclaim" | cut -d'|' -f2)")"
|
|
128
|
+
fi
|
|
129
|
+
say "images : ${img_count:-0} sha-tagged deploy image(s); prune would remove ${reclaim_n} ${reclaim_tags} (${reclaim_size}): kampodine deploy prune --dry-run"
|
|
130
|
+
|
|
131
|
+
# init detection (groundwork for non-Alpine targets): the roll call keeps
|
|
132
|
+
# the historical shape on Alpine (byte-identical "for s in … rc-service …")
|
|
133
|
+
# and swaps the probe command on systemd hosts.
|
|
134
|
+
init_detect vm >/dev/null 2>&1 || true
|
|
135
|
+
case "$INIT_SYSTEM" in
|
|
136
|
+
systemd) svc_probe='systemctl status "$s"' ;;
|
|
137
|
+
*) svc_probe='rc-service "$s" status' ;;
|
|
138
|
+
esac
|
|
139
|
+
say "services:"
|
|
140
|
+
vm "for s in kampodine-api kamal-proxy walshipper; do if $svc_probe >/dev/null 2>&1; then echo \"\$s: running\"; else echo \"\$s: not-running\"; fi; done" \
|
|
141
|
+
|| say "(service roll call failed)"
|
|
142
|
+
|
|
143
|
+
if [[ $VERBOSE -eq 1 ]]; then
|
|
144
|
+
say
|
|
145
|
+
say "== metrics snapshot =="
|
|
146
|
+
if metrics_raw="$(vm "$METRICS_REMOTE_CMD" 2>/dev/null)"; then
|
|
147
|
+
metrics_render "$metrics_raw"
|
|
148
|
+
metrics_pct="$(disk_pct_from_df "$M_DISK")"
|
|
149
|
+
if [[ -n "$metrics_pct" ]] && [[ "$metrics_pct" -gt 90 ]]; then
|
|
150
|
+
say "WARNING : root disk above 90% — reclaim: kampodine deploy prune --dry-run"
|
|
151
|
+
fi
|
|
152
|
+
else
|
|
153
|
+
say "(metrics snapshot failed — VM unreachable?)"
|
|
154
|
+
fi
|
|
155
|
+
fi
|
|
156
|
+
fi
|
|
157
|
+
|
|
42
158
|
say
|
|
43
159
|
say "== blue/green pair =="
|
|
44
|
-
|
|
160
|
+
if [[ -n "$PROFILE_FLAG" ]]; then
|
|
161
|
+
exec bash "$HERE/bluegreen.sh" status --profile "$PROFILE_FLAG"
|
|
162
|
+
else
|
|
163
|
+
exec bash "$HERE/bluegreen.sh" status
|
|
164
|
+
fi
|
package/scripts/vm-prepare.sh
CHANGED
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
# not a restart).
|
|
36
36
|
#
|
|
37
37
|
# kampodine vm-prepare --host root@<new-ip>
|
|
38
|
+
# kampodine vm-prepare --profile <name> # host/key from ~/.kampodine/config.json
|
|
38
39
|
# ... --pull-images # + pre-pull the app image over the registry tunnel
|
|
39
40
|
# ... --ssh-key <path> # ssh identity (default: agent / KAMPODINE_SSH_KEY)
|
|
40
41
|
set -euo pipefail
|
|
@@ -42,35 +43,48 @@ set -euo pipefail
|
|
|
42
43
|
HOST=""
|
|
43
44
|
DO_PULL=0
|
|
44
45
|
SSH_KEY="${KAMPODINE_SSH_KEY:-}"
|
|
46
|
+
PROFILE_FLAG=""
|
|
47
|
+
HOST_FLAG=""
|
|
48
|
+
KEY_FLAG=""
|
|
49
|
+
HERE="$(cd "$(dirname "$0")" && pwd)"
|
|
50
|
+
# shellcheck source=common.sh
|
|
51
|
+
source "$HERE/common.sh"
|
|
45
52
|
|
|
46
53
|
say() { printf '\033[1;32m[vm-prepare]\033[0m %s\n' "$*"; }
|
|
47
54
|
die() { printf '\033[1;31m[vm-prepare] FAIL:\033[0m %s\n' "$*" >&2; exit 1; }
|
|
48
55
|
usage() {
|
|
49
56
|
cat <<'EOF'
|
|
50
57
|
Usage:
|
|
51
|
-
kampodine vm-prepare --host root@<new-ip> [--pull-images] [--ssh-key <path>]
|
|
58
|
+
kampodine vm-prepare --host root@<new-ip> [--pull-images] [--ssh-key <path>] [--profile <name>]
|
|
52
59
|
|
|
53
60
|
Examples:
|
|
54
61
|
EOF
|
|
55
62
|
grep '^# kampodine vm-prepare' "$0" | sed 's/^# //'
|
|
56
63
|
cat <<'EOF'
|
|
57
64
|
|
|
58
|
-
Host/key resolution: --host |
|
|
59
|
-
--ssh-key |
|
|
65
|
+
Host/key resolution: --host | --profile <name> | KAMPODINE_PROFILE |
|
|
66
|
+
config defaultProfile; --ssh-key | profile sshKey | KAMPODINE_SSH_KEY |
|
|
67
|
+
ssh-agent / ~/.ssh/config.
|
|
60
68
|
EOF
|
|
61
69
|
exit 0
|
|
62
70
|
}
|
|
63
71
|
|
|
64
72
|
while [[ $# -gt 0 ]]; do
|
|
65
73
|
case "$1" in
|
|
66
|
-
--host) HOST="$2"; shift 2 ;;
|
|
74
|
+
--host) HOST_FLAG="$2"; HOST="$2"; shift 2 ;;
|
|
67
75
|
--pull-images) DO_PULL=1; shift ;;
|
|
68
|
-
--ssh-key) SSH_KEY="$2"; shift 2 ;;
|
|
76
|
+
--ssh-key) KEY_FLAG="$2"; SSH_KEY="$2"; shift 2 ;;
|
|
77
|
+
--profile) PROFILE_FLAG="$2"; shift 2 ;;
|
|
69
78
|
-h|--help) usage ;;
|
|
70
79
|
*) die "unknown argument: $1 (--help)" ;;
|
|
71
80
|
esac
|
|
72
81
|
done
|
|
73
|
-
|
|
82
|
+
# profile resolution (flag > KAMPODINE_PROFILE > defaultProfile); the explicit
|
|
83
|
+
# --host/--ssh-key flags always beat the profile
|
|
84
|
+
profile_resolve "$PROFILE_FLAG" "${HOST_FLAG:-}" "${KEY_FLAG:-}"
|
|
85
|
+
SSH_KEY="${KEY_FLAG:-${KAMPODINE_SSH_KEY:-}}"
|
|
86
|
+
[[ -z "$HOST" ]] && HOST="${KAMPODINE_HOST:-}"
|
|
87
|
+
[[ -n "$HOST" ]] || die "--host root@<ip> required (--profile <name> or KAMPODINE_HOST also work; --help for usage)"
|
|
74
88
|
|
|
75
89
|
SSH_ARGS=(-o ConnectTimeout=10 -o BatchMode=yes -o StrictHostKeyChecking=accept-new)
|
|
76
90
|
[[ -n "$SSH_KEY" ]] && SSH_ARGS+=(-i "$SSH_KEY")
|