code wiki / _hdl_build / nx_deploy_run.nx
nx_deploy_run.nx source
↩ module page · 88 lines · 5211 B
1// nx_deploy_run.nx -- the RUNNABLE one-command safe deploy (retires the F-level 3-command manual dance).
2// The existing nx_deploy.nx encodes the safe-deploy DECISION PREDICATES (backup/atomic-swap/health/rollback)
3// but was never wired to actually run a deploy (no exec, no artifact validation). This organ is that wiring:
4// VALIDATE the artifact (fail-closed, the missing pre-flight) -> PROMOTE via the proven nx_aw_hostctl (atomic
5// rename + respawn) -> HEALTH-VERIFY (hostctl status) -> AUTO-ROLLBACK if unhealthy (restore .prev, never leave
6// the site down) -> record the outcome in the publish ledger. Composes proven organs + the gated nx_deploy_lib.
7// argv[1]=kind(0 bin/1 html/2 any) argv[2]=local_src argv[3]=hostctl_subcommand(deploy|wikideploy|galxdeploy|...).
8// Staging the artifact to the NAS (nx_aw_send/nx_pub_ship) is the prerequisite; this adds the SAFETY around the
9// promote -- the part that was missing. license_tier: ORIGINAL
10import "nx_http_health_lib.nx"
11const K_MAGIC_16384: i64 = 16384
12const K_MAGIC_16380: i64 = 16380
13
14func dp_atoi(p: *u8) -> i64 { var v: i64=0; var i: i64=0; while p[i]!=(0 as u8){ let c: i64=p[i] as i64; if c>=48{ if c<=57{ v=v*10+(c-48) } } i=i+1 } return v }
15func dep_ledger(path: *u8, status: *u8, src: *u8, sub: *u8) -> i64 {
16 let fd: i64 = sys_openat_append(path, 0x1a4)
17 if fd < 0 { return 0 - 1 }
18 dp_w(fd, "DEPLOY status=" as *u8); dp_w(fd, status); dp_w(fd, " src=" as *u8); dp_w(fd, src)
19 dp_w(fd, " target=" as *u8); dp_w(fd, sub); dp_w(fd, " epoch=" as *u8); dp_wn(fd, sys_now_realtime_sec()); dp_w(fd, "\n" as *u8)
20 sys_close(fd)
21 return 0
22}
23
24func main(argc: i64, argv: *i64) -> i64 {
25 var kind: i64 = 1
26 var src: *u8 = "web_assets/maturity.html" as *u8
27 var sub: *u8 = "deploy" as *u8
28 var health_url: *u8 = "https://nishifamily.com" as *u8
29 let ledger: *u8 = "knowledge/publish/ledger.tsv" as *u8
30 let helf: *u8 = "_offc/nx_aw_hostctl.elf" as *u8
31 if argc >= 2 { kind = dp_atoi(argv[1] as *u8) }
32 if argc >= 3 { src = argv[2] as *u8 }
33 if argc >= 4 { sub = argv[3] as *u8 }
34 if argc >= 5 { health_url = argv[4] as *u8 }
35 dp_w(1, "=== NISHI DEPLOY: validate -> promote -> health-verify -> rollback-on-fail (one safe call) ===\n" as *u8)
36 // SAFETY: require explicit args. A no-arg run is a NO-OP, so building/gating this organ never triggers a
37 // live deploy (the lesson from the live sites.elf swap: defaults must never touch production).
38 if argc < 4 {
39 dp_w(1, "usage: nx_deploy_run <kind 0bin|1html|2any> <local_src> <hostctl_sub> [health_url]\n" as *u8)
40 dp_w(1, " no-op without explicit args (so a default build never deploys).\n" as *u8)
41 sys_exit(2); return 2
42 }
43 // 1. VALIDATE-BEFORE-PROMOTE (fail-closed -- the pre-flight the predicates assumed but nothing enforced)
44 let valid: i64 = dep_validate(src, kind)
45 if valid == 0 {
46 dp_w(1, "ABORT: source failed validation (" as *u8); dp_w(1, src); dp_w(1, ") -- NOTHING promoted, site untouched\n" as *u8)
47 dep_ledger(ledger, "DEPLOY_ABORT_INVALID" as *u8, src, sub)
48 sys_exit(4); return 4
49 }
50 // 2. PROMOTE (proven atomic-swap + respawn)
51 let proargs: *i64 = sys_mmap(16) as *i64; proargs[0] = sub as i64
52 let promote_rc: i64 = dep_run(helf, proargs, 1)
53 // 3. HEALTH-VERIFY (THE REAL CHECK): after promote, does the actual PAGE load? a real HTTPS GET -> 200 + body.
54 // NOT "port bound" / "status exit 0" / a ": UP" supervisor line -- those proxies false-greened while the site
55 // was DOWN (proven live). Inline verdict dodges the hh_healthy call-miscompile found live.
56 var health_ok: i64 = 0
57 if promote_rc == 0 {
58 let pargs: *i64 = sys_mmap(16) as *i64; pargs[0] = health_url as i64
59 dep_run_capture("_offc/nx_research_fetch.elf" as *u8, pargs, 1, "/tmp/nx_deploy_health.out" as *u8)
60 let pbuf: *u8 = sys_mmap(K_MAGIC_16384)
61 let pn: i64 = dp_read("/tmp/nx_deploy_health.out" as *u8, pbuf, K_MAGIC_16380)
62 let st: i64 = hh_after(pbuf, pn, "status=" as *u8)
63 let bb: i64 = hh_after(pbuf, pn, "body_bytes=" as *u8)
64 var hh: i64 = 1
65 if st != 200 { hh = 0 }
66 if bb <= 0 { hh = 0 }
67 health_ok = hh
68 }
69 // 4. DECIDE + act
70 let action: i64 = dep_decide(valid, 0, promote_rc, health_ok)
71 if action == 0 {
72 dp_w(1, "DEPLOYED + HEALTHY (promote rc=0, status rc=0) verdict=GREEN\n" as *u8)
73 dep_ledger(ledger, "DEPLOYED" as *u8, src, sub)
74 sys_exit(0); return 0
75 }
76 if action == 1 {
77 dp_w(1, "promote rc=" as *u8); dp_wn(1, promote_rc); dp_w(1, " health=" as *u8); dp_wn(1, health_ok)
78 dp_w(1, " -> AUTO-ROLLBACK (restoring .prev, site NOT left down)...\n" as *u8)
79 let rbargs: *i64 = sys_mmap(16) as *i64; rbargs[0] = "rollback" as i64
80 let rb: i64 = dep_run(helf, rbargs, 1)
81 dp_w(1, "rolled back rc=" as *u8); dp_wn(1, rb); dp_w(1, " verdict=ROLLED-BACK\n" as *u8)
82 dep_ledger(ledger, "DEPLOY_FAIL_ROLLBACK" as *u8, src, sub)
83 sys_exit(5); return 5
84 }
85 dp_w(1, "ABORT (ship failed)\n" as *u8)
86 dep_ledger(ledger, "DEPLOY_ABORT" as *u8, src, sub)
87 sys_exit(4); return 4
88}