code wiki / _hdl_build / nx_release_master.nx

nx_release_master.nx source

↩ module page · 113 lines · 6865 B

1// nx_release_master.nx -- the RELEASE-MASTER role (verb = BLESS): the ONE owner of coordinated, safe deploys 2// so parallel workstreams STOP CRASHING the shared live site. Today the team has deploy PRIMITIVES but no role 3// owns "bless an artifact -> deploy it"; publishes bypass the arbiter lease and race the shared sink -> corrupt 4// content / dropped site. This organ closes that gap by composing the existing primitives into ONE blessed, 5// LEASED, rollback-safe, serving-aware, audited lifecycle. Per deploy, holding the resource lease the whole time: 6// 1. LEASE fl_acquire(resource) -- serialize: two workstreams can't swap the same sink at once 7// 2. BLESS gate_passed==1 precondition -- NEVER deploy an un-gated artifact (no-bless-without-pass) 8// 3. SNAPSHOT live -> live.bak -- the rollback point (never deploy without one) 9// 4. SWAP candidate -> live.new -> renameat(live.new, live) -- atomic: no half-written live file 10// 5. HEALTH rm_health(live) -- serving-aware: is the swapped artifact actually good? 11// 6. ROLLBACK on unhealthy: live.bak -> live -- restore; production survives a bad deploy 12// 7. LEDGER append the verdict to a DURABLE release ledger (what was deployed, with what outcome) 13// 8. RELEASE fl_release -- siblings proceed 14// Returns the nx_deploy verdict: DEP_ABORTED (prod untouched) / DEP_DEPLOYED / DEP_ROLLED_BACK. 15// HEALTH NOTE: this rung's rm_health is a content-marker proxy (deterministic, gate-testable). The production 16// upgrade swaps rm_health's body for nx_url_probe (a real HTTPS/TLS GET of the BARE served URL) -- same shape 17// ("is the deployed thing actually serving?"), killing the sites.elf-outage class. license_tier: ORIGINAL 18import "nx_arbiter.nx" 19import "nx_deploy.nx" 20import "nx_syscalls.nx" 21const K_MAGIC_262144: i64 = 262144 22const K_MAGIC_1280: i64 = 1280 23 24func rm_len(s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){i=i+1} return i } 25func rm_puts(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){ dst[off+i]=s[i]; i=i+1 } return off+i } 26func rm_putn(dst: *u8, off: i64, v: i64) -> i64 { 27 if v==0 { dst[off]=48 as u8; return off+1 } 28 var m: i64=v; if m<0{m=0-m} 29 let t: *u8=sys_mmap(32); var k: i64=0 30 while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } 31 var j: i64=0; while j<k { dst[off+j]=t[k-1-j]; j=j+1 } 32 return off+k 33} 34// build "base"+"suf" (NUL-terminated) into out. 35func rm_cat(base: *u8, suf: *u8, out: *u8) -> i64 { var o: i64 = rm_puts(out,0,base); o = rm_puts(out,o,suf); out[o]=0 as u8; return o } 36 37// is `path` present and non-empty? (candidate transfer check + live-existence check) 38func rm_nonempty(path: *u8) -> i64 { 39 let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 } 40 let b: *u8 = sys_mmap(8); let r: i64 = sys_read(fd, b, 1); sys_close(fd) 41 if r > 0 { return 1 } 42 return 0 43} 44// copy src -> dst (truncating). 1 ok / 0 fail. 45func rm_copy(src: *u8, dst: *u8) -> i64 { 46 let fdr: i64 = sys_openat_rd(src); if fdr < 0 { return 0 } 47 let fdw: i64 = sys_openat_wr(dst, 0x1a4); if fdw < 0 { sys_close(fdr); return 0 } 48 let buf: *u8 = sys_mmap(K_MAGIC_262144); var ok: i64 = 1; var go: i64 = 1 49 while go == 1 { 50 let r: i64 = sys_read(fdr, buf, K_MAGIC_262144) 51 if r <= 0 { go = 0 } else { let w: i64 = sys_write(fdw, buf, r); if w != r { ok = 0; go = 0 } } 52 } 53 sys_close(fdr); sys_close(fdw) 54 return ok 55} 56// does `path`'s content contain the NUL-terminated marker? (the serving-aware health proxy for this rung) 57func rm_contains(path: *u8, marker: *u8) -> i64 { 58 let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 } 59 let buf: *u8 = sys_mmap(K_MAGIC_262144); var n: i64 = 0; var go: i64 = 1 60 while go == 1 { let r: i64 = sys_read(fd, buf+n, K_MAGIC_262144-n); if r <= 0 { go = 0 } else { n = n + r; if n >= K_MAGIC_262144 { go = 0 } } } 61 sys_close(fd) 62 let ml: i64 = rm_len(marker); if ml <= 0 { return 0 } 63 var i: i64 = 0 64 while i + ml <= n { 65 var j: i64 = 0; var m: i64 = 1 66 while j < ml { if buf[i+j] != marker[j] { m = 0; j = ml } else { j = j + 1 } } 67 if m == 1 { return 1 } 68 i = i + 1 69 } 70 return 0 71} 72// SERVING-AWARE health: the swapped live artifact must be present, non-empty, and carry the serving marker. 73// (production: replace this body with nx_url_probe of the bare served URL.) 74func rm_health(live: *u8, marker: *u8) -> i64 { 75 if rm_nonempty(live) == 0 { return 0 } 76 if rm_contains(live, marker) == 0 { return 0 } 77 return 1 78} 79// append one durable release-ledger line: "verdict=<v> <tag>\n". 80func rm_ledger(ledger: *u8, verdict: i64, tag: *u8) -> i64 { 81 let fd: i64 = sys_openat_append(ledger, 0x1a4); if fd < 0 { return 0 } 82 let line: *u8 = sys_mmap(K_MAGIC_1280); var o: i64 = 0 83 o = rm_puts(line, o, "verdict=" as *u8); o = rm_putn(line, o, verdict); o = rm_puts(line, o, " " as *u8); o = rm_puts(line, o, tag) 84 line[o] = 10 as u8; o = o + 1 85 sys_write(fd, line, o); sys_close(fd) 86 return 0 87} 88 89// THE BLESSED, COORDINATED DEPLOY. Holds the lease for the whole lifecycle. Returns DEP_ABORTED/DEPLOYED/ROLLED_BACK. 90func rm_deploy(candidate: *u8, live: *u8, gate_passed: i64, resource: *u8, ledger: *u8, marker: *u8) -> i64 { 91 let lease: i64 = fl_acquire(resource, 600, 100) 92 if lease < 0 { rm_ledger(ledger, DEP_ABORTED, "LEASE-TIMEOUT" as *u8); return DEP_ABORTED } // can't coordinate -> fail-safe, don't deploy 93 // BLESS: never deploy an artifact that hasn't passed its gate. 94 if gate_passed != 1 { rm_ledger(ledger, DEP_ABORTED, "BLESS-REFUSED" as *u8); fl_release(lease); return DEP_ABORTED } 95 let transfer_ok: i64 = rm_nonempty(candidate) 96 // SNAPSHOT: back up the live artifact (the rollback point). A first-ever deploy has nothing to back up. 97 let bak: *u8 = sys_mmap(K_MAGIC_1280); rm_cat(live, ".bak" as *u8, bak) 98 var backup_taken: i64 = 1 99 if rm_nonempty(live) == 1 { backup_taken = rm_copy(live, bak) } 100 // SAFETY GATE: never touch production unless a backup exists AND the candidate is intact. 101 if dep_ready(backup_taken, transfer_ok) == 0 { rm_ledger(ledger, DEP_ABORTED, "PRECOND-FAIL" as *u8); fl_release(lease); return DEP_ABORTED } 102 // ATOMIC SWAP: stage to live.new, then rename over live (a concurrent reader never sees a half-written file). 103 let nw: *u8 = sys_mmap(K_MAGIC_1280); rm_cat(live, ".new" as *u8, nw) 104 rm_copy(candidate, nw) 105 sys_renameat(nw, live) 106 // SERVING-AWARE HEALTH + verdict. 107 let health_ok: i64 = rm_health(live, marker) 108 let verdict: i64 = dep_verdict(backup_taken, transfer_ok, health_ok) 109 if verdict == DEP_ROLLED_BACK { rm_copy(bak, live) } // restore -> production survives the bad deploy 110 rm_ledger(ledger, verdict, live) 111 fl_release(lease) 112 return verdict 113}