diff --git a/docs/v1-redeploy-changelog.md b/docs/v1-redeploy-changelog.md index 25a32ee..aba5fcc 100644 --- a/docs/v1-redeploy-changelog.md +++ b/docs/v1-redeploy-changelog.md @@ -312,3 +312,323 @@ 2. A redeploy-prep wrapper: set model-defaults default-space=metal-admin, add-model, verify the MODEL's effective default-space (the value that poisoned the last deploy), reload-spaces, run juju-spaces-check. Currently manual steps R1-R3. + +--- + +## Phase-02 vault bring-up (as-executed -- COMPLETE 2026-06-27) + +**Session:** 2026-06-27. Origin/jumphost HEAD at phase-02 start: 1a103f5 ("Create +phase-02-vault-preflight.sh"; was 68a0bd5 at the redeploy handoff). Model: openstack. +Next free numbers at section open: design decision D-056; doc fix DOCFIX-042 (verified +by grep: changelog max D-055 / DOCFIX-041; design-decisions max D-053 / DOCFIX-038). + +### Pre-flight gate (Step 2.1 verify-before-mutate) -- PASS + +Manual A-E audit on the jumphost cleared all gates; the new +`scripts/phase-02-vault-preflight.sh` then reproduced it identically with REAL jq: + + A auth jessea123 / juju-controller / model openstack; no macaroon EOF. + B machines 4/4 started. + C mysql mysql-innodb-cluster 3/3 -- /0 R/W, /1 R/O, /2 R/O, all + "Cluster is ONLINE and can tolerate up to ONE failure." (vault backend OK) + D vault vault/0 [blocked] "Vault needs to be initialized" -- FRESH + (irreversibility guard satisfied). + E census units=63 workload-error=0 agent-error(hook)=0 + blocked=2 (vault + octavia "Awaiting configure-resources") + waiting=9 active=51 unknown=1 (glance-simplestreams-sync). + +Census 63 vs the handoff's 31 is NOT a discrepancy: the handoff counted PRINCIPALS +(active=25/blocked=2/waiting=3/unknown=1); the script recurses into subordinates. +waiting 3->9 reconciles against the handoff prose (ovn-central x3 principals + ovn-chassis +x3 + ovn-chassis-octavia + neutron-api-plugin-ovn + nova-compute certs); active 25->51 is +the hacluster/mysql-router/filebeat subordinate layer. blocked=2 and unknown=1 match exactly. + +### FINDING -- live machine IDs are 0-3, NOT the handoff's 8-11 [-> DOCFIX-043] + +Committed bundle.yaml declares SYMBOLIC machine IDs "8"/"9"/"10"/"11" (machines: section, +constraints tags=openstack). Juju treats bundle machine keys as PLACEHOLDERS, not real IDs; +deployed into a fresh model they map in order to real IDs 0/1/2/3. Live (confirmed by the +preflight script's machine display lines): + + real m0 = openstack0 = 10.12.12.40 (bundle "8") control-only, 7 LXD: 0/lxd/0..6 + real m1 = openstack1 = 10.12.12.41 (bundle "9") + real m2 = openstack3 = 10.12.12.43 (bundle "10") + real m3 = openstack2 = 10.12.12.42 (bundle "11") holds vault/0 (juju-f5a310-3-lxd-5) + +The openstack2/openstack3 <-> m3/m2 "swap" is MAAS tag-based allocation (hosts pinned by +tag=openstack, NOT by system_id), so the host->machine binding floats per deploy. +nova-compute `to: ["9","10","11"]` (symbolic) therefore landed on real m1/m2/m3 = +openstack1/openstack3/openstack2, leaving m0/openstack0 control-only -- CONSISTENT with the +handoff's intended role split. ceph `to: ["8","9","10","11"]` -> all four real machines. + +IMPACT: zero on phase-02 (vault/0 resolves by unit name). The handoff text "= bundle +machines 8/9/10/11" is stale on LIVE ids. RULE to fold into the runbook: resolve everything +by unit name / hostname / CIDR, NEVER by machine ID; document the bundle-symbolic vs +live-real mapping so a future operator does not mistake it for a deploy fault. Phase-03 +host-role verify (open-item 2) confirms which units run on which machine definitively. + +### DELIVERABLE -- scripts/phase-02-vault-preflight.sh (committed 1a103f5) [-> DOCFIX-042] + +Read-only verify-before-mutate gate packaging the A-E audit into one re-runnable command. +Mutates NOTHING; the vault init/unseal/authorize MUTATIONS stay gated human steps (item-8 +principle: scripts own the deterministic/read-only/repeated; the human gate owns the +consequential mutation + secret custody). Gates: B all machines started; C mysql 3 units / +all active+ONLINE / exactly 1 R/W; D vault fresh ([blocked] "needs to be initialized" -- +REFUSES and escalates if not, since a non-fresh vault may already hold keys); E zero +workload-error AND zero agent-error(hook), subordinates included. Exit 0 PROCEED / 1 HOLD / +2 precondition. Sources lib-net.sh (need_jq); whoami-direct-first so a stale-macaroon prompt +reaches the tty before captured calls; single juju-status snapshot; one jq metrics pass +(eval'd key=value); dynamic lookups, nothing host/IP/ID hardcoded. ASCII+LF, bash -n clean. + +Testing: shellcheck + jq both ABSENT from Claude's sandbox -> behavior-tested with juju+jq +shims across 5 fixtures (1 healthy + 4 single-fault: vault-already-initialized D, mysql +OFFLINE C, hook-failure E, machine-down B); each produced the correct exit code and gate +attribution. jq metrics algorithm mirrored/validated in Python. REAL-jq/REAL-data +confirmation on the jumphost first run reproduced the manual audit EXACTLY (units=63, +errors 0, PROCEED, EXIT=0); Windows -> GitHub Desktop -> push -> jumphost-pull preserved +LF/ASCII/parse. FOLD INTO phase-02 do-doc: invoke this script as the Step 2.1 pre-flight gate. + +### DELIVERABLE -- tests/phase-02/ regression harness (staged; commit pending) + +run-tests.sh + make_fixtures.py + fakebin/{juju,jq} shims. Offline regression for the +preflight script: drives the REAL script's decision/exit logic against the 5 generated +fixtures; touches NO live infra (fake juju emits fixtures, fake jq mirrors the metrics in +Python); runs anywhere with python3 + bash (no real jq needed); re-asserts shim exec bits so +the Windows -> git round trip dropping them will not break it. Sandbox run: ALL PASS / exit 0. +Target paths: tests/phase-02/{run-tests.sh, make_fixtures.py, fakebin/juju, fakebin/jq}. + +### Step 2.1 delivery split [-> DOCFIX-042] + +The do-doc presents Step 2.1's in-session block as one paste (env-setup; vault status; +vault operator init | tee; grep -c; grep -q). Split at the verify/mutate boundary into two +gated pastes: + 2.1a (read-only verify): `export VAULT_ADDR...; umask 077; mkdir -p ~/vault-init` + + `vault status 2>&1 | grep -E 'Initialized|Sealed|Storage Type|HA Enabled' || true` + 2.1b (irreversible) : `vault operator init -key-shares=5 -key-threshold=3 2>&1 | tee + ~/vault-init/init.txt` + `grep -c '^Unseal Key' ...` + `grep -q '^Initial Root Token:' ...` +Rationale: the `vault status` line exists to be OBSERVED before the irreversible init; a +single paste runs init before it can be read, defeating verify-before-mutate. Commands are +verbatim/unchanged -- only the paste boundary moves. Amend phase-02 do-doc Step 2.1 to +present 2.1a/2.1b as two gated pastes. + +### Step 2.1a verify -- FRESH confirmed (2026-06-27) + +Session opened on vault/0: `juju ssh -m openstack vault/0` -> ubuntu@juju-f5a310-3-lxd-5 +(= real machine 3 = openstack2, LXD container 5). 2.1a output: + + Initialized false uninitialized; safe to init + Sealed true + Storage Type mysql vault-on-mysql backend (mysql-innodb-cluster) + HA Enabled false CORRECT for vault-on-mysql (R3); NOT a defect + +Vault's own status agrees with the Juju workload-status. Cleared for 2.1b (vault init). + +### Step 2.1b vault init -- EXECUTED 2026-06-27 (irreversible one-shot done) + +`vault operator init -key-shares=5 -key-threshold=3 2>&1 | tee ~/vault-init/init.txt` ran +once. Token gate: `grep -q '^Initial Root Token:'` -> TOKEN_OK (root token line captured in +init.txt). Unseal-Key count gate (`grep -c '^Unseal Key'` MUST = 5): = 5 (operator confirmed); not +inferred. Operator confirmed all key material (5 shares + root token) saved OFF cloud/host; +~/vault-init/init.txt on the unit is the only on-unit copy (dies with the unit). + +Post-init expected state: vault Initialized true / Sealed true (init does NOT unseal a +vault-on-mysql; unseal is the separate 2.2 step). + +### Step 2.2 unseal -- EXECUTED 2026-06-27 +3-of-5 via `vault operator unseal` (no arg, vault's own hidden prompt; keys never on argv/ +history -- L4). Final `vault status`: Initialized true / Sealed false / Storage Type mysql / +HA Enabled false (HA false correct for single-unit vault-on-mysql -- R3). Vault is now +initialized AND unsealed. v1 policy: MANUAL unseal is the v1 standard -- re-run 3-of-5 at +the hidden prompt after any vault-unit reboot (auto-unseal via transit/KMS not configured +in v1; D-011.6 re-confirms in phase-08). + +### Step 2.3 authorize-charm + generate-root-ca -- EXECUTED 2026-06-27 +Short-lived child token (10m TTL) minted in vault/0 via hidden `read -s` root token + +`vault token create -ttl=10m -field=token` (NOT the root token -- juju op-log persists +action params; DOCFIX-011 param=`token`). `juju run vault/leader authorize-charm token=...` +then `juju run vault/leader generate-root-ca` (REQUIRED -- DOCFIX-014) both completed; child +token entered via hidden `read -s` on the jumphost too (narrows, does not eliminate, op-log +exposure). Root CA PEM emitted ("Vault Root Certificate Authority (charm-pki-local)") and +copied OFF cloud. + +Result (juju status vault): vault 1.8.8 active "Unit is ready (active: true, mlock: +disabled)"; vault/0 active/idle on 3/lxd/5 (= machine 3 = openstack2; container 10.12.12.106); +vault-mysql-router/0 active. The "Missing CA cert" block cleared STRAIGHT to active -- +validates DOCFIX-014. `mlock: disabled` is expected/benign for container vault (no IPC_LOCK). + +### PHASE-02 EXIT GATE -- MET (2026-06-27) +- Vault Initialized true / Sealed false; 5 shares + root token saved OFF cloud/host. [DONE] +- vault/0 active/idle; root CA generated (the cloud's PKI anchor); PEM saved off-cloud. [DONE] +- Narrow cert cascade to consumers (ovn-central x3, ovn-chassis x3, ovn-chassis-octavia, + neutron-api-plugin-ovn, barbican-vault) ACTIVE/proceeding -- watched + accepted phase-03. [IN PROGRESS] +- POST-INIT SWEEP -- cascade SETTLED 2026-06-27 (full juju status, two-image capture): + all apps active EXCEPT octavia (blocked "Awaiting ... configure-resources" -- EXPECTED, + phase-05) and glance-simplestreams-sync (unknown -- expected sync state). Cert consumers + now active: ovn-central x3 (leader ovnnb_db/ovnsb_db; northd active), ovn-chassis x3, + ovn-chassis-octavia, neutron-api-plugin-ovn, barbican + barbican-vault. NO errors / NO + hook failures. + * magnum/0 active "Unit is ready" (1/lxd/2, 10.12.12.115; public port 9511/tcp) -- the + phase-01 pre-vault 9501 loopback BLOCK self-resolved at the TLS cutover, as predicted. + Definitive *:9501 not-loopback bind check via read-only `ss` on magnum/0 (juju exec): + 9501 -> `*:9501` (all-interfaces; NOT 127.0.0.1); 9511 -> `0.0.0.0:9511` + `*:9511`. + NOT loopback -> escalation condition NOT met; the phase-01 9501 line was the expected + pre-vault posture, NOT a defect. Settle also confirmed at principal level via + deploy-watch.sh: active=29 / blocked=1 (octavia) / unknown=1 (glance-ss-sync) = 31 + principals -- reconciles with the handoff's original 31. **PHASE-02 EXIT GATE CLOSED.** + * keystone/0 "PO (broken): Unit is ready" -- UNCHANGED (FINDING-1; expected; no regression). + * Host-role confirm (open-item 2): nova-compute on machines 1/2/3 = openstack1/openstack3/ + openstack2; openstack0 (m0) carries NO nova-compute / NO ovn-chassis (control-only, 7 + LXD: 0/lxd/0..6). CONFIRMS the bundle-symbolic->live-real machine-ID remap (DOCFIX-043) + and the intended 3-compute/1-control split. Open design Q remains (Jesse's call, not + phase-02): openstack0's provider MAC is still in ovn-chassis bridge-interface-mappings + though no chassis runs there -- trim it (3-compute/1-control) vs add openstack0 to + nova-compute `to:`. + +PHASE-02 COMPLETE -- discrete vault mutations done. Cascade-settle + the post-init sweep are +the opening activities of phase-03 (runbooks/phase-03-core-verify.md). + +### Next-free numbers after this append +Design decision: D-056. Doc fix: DOCFIX-044. + DOCFIX-042 = phase-02 Step 2.1 split (2.1a verify / 2.1b init) + invoke preflight script. + DOCFIX-043 = document bundle-symbolic vs live-real machine-ID remap + MAAS tag-allocation + host swap; resolve by unit/hostname/CIDR, never by machine ID. + +--- + +## Phase-03 core verify (as-executed -- IN PROGRESS) + +**Session:** 2026-06-27 (continues). Next free numbers at section open: D-056; DOCFIX-044. + +### CORRECTION (DOCFIX-044) -- phase-02 preflight hook-error key wrong (agent-status -> juju-status) + +scripts/phase-02-vault-preflight.sh (committed 1a103f5) computed the agent/hook-error count +as `select(."agent-status".current=="error")`. In `juju status --format json` a UNIT carries +`workload-status` + `juju-status` (the agent state: idle/executing/error); there is NO +`agent-status` key on units. Confirmed against two authoritative consumers: deploy-watch.sh:43 +(`.value."juju-status".current=="error"` for units) and the phase-03 do-doc acceptance walk +(`u.get('juju-status')`). So the `ae` (hook-failed) half of the E gate was INERT -- it read a +nonexistent key and always returned 0; a real hook failure would NOT have been caught. +- Decision impact this run: NONE. The cloud had zero errors of either kind, so 0/0 was the + correct verdict regardless; the workload-error half (workload-status, correct key) worked. + The defect is a latent false-negative, not a wrong decision. +- Why the harness missed it: the phase-02 mock fixtures + jq shim used the SAME wrong key, so + the regression validated internal consistency against a fiction, not the real schema. + LESSON (fold into conventions): mock fixtures MUST mirror the real `juju status` JSON schema; + a fixture that agrees with the script's bug hides the bug. The phase-03 harness surfaced this + because its fixtures (built from the do-doc's juju-status walk) disagreed with the bad key. +- FIX: phase-02 preflight `ae` -> `select(."juju-status".current=="error")` + an anti-regression + header note. Harness corrected (fixtures + shim now juju-status); the FAIL-E case now sets + juju-status.current=error and only passes because the key is right. RE-COMMIT REQUIRED over + 1a103f5. Re-running on the (healthy) cloud still yields PROCEED; the fix matters for catching + FUTURE hook failures. + +### Step 3.1 core verify -- PASS (2026-06-27) +3.1a acceptance walk: 2 non-active/idle, BOTH expected -- glance-simplestreams-sync/0 (unknown, +image-sync state) + octavia/0 (blocked "Awaiting configure-resources", D-021). No TLS consumer +stuck. 3.1b haproxy backend-health sweep (D-045/DOCFIX-031): ZERO DOWN across all principal +units -- the plaintext-vs-SSL backend failure did NOT recur this cycle (cert cascade + haproxy +reload state healthy). No remediation needed. + +### DELIVERABLE -- scripts/phase-03-core-verify.sh + scripts/phase03_accept_walk.py + tests/phase-03/ +Read-only Step 3.1 gate packaging 3.1a (acceptance walk) + 3.1b (haproxy sweep). HARDENED beyond +the do-doc's bare count gate: phase03_accept_walk.py gates on IDENTITY -- only octavia +(blocked/configure-resources) and glance-simplestreams-sync (unknown/waiting) may be +non-active/idle; a different app blocked also yields count==2 yet correctly FAILS. The do-doc's +inline python-in-bash acceptance walk is moved to its own tested .py (convention); the haproxy +sweep's unit list comes from jq on the captured snapshot (no second juju call, no inline python). +Mutations stay gated: a DOWN backend's `haproxy -c` + `systemctl reload` is a per-unit human step; +Step 3.2 (admin-openrc) and 3.3 (Horizon) too. tests/phase-03/: unit-tests the .py +(pass/unexpected-blocked) + behavior-tests the .sh with juju+jq shims (settled / unexpected-unit / +injected haproxy-DOWN). ALL PASS, offline, no real jq. Real-jq/real-data: 3.1a+3.1b already ran by +hand this session and PASSED; the script reproduces them. + +### Next-free numbers after this append +Design decision: D-056. Doc fix: DOCFIX-045. + DOCFIX-044 = phase-02 preflight hook-error key agent-status -> juju-status (+ harness fix). + +### Artifact validation -- all four confirmed (2026-06-27, post-commit, on jumphost) +1. tests/phase-02/run-tests.sh: ALL PASS / 0 (corrected FAIL-E now drives juju-status.current=error). +2. tests/phase-03/run-tests.sh: ALL PASS / 0 (accept-walk + haproxy gate incl injected-DOWN). +3. scripts/phase-03-core-verify.sh LIVE: PROCEED / 0 -- accept walk 2 expected (glance-ss unknown, + octavia blocked); haproxy sweep ZERO DOWN across 31 principal units. Reproduces manual 3.1. +4. scripts/phase-02-vault-preflight.sh LIVE: HOLD / 1 on gate D ONLY (vault/0 now [active], + units=1 fresh=0) -- irreversibility guard correctly refusing re-init of a live vault. B/C/E pass. + DOCFIX-044 closed with REAL-DATA confirmation: the corrected `ae` ran live and reported + agent-error(hook)=0 via juju-status (post-settle census: units=63, workload-error=0, + agent-error=0, blocked=1 [octavia], waiting=0, active=61, unknown=1). + +### Step 3.2 build admin-openrc -- PASS (2026-06-27) +Vault root CA pulled via get-root-ca --format json + jq (DOCFIX-021 path): CN=Vault Root +Certificate Authority (charm-pki-local), valid 2026-06-27 -> 2036-06-24. Admin password from +get-admin-password --format json; admin project DISCOVERED via the scope-test loop (DOCFIX-022; +value recorded in ~/admin-openrc OS_PROJECT_NAME, not captured this turn). ~/admin-openrc written +(chmod 600); `openstack endpoint list` authenticated and returned the full catalog -> confirms a +SCOPED token (the gate). Endpoints IP-only on the three D-052 planes: + public -> provider VIP 10.12.4.5x + internal -> metal-internal 10.12.12.5x + admin -> metal-admin 10.12.8.5x (keystone admin on :35357) +VIP octets match bundle: keystone .50, barbican .51, cinderv3 .52, glance .53, magnum .54, +neutron .55, nova .56, octavia .57, placement .59, radosgw/s3/swift .60:443. + +### DOCFIX-045 -- phase-03 do-doc 3.2 gate text is pre-D-052 (internal plane) +The 3.2 GATE text reads "internal+admin on the metal VIP .8.5x" -- predates D-052's dedicated +metal-internal plane. LIVE (correct) shows INTERNAL on metal-internal 10.12.12.5x and ADMIN on +metal-admin 10.12.8.5x (bundle triple-VIP "10.12.4.5x 10.12.8.5x 10.12.12.5x" + D-052 internal +binding). Amend the 3.2 gate to: public provider .4.5x; internal metal-internal .12.5x; admin +metal-admin .8.5x; keystone admin :35357. +ALSO (value drift, non-blocking): gss image-stream endpoint is HTTP on metal 10.12.8.226 this +deploy (do-doc note said .172) -- the simplestreams image-stream IP is per-deploy; note as +dynamic, do not hardcode. s3/swift on radosgw VIP .60:443 -- re-check vs radosgw :80 listener +during any Swift/S3 smoke (carried-forward do-doc note). + +### Step 3.3 Horizon nginx reverse proxy -- PASS (2026-06-27) +v1 Horizon = PLAIN-HTTP reverse-proxy leg per D-044 (authoritative, adopted 2026-06-17). NO nginx +edit was needed: the existing /etc/nginx/sites-available/openstack vhost on the nginx host +(10.12.4.7) already proxies `listen 81` -> `proxy_pass http://10.12.4.58:80` at the CURRENT +dashboard provider VIP (.58 confirmed vs bundle), with `proxy_set_header Host $http_host` (B5 +ALLOWED_HOSTS) + X-Forwarded-*. No proxy_ssl_* applied (that is the Roosevelt root-fix, not v1). +The vhost's "Main LXD UI" comment is a stale mislabel (it is the Horizon proxy) -- cosmetic, +flag for consolidation cleanup; left untouched to avoid mutating a working MAAS-fronting host. +Live scheme probes (decisive, verify-before-mutate, from both jumphost and nginx host): + jumphost->.58 https rc=000 FAIL(35) | http rc=200 + nginx->.58 https rc=000 FAIL(35) | http rc=200 + s_client .58:443 -> CONNECTED but "no peer certificate available" (certless :443 listener) + => dashboard serves Horizon over HTTP :80; :443 is an unused, certless haproxy frontend. +The certless :443 is EXPECTED under D-044 (v1 does not use dashboard HTTPS). The bundle's +openstack-dashboard:certificates<->vault:certificates relation provisions a cert, but the v1 +plain-HTTP leg never serves it. NOT a v1 defect; the Roosevelt DNS + FQDN-cert workstream is the +end-to-end HTTPS root-fix. The earlier dashboard-SAN probe was therefore moot (proxy_ssl_name is +a Roosevelt concern, not v1). +Steps executed: + A (nginx host, read-only): curl -sI http://127.0.0.1:81/horizon/ -> HTTP/1.1 302 Found (login + redirect). GATE A met. + B (jumphost, the one v1 mutation, PER-REBUILD, verbatim do-doc): juju ssh + openstack-dashboard/leader wrote _99_internal_http_cookies.py (CSRF_COOKIE_SECURE=False + + SESSION_COOKIE_SECURE=False, ASCII-only) + systemctl reload apache2. Clean. + C (jumphost, verify adapted https->http per DOCFIX-046): csrftoken Set-Cookie present, no Secure + attribute -> "OK: csrftoken not Secure". GATE C met. + D: external browser login over http://10.17.11.246:81/horizon/ SUCCEEDED -- Horizon Overview + renders as admin_domain/admin, fresh-cloud quotas 0-of-N. "Not secure" address bar = expected + (plain-HTTP client leg, D-044). GATE D met. +PHASE-03 EXIT GATE MET: 3.1 PASS (accept walk 2-expected + haproxy ZERO DOWN across 31 principals), +3.2 PASS (admin-openrc + scoped catalog), 3.3 PASS (Horizon reachable + login). + +### DOCFIX-046 -- phase-03 do-doc 3.3 carries an abandoned HTTPS-upstream edit set (contradicts D-044) +The phase-03 do-doc Step 3.3 body contains BOTH (a) an HTTPS-upstream edit set -- proxy_pass +https://10.12.4.58:443, proxy_ssl_verify on, proxy_ssl_trusted_certificate, proxy_ssl_name + a +dashboard-cert SAN discovery -- AND (b) the real "the upstream stays PLAIN HTTP (as-built)" line. +These contradict. D-044 (authoritative) resolves it: v1 is the plain-HTTP leg; the proxy_ssl_name +/ HTTPS-upstream handling is the ROOSEVELT root-fix, not v1. The (a) block, if applied on the +testcloud, would repoint nginx at the certless :443 and BREAK Horizon (curl 35) -- exactly what +the live probes confirmed would happen. +Also: the do-doc's D-044 VERIFY command uses `curl --cacert ... https://10.12.4.58/...` -- same +HTTPS assumption; it fails (rc=000/35) against the v1 HTTP dashboard. Adapt to +`curl ... http://10.12.4.58/horizon/auth/login/`. +FIX (for completion consolidation): rewrite 3.3 to the v1 plain-HTTP path (verify the existing +vhost points at the current dashboard VIP over http:80; no proxy_ssl_*; apply the cookie override; +verify over http); move the proxy_ssl_*/SAN block verbatim into a clearly-marked "Roosevelt +root-fix (DNS+FQDN certs)" subsection so a future operator does not apply it on the testcloud; fix +the verify command https->http. Cross-ref D-044. Also fix the stale "Main LXD UI" vhost comment. + +### Next-free numbers +Design decision: D-056. Doc fix: DOCFIX-047.