@mriekki/lean 0.0.0-stage → 0.1.1
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/README.md +66 -2
- package/assets/components.json +33 -0
- package/assets/core/distribution.json +51 -0
- package/assets/deployment/distribution.json +34 -0
- package/assets/generated/ASSEMBLY.json +382 -0
- package/assets/generated/core/core/agents/coach.agent.md +69 -0
- package/assets/generated/core/core/agents/reviewer.agent.md +85 -0
- package/assets/generated/core/core/instructions/lean-docs.instructions.md +14 -0
- package/assets/generated/core/core/instructions/lean-workflow.instructions.md +35 -0
- package/assets/generated/core/core/learning/CODING_DRILLS.md +35 -0
- package/assets/generated/core/core/learning/DIAGRAM_GUIDE.md +19 -0
- package/assets/generated/core/core/learning/ENGINEERING_LEARNING_WORKBOOK.md +82 -0
- package/assets/generated/core/core/learning/LEARNING_MAP.md +51 -0
- package/assets/generated/core/core/learning/LEARNING_PROGRESS.md +31 -0
- package/assets/generated/core/core/learning/RESOURCE_CATALOG.md +25 -0
- package/assets/generated/core/core/learning/SQL_DRILLS.md +27 -0
- package/assets/generated/core/core/learning/SYSTEM_DESIGN_DRILLS.md +21 -0
- package/assets/generated/core/core/process/COACHING_GUIDE.md +57 -0
- package/assets/generated/core/core/process/GUIDED_NEXT_STEPS.md +48 -0
- package/assets/generated/core/core/process/HUMAN_GATES.md +81 -0
- package/assets/generated/core/core/process/INTERACTIVE_SESSION_GUIDE.md +62 -0
- package/assets/generated/core/core/process/PRODUCTION_ENABLEMENT.md +59 -0
- package/assets/generated/core/core/process/PR_WORKFLOW.md +53 -0
- package/assets/generated/core/core/process/SETUP_ACCEPTANCE_CHECKLIST.md +72 -0
- package/assets/generated/core/core/process/WORK_ITEM_MODEL.md +56 -0
- package/assets/generated/core/core/skills/cleanup-branches/SKILL.md +190 -0
- package/assets/generated/core/core/skills/coach/SKILL.md +136 -0
- package/assets/generated/core/core/skills/code-walkthrough/SKILL.md +197 -0
- package/assets/generated/core/core/skills/core-sync/SKILL.md +220 -0
- package/assets/generated/core/core/skills/define-feature/SKILL.md +144 -0
- package/assets/generated/core/core/skills/deliver/SKILL.md +315 -0
- package/assets/generated/core/core/skills/deploy/SKILL.md +193 -0
- package/assets/generated/core/core/skills/grill-me/SKILL.md +77 -0
- package/assets/generated/core/core/skills/grill-with-docs/SKILL.md +90 -0
- package/assets/generated/core/core/skills/learning-review/SKILL.md +90 -0
- package/assets/generated/core/core/skills/next-step/SKILL.md +166 -0
- package/assets/generated/core/core/skills/production-readiness/SKILL.md +357 -0
- package/assets/generated/core/core/skills/pull-latest/SKILL.md +166 -0
- package/assets/generated/core/core/skills/refine-requirements/SKILL.md +207 -0
- package/assets/generated/core/core/skills/start-work/SKILL.md +178 -0
- package/assets/generated/core/core/skills/tear-down/SKILL.md +138 -0
- package/assets/generated/core/core/skills/upstream-fix/SKILL.md +206 -0
- package/assets/generated/core/core/skills/wait-what/SKILL.md +86 -0
- package/assets/generated/core/core/templates/FEATURE_BRIEF_TEMPLATE.md +27 -0
- package/assets/generated/core/core/templates/PRODUCT_BRIEF_TEMPLATE.md +27 -0
- package/assets/generated/core/core/templates/PULL_REQUEST_TEMPLATE.md +37 -0
- package/assets/generated/core/core/templates/REQUIREMENTS_TEMPLATE.md +17 -0
- package/assets/generated/core/profiles/greenfield/lean-workspace.json +12 -0
- package/assets/generated/core/tools/package/check_baseline.py +102 -0
- package/assets/generated/core/tools/package/check_upstream.py +171 -0
- package/assets/generated/deployment/distribution/lean-poc-deploy.py +8 -0
- package/assets/generated/deployment/src/lean_poc_deployment/__init__.py +3 -0
- package/assets/generated/deployment/src/lean_poc_deployment/__main__.py +3 -0
- package/assets/generated/deployment/src/lean_poc_deployment/app_cli.py +140 -0
- package/assets/generated/deployment/src/lean_poc_deployment/app_runtime.py +455 -0
- package/assets/generated/deployment/src/lean_poc_deployment/app_runtime_remote.py +416 -0
- package/assets/generated/deployment/src/lean_poc_deployment/box_platform.py +208 -0
- package/assets/generated/deployment/src/lean_poc_deployment/box_platform_assets.py +100 -0
- package/assets/generated/deployment/src/lean_poc_deployment/box_platform_remote.py +271 -0
- package/assets/generated/deployment/src/lean_poc_deployment/cli.py +437 -0
- package/assets/generated/deployment/src/lean_poc_deployment/doctor.py +121 -0
- package/assets/generated/deployment/src/lean_poc_deployment/entrypoint.py +25 -0
- package/assets/generated/deployment/src/lean_poc_deployment/errors.py +5 -0
- package/assets/generated/deployment/src/lean_poc_deployment/keys.py +171 -0
- package/assets/generated/deployment/src/lean_poc_deployment/profiles.py +204 -0
- package/assets/generated/deployment/src/lean_poc_deployment/route_registry.py +367 -0
- package/assets/generated/deployment/src/lean_poc_deployment/route_registry_remote.py +443 -0
- package/assets/generated/deployment/src/lean_poc_deployment/security.py +290 -0
- package/assets/generated/deployment/src/lean_poc_deployment/sqlite_adapter.py +335 -0
- package/assets/generated/deployment/src/lean_poc_deployment/sqlite_adapter_remote.py +340 -0
- package/assets/generated/deployment/src/lean_poc_deployment/sqlite_cli.py +86 -0
- package/assets/generated/deployment/src/lean_poc_deployment/sqlite_import_recovery.py +437 -0
- package/assets/generated/deployment/src/lean_poc_deployment/ssh.py +118 -0
- package/assets/generated/deployment/src/lean_poc_deployment/teardown.py +286 -0
- package/assets/generated/deployment/src/lean_poc_deployment/teardown_cli.py +120 -0
- package/assets/generated/deployment/src/lean_poc_deployment/teardown_remote.py +100 -0
- package/assets/generated/deployment/src/lean_poc_deployment/trust.py +278 -0
- package/bin/lean.mjs +9 -0
- package/package.json +31 -4
- package/src/cli.mjs +131 -0
- package/src/engine.mjs +243 -0
- package/src/package-data.mjs +18 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"""Static shared-box platform assets and contract constants."""
|
|
2
|
+
|
|
3
|
+
PLATFORM_SCHEMA_VERSION = 1
|
|
4
|
+
PLATFORM_VERSION = "2"
|
|
5
|
+
PLATFORM_DISTRIBUTION = "trusted-lan-ubuntu-compose"
|
|
6
|
+
PLATFORM_ROOT = "/srv/lean-poc-platform"
|
|
7
|
+
NETWORK_NAME = "caddy-net"
|
|
8
|
+
CADDY_CONTAINER = "lean-poc-caddy"
|
|
9
|
+
CADDY_IMAGE = "caddy:2.8.4-alpine@sha256:af32e97399febea808609119bb21544d0265c58a02836576e32a2d082c262c17"
|
|
10
|
+
HOST_PLATFORM_WRITE_PHRASE = "[HOST PLATFORM WRITE]"
|
|
11
|
+
|
|
12
|
+
COMPOSE_YAML = f"""services:
|
|
13
|
+
caddy:
|
|
14
|
+
image: {CADDY_IMAGE}
|
|
15
|
+
container_name: {CADDY_CONTAINER}
|
|
16
|
+
restart: unless-stopped
|
|
17
|
+
ports:
|
|
18
|
+
- \"80:80\"
|
|
19
|
+
volumes:
|
|
20
|
+
- {PLATFORM_ROOT}/proxy/Caddyfile:/etc/caddy/Caddyfile:ro
|
|
21
|
+
- {PLATFORM_ROOT}/proxy/conf.d:/etc/caddy/conf.d:ro
|
|
22
|
+
- {PLATFORM_ROOT}/proxy/data:/data
|
|
23
|
+
- {PLATFORM_ROOT}/proxy/config:/config
|
|
24
|
+
networks:
|
|
25
|
+
- {NETWORK_NAME}
|
|
26
|
+
logging:
|
|
27
|
+
driver: json-file
|
|
28
|
+
options:
|
|
29
|
+
max-size: \"10m\"
|
|
30
|
+
max-file: \"3\"
|
|
31
|
+
|
|
32
|
+
networks:
|
|
33
|
+
{NETWORK_NAME}:
|
|
34
|
+
external: true
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
CADDYFILE = """{
|
|
38
|
+
auto_https off
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
import /etc/caddy/conf.d/*.caddy
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
PUBLISH_ALIAS_SH = """#!/usr/bin/env bash
|
|
45
|
+
set -Eeuo pipefail
|
|
46
|
+
|
|
47
|
+
: \"${ALIAS_HOSTNAME:?ALIAS_HOSTNAME is required}\"
|
|
48
|
+
|
|
49
|
+
current_ip() {
|
|
50
|
+
local ip
|
|
51
|
+
ip=\"$(ip route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i==\"src\") print $(i+1)}')\"
|
|
52
|
+
if [[ -z \"$ip\" ]]; then
|
|
53
|
+
ip=\"$(ip -4 addr show scope global | grep -v 'docker' | grep -v 'br-' | awk '/inet / {print $2}' | cut -d/ -f1 | head -n1)\"
|
|
54
|
+
fi
|
|
55
|
+
printf '%s\\n' \"$ip\"
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
CURRENT_IP=\"$(current_ip)\"
|
|
59
|
+
if [[ -z \"$CURRENT_IP\" ]]; then
|
|
60
|
+
echo \"lean-poc alias publisher: could not determine host LAN IPv4 address.\" >&2
|
|
61
|
+
exit 1
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
/usr/bin/avahi-publish -a -R \"$ALIAS_HOSTNAME\" \"$CURRENT_IP\" &
|
|
65
|
+
AVAHI_PID=$!
|
|
66
|
+
|
|
67
|
+
cleanup() {
|
|
68
|
+
kill \"$AVAHI_PID\" 2>/dev/null || true
|
|
69
|
+
wait \"$AVAHI_PID\" 2>/dev/null || true
|
|
70
|
+
}
|
|
71
|
+
trap cleanup SIGTERM SIGINT EXIT
|
|
72
|
+
|
|
73
|
+
while kill -0 \"$AVAHI_PID\" 2>/dev/null; do
|
|
74
|
+
sleep 10
|
|
75
|
+
NEW_IP=\"$(current_ip)\"
|
|
76
|
+
if [[ -n \"$NEW_IP\" && \"$NEW_IP\" != \"$CURRENT_IP\" ]]; then
|
|
77
|
+
cleanup
|
|
78
|
+
exit 0
|
|
79
|
+
fi
|
|
80
|
+
done
|
|
81
|
+
wait \"$AVAHI_PID\"
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
AVAHI_SERVICE = """[Unit]
|
|
85
|
+
Description=Lean POC mDNS alias %i
|
|
86
|
+
After=network-online.target avahi-daemon.service
|
|
87
|
+
Wants=network-online.target
|
|
88
|
+
Requires=avahi-daemon.service
|
|
89
|
+
|
|
90
|
+
[Service]
|
|
91
|
+
Type=simple
|
|
92
|
+
EnvironmentFile=/etc/lean-poc-platform/aliases/%i.env
|
|
93
|
+
ExecStart=/usr/local/lib/lean-poc-platform/publish-alias.sh
|
|
94
|
+
Restart=always
|
|
95
|
+
RestartSec=2
|
|
96
|
+
NoNewPrivileges=true
|
|
97
|
+
|
|
98
|
+
[Install]
|
|
99
|
+
WantedBy=multi-user.target
|
|
100
|
+
"""
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
"""Remote Ubuntu host-platform script template."""
|
|
2
|
+
|
|
3
|
+
REMOTE_SCRIPT = r'''#!/usr/bin/env bash
|
|
4
|
+
set -Eeuo pipefail
|
|
5
|
+
|
|
6
|
+
ACTION="$1"
|
|
7
|
+
PLATFORM_ROOT="__PLATFORM_ROOT__"
|
|
8
|
+
PROXY_ROOT="$PLATFORM_ROOT/proxy"
|
|
9
|
+
ROUTE_ROOT="$PLATFORM_ROOT/routes"
|
|
10
|
+
MARKER="$PLATFORM_ROOT/platform.env"
|
|
11
|
+
LOCK_FILE="/run/lock/lean-poc-platform.lock"
|
|
12
|
+
NETWORK_NAME="__NETWORK_NAME__"
|
|
13
|
+
CADDY_CONTAINER="__CADDY_CONTAINER__"
|
|
14
|
+
CADDY_IMAGE="__CADDY_IMAGE__"
|
|
15
|
+
SCHEMA_VERSION="__SCHEMA_VERSION__"
|
|
16
|
+
PLATFORM_VERSION="__PLATFORM_VERSION__"
|
|
17
|
+
DISTRIBUTION="__DISTRIBUTION__"
|
|
18
|
+
COMPOSE_B64="__COMPOSE_B64__"
|
|
19
|
+
CADDYFILE_B64="__CADDYFILE_B64__"
|
|
20
|
+
PUBLISH_ALIAS_B64="__PUBLISH_ALIAS_B64__"
|
|
21
|
+
AVAHI_SERVICE_B64="__AVAHI_SERVICE_B64__"
|
|
22
|
+
|
|
23
|
+
marker_value() {
|
|
24
|
+
local key="$1"
|
|
25
|
+
[[ -f "$MARKER" ]] || return 1
|
|
26
|
+
sed -n "s/^${key}=//p" "$MARKER" | head -n1
|
|
27
|
+
}
|
|
28
|
+
port80_in_use() {
|
|
29
|
+
if command -v ss >/dev/null 2>&1; then
|
|
30
|
+
ss -ltn '( sport = :80 )' 2>/dev/null | tail -n +2 | grep -q .
|
|
31
|
+
else
|
|
32
|
+
return 1
|
|
33
|
+
fi
|
|
34
|
+
}
|
|
35
|
+
prereqs_ready() {
|
|
36
|
+
command -v docker >/dev/null 2>&1 &&
|
|
37
|
+
docker compose version >/dev/null 2>&1 &&
|
|
38
|
+
command -v systemctl >/dev/null 2>&1 &&
|
|
39
|
+
command -v avahi-publish >/dev/null 2>&1 &&
|
|
40
|
+
command -v flock >/dev/null 2>&1 &&
|
|
41
|
+
command -v base64 >/dev/null 2>&1 &&
|
|
42
|
+
command -v install >/dev/null 2>&1 &&
|
|
43
|
+
command -v mktemp >/dev/null 2>&1 &&
|
|
44
|
+
command -v ss >/dev/null 2>&1
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
status() {
|
|
48
|
+
local marker_present=false prereqs=false network=false caddy_running=false avahi=false port80=false
|
|
49
|
+
[[ -f "$MARKER" ]] && marker_present=true
|
|
50
|
+
prereqs_ready && prereqs=true || true
|
|
51
|
+
docker network inspect "$NETWORK_NAME" >/dev/null 2>&1 && network=true || true
|
|
52
|
+
[[ "$(docker inspect --format '{{.State.Status}}' "$CADDY_CONTAINER" 2>/dev/null || true)" == "running" ]] && caddy_running=true || true
|
|
53
|
+
systemctl is-active --quiet avahi-daemon 2>/dev/null && avahi=true || true
|
|
54
|
+
port80_in_use && port80=true || true
|
|
55
|
+
|
|
56
|
+
local state marker_schema marker_distribution marker_version
|
|
57
|
+
marker_schema="$(marker_value SCHEMA_VERSION 2>/dev/null || true)"
|
|
58
|
+
marker_distribution="$(marker_value DISTRIBUTION 2>/dev/null || true)"
|
|
59
|
+
marker_version="$(marker_value PLATFORM_VERSION 2>/dev/null || true)"
|
|
60
|
+
|
|
61
|
+
if [[ "$marker_present" == false ]]; then
|
|
62
|
+
if [[ "$prereqs" != true ]]; then
|
|
63
|
+
state="blocked"
|
|
64
|
+
elif [[ "$port80" == true ]]; then
|
|
65
|
+
state="blocked-port-80"
|
|
66
|
+
else
|
|
67
|
+
state="installable"
|
|
68
|
+
fi
|
|
69
|
+
elif [[ "$marker_schema" != "$SCHEMA_VERSION" || "$marker_distribution" != "$DISTRIBUTION" ]]; then
|
|
70
|
+
state="incompatible"
|
|
71
|
+
elif [[ "$prereqs" != true ]]; then
|
|
72
|
+
state="blocked"
|
|
73
|
+
elif [[ "$marker_version" != "$PLATFORM_VERSION" ]]; then
|
|
74
|
+
state="upgrade-required"
|
|
75
|
+
elif [[ "$network" == true && "$caddy_running" == true && "$avahi" == true && -f "$PROXY_ROOT/compose.yaml" && -f "$PROXY_ROOT/Caddyfile" && -d "$ROUTE_ROOT" && -f /usr/local/lib/lean-poc-platform/publish-alias.sh && -f /etc/systemd/system/lean-poc-avahi-alias@.service ]]; then
|
|
76
|
+
state="ready"
|
|
77
|
+
else
|
|
78
|
+
state="drifted"
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
printf 'state=%s\n' "$state"
|
|
82
|
+
printf 'markerPresent=%s\n' "$marker_present"
|
|
83
|
+
printf 'markerSchemaVersion=%s\n' "$marker_schema"
|
|
84
|
+
printf 'markerDistribution=%s\n' "$marker_distribution"
|
|
85
|
+
printf 'markerPlatformVersion=%s\n' "$marker_version"
|
|
86
|
+
printf 'expectedPlatformVersion=%s\n' "$PLATFORM_VERSION"
|
|
87
|
+
printf 'prerequisitesReady=%s\n' "$prereqs"
|
|
88
|
+
printf 'networkPresent=%s\n' "$network"
|
|
89
|
+
printf 'caddyRunning=%s\n' "$caddy_running"
|
|
90
|
+
printf 'avahiRunning=%s\n' "$avahi"
|
|
91
|
+
printf 'port80InUse=%s\n' "$port80"
|
|
92
|
+
printf 'platformRoot=%s\n' "$PLATFORM_ROOT"
|
|
93
|
+
printf 'networkName=%s\n' "$NETWORK_NAME"
|
|
94
|
+
printf 'caddyContainer=%s\n' "$CADDY_CONTAINER"
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
require_write_prereqs() {
|
|
98
|
+
if ! prereqs_ready; then
|
|
99
|
+
echo "Required host prerequisites are missing. Docker Engine + Compose, systemd, avahi-utils, iproute2/ss, flock, base64, install, and mktemp must be prepared separately." >&2
|
|
100
|
+
exit 3
|
|
101
|
+
fi
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
write_marker() {
|
|
105
|
+
local tmp="$MARKER.tmp.$$"
|
|
106
|
+
cat > "$tmp" <<EOF
|
|
107
|
+
SCHEMA_VERSION=$SCHEMA_VERSION
|
|
108
|
+
DISTRIBUTION=$DISTRIBUTION
|
|
109
|
+
PLATFORM_VERSION=$PLATFORM_VERSION
|
|
110
|
+
NETWORK_NAME=$NETWORK_NAME
|
|
111
|
+
CADDY_CONTAINER=$CADDY_CONTAINER
|
|
112
|
+
CADDY_IMAGE=$CADDY_IMAGE
|
|
113
|
+
EOF
|
|
114
|
+
chmod 0644 "$tmp"
|
|
115
|
+
mv -f "$tmp" "$MARKER"
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
decode_to() {
|
|
119
|
+
local payload="$1" dest="$2" mode="$3"
|
|
120
|
+
local tmp="${dest}.tmp.$$"
|
|
121
|
+
printf '%s' "$payload" | base64 --decode > "$tmp"
|
|
122
|
+
chmod "$mode" "$tmp"
|
|
123
|
+
mv -f "$tmp" "$dest"
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
validate_candidate() {
|
|
127
|
+
local candidate_compose="$1" candidate_caddy="$2"
|
|
128
|
+
docker compose -f "$candidate_compose" config >/dev/null
|
|
129
|
+
docker run --rm \
|
|
130
|
+
-v "$candidate_caddy:/etc/caddy/Caddyfile:ro" \
|
|
131
|
+
-v "$PROXY_ROOT/conf.d:/etc/caddy/conf.d:ro" \
|
|
132
|
+
"$CADDY_IMAGE" caddy validate --config /etc/caddy/Caddyfile >/dev/null
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
install_platform() {
|
|
136
|
+
require_write_prereqs
|
|
137
|
+
if [[ -f "$MARKER" ]]; then
|
|
138
|
+
echo "Platform marker already exists; use explicit upgrade instead of install." >&2
|
|
139
|
+
exit 4
|
|
140
|
+
fi
|
|
141
|
+
if port80_in_use; then
|
|
142
|
+
echo "Port 80 is already occupied; prepare a clean host before platform install." >&2
|
|
143
|
+
exit 6
|
|
144
|
+
fi
|
|
145
|
+
|
|
146
|
+
install -d -m 0750 "$PLATFORM_ROOT" "$PROXY_ROOT" "$ROUTE_ROOT"
|
|
147
|
+
install -d -m 0755 "$PROXY_ROOT/conf.d" "$PROXY_ROOT/data" "$PROXY_ROOT/config"
|
|
148
|
+
install -d -m 0750 "$ROUTE_ROOT"
|
|
149
|
+
install -d -m 0755 /usr/local/lib/lean-poc-platform /etc/lean-poc-platform/aliases
|
|
150
|
+
if [[ ! -e "$PROXY_ROOT/conf.d/00-platform-empty.caddy" ]]; then
|
|
151
|
+
printf '# Platform-owned placeholder; application routes are registered separately.\n' > "$PROXY_ROOT/conf.d/00-platform-empty.caddy"
|
|
152
|
+
chmod 0644 "$PROXY_ROOT/conf.d/00-platform-empty.caddy"
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
if ! docker network inspect "$NETWORK_NAME" >/dev/null 2>&1; then
|
|
156
|
+
docker network create "$NETWORK_NAME" >/dev/null
|
|
157
|
+
fi
|
|
158
|
+
|
|
159
|
+
local candidate_dir candidate_compose candidate_caddy
|
|
160
|
+
candidate_dir="$(mktemp -d)"
|
|
161
|
+
trap 'rm -rf "$candidate_dir"' RETURN
|
|
162
|
+
candidate_compose="$candidate_dir/compose.yaml"
|
|
163
|
+
candidate_caddy="$candidate_dir/Caddyfile"
|
|
164
|
+
printf '%s' "$COMPOSE_B64" | base64 --decode > "$candidate_compose"
|
|
165
|
+
printf '%s' "$CADDYFILE_B64" | base64 --decode > "$candidate_caddy"
|
|
166
|
+
validate_candidate "$candidate_compose" "$candidate_caddy"
|
|
167
|
+
|
|
168
|
+
decode_to "$COMPOSE_B64" "$PROXY_ROOT/compose.yaml" 0644
|
|
169
|
+
decode_to "$CADDYFILE_B64" "$PROXY_ROOT/Caddyfile" 0644
|
|
170
|
+
decode_to "$PUBLISH_ALIAS_B64" /usr/local/lib/lean-poc-platform/publish-alias.sh 0755
|
|
171
|
+
decode_to "$AVAHI_SERVICE_B64" /etc/systemd/system/lean-poc-avahi-alias@.service 0644
|
|
172
|
+
|
|
173
|
+
systemctl daemon-reload
|
|
174
|
+
systemctl enable --now avahi-daemon >/dev/null
|
|
175
|
+
docker compose -f "$PROXY_ROOT/compose.yaml" up -d
|
|
176
|
+
docker exec "$CADDY_CONTAINER" caddy validate --config /etc/caddy/Caddyfile >/dev/null
|
|
177
|
+
write_marker
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
upgrade_platform() {
|
|
181
|
+
require_write_prereqs
|
|
182
|
+
if [[ ! -f "$MARKER" ]]; then
|
|
183
|
+
echo "Platform marker is absent; use install on a fresh host." >&2
|
|
184
|
+
exit 7
|
|
185
|
+
fi
|
|
186
|
+
local marker_schema marker_distribution marker_version
|
|
187
|
+
marker_schema="$(marker_value SCHEMA_VERSION || true)"
|
|
188
|
+
marker_distribution="$(marker_value DISTRIBUTION || true)"
|
|
189
|
+
marker_version="$(marker_value PLATFORM_VERSION || true)"
|
|
190
|
+
if [[ "$marker_schema" != "$SCHEMA_VERSION" || "$marker_distribution" != "$DISTRIBUTION" ]]; then
|
|
191
|
+
echo "Existing platform marker is incompatible; refusing in-place upgrade." >&2
|
|
192
|
+
exit 8
|
|
193
|
+
fi
|
|
194
|
+
if [[ "$marker_version" == "$PLATFORM_VERSION" ]]; then
|
|
195
|
+
echo "Platform is already at version $PLATFORM_VERSION; no upgrade applied."
|
|
196
|
+
return 0
|
|
197
|
+
fi
|
|
198
|
+
|
|
199
|
+
install -d -m 0755 "$PROXY_ROOT/conf.d" "$PROXY_ROOT/data" "$PROXY_ROOT/config"
|
|
200
|
+
install -d -m 0750 "$ROUTE_ROOT"
|
|
201
|
+
if [[ ! -e "$PROXY_ROOT/conf.d/00-platform-empty.caddy" ]]; then
|
|
202
|
+
printf '# Platform-owned placeholder; application routes are registered separately.\n' > "$PROXY_ROOT/conf.d/00-platform-empty.caddy"
|
|
203
|
+
chmod 0644 "$PROXY_ROOT/conf.d/00-platform-empty.caddy"
|
|
204
|
+
fi
|
|
205
|
+
if ! docker network inspect "$NETWORK_NAME" >/dev/null 2>&1; then
|
|
206
|
+
docker network create "$NETWORK_NAME" >/dev/null
|
|
207
|
+
fi
|
|
208
|
+
local candidate_dir candidate_compose candidate_caddy backup_dir
|
|
209
|
+
candidate_dir="$(mktemp -d)"
|
|
210
|
+
backup_dir="$(mktemp -d)"
|
|
211
|
+
candidate_compose="$candidate_dir/compose.yaml"
|
|
212
|
+
candidate_caddy="$candidate_dir/Caddyfile"
|
|
213
|
+
printf '%s' "$COMPOSE_B64" | base64 --decode > "$candidate_compose"
|
|
214
|
+
printf '%s' "$CADDYFILE_B64" | base64 --decode > "$candidate_caddy"
|
|
215
|
+
validate_candidate "$candidate_compose" "$candidate_caddy"
|
|
216
|
+
|
|
217
|
+
for path in "$PROXY_ROOT/compose.yaml" "$PROXY_ROOT/Caddyfile" /usr/local/lib/lean-poc-platform/publish-alias.sh /etc/systemd/system/lean-poc-avahi-alias@.service "$MARKER"; do
|
|
218
|
+
if [[ -f "$path" ]]; then cp -a "$path" "$backup_dir/$(basename "$path")"; fi
|
|
219
|
+
done
|
|
220
|
+
|
|
221
|
+
rollback() {
|
|
222
|
+
echo "Upgrade failed; restoring previous platform-managed files." >&2
|
|
223
|
+
[[ -f "$backup_dir/compose.yaml" ]] && cp -f "$backup_dir/compose.yaml" "$PROXY_ROOT/compose.yaml"
|
|
224
|
+
[[ -f "$backup_dir/Caddyfile" ]] && cp -f "$backup_dir/Caddyfile" "$PROXY_ROOT/Caddyfile"
|
|
225
|
+
[[ -f "$backup_dir/publish-alias.sh" ]] && cp -f "$backup_dir/publish-alias.sh" /usr/local/lib/lean-poc-platform/publish-alias.sh
|
|
226
|
+
[[ -f "$backup_dir/lean-poc-avahi-alias@.service" ]] && cp -f "$backup_dir/lean-poc-avahi-alias@.service" /etc/systemd/system/lean-poc-avahi-alias@.service
|
|
227
|
+
[[ -f "$backup_dir/platform.env" ]] && cp -f "$backup_dir/platform.env" "$MARKER"
|
|
228
|
+
systemctl daemon-reload || true
|
|
229
|
+
docker compose -f "$PROXY_ROOT/compose.yaml" up -d || true
|
|
230
|
+
docker exec "$CADDY_CONTAINER" caddy reload --config /etc/caddy/Caddyfile || true
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
set +e
|
|
234
|
+
decode_to "$COMPOSE_B64" "$PROXY_ROOT/compose.yaml" 0644
|
|
235
|
+
rc=$?
|
|
236
|
+
[[ $rc -eq 0 ]] && decode_to "$CADDYFILE_B64" "$PROXY_ROOT/Caddyfile" 0644; rc=$(( rc == 0 ? $? : rc ))
|
|
237
|
+
[[ $rc -eq 0 ]] && decode_to "$PUBLISH_ALIAS_B64" /usr/local/lib/lean-poc-platform/publish-alias.sh 0755; rc=$(( rc == 0 ? $? : rc ))
|
|
238
|
+
[[ $rc -eq 0 ]] && decode_to "$AVAHI_SERVICE_B64" /etc/systemd/system/lean-poc-avahi-alias@.service 0644; rc=$(( rc == 0 ? $? : rc ))
|
|
239
|
+
[[ $rc -eq 0 ]] && systemctl daemon-reload; rc=$(( rc == 0 ? $? : rc ))
|
|
240
|
+
[[ $rc -eq 0 ]] && systemctl enable --now avahi-daemon >/dev/null; rc=$(( rc == 0 ? $? : rc ))
|
|
241
|
+
[[ $rc -eq 0 ]] && docker compose -f "$PROXY_ROOT/compose.yaml" up -d; rc=$(( rc == 0 ? $? : rc ))
|
|
242
|
+
[[ $rc -eq 0 ]] && docker exec "$CADDY_CONTAINER" caddy reload --config /etc/caddy/Caddyfile; rc=$(( rc == 0 ? $? : rc ))
|
|
243
|
+
if [[ $rc -eq 0 ]]; then write_marker; rc=$?; fi
|
|
244
|
+
set -e
|
|
245
|
+
if [[ $rc -ne 0 ]]; then
|
|
246
|
+
rollback
|
|
247
|
+
rm -rf "$candidate_dir" "$backup_dir"
|
|
248
|
+
exit "$rc"
|
|
249
|
+
fi
|
|
250
|
+
rm -rf "$candidate_dir" "$backup_dir"
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
case "$ACTION" in
|
|
254
|
+
status)
|
|
255
|
+
status
|
|
256
|
+
;;
|
|
257
|
+
install|upgrade)
|
|
258
|
+
exec 9>>"$LOCK_FILE"
|
|
259
|
+
if ! flock -n 9; then
|
|
260
|
+
echo "Another host-platform operation holds the lock." >&2
|
|
261
|
+
exit 75
|
|
262
|
+
fi
|
|
263
|
+
if [[ "$ACTION" == install ]]; then install_platform; else upgrade_platform; fi
|
|
264
|
+
status
|
|
265
|
+
;;
|
|
266
|
+
*)
|
|
267
|
+
echo "Unsupported platform action: $ACTION" >&2
|
|
268
|
+
exit 2
|
|
269
|
+
;;
|
|
270
|
+
esac
|
|
271
|
+
'''
|