diff --git a/bundle.yaml b/bundle.yaml index 3757116..528007f 100644 --- a/bundle.yaml +++ b/bundle.yaml @@ -123,7 +123,7 @@ num_units: 1 # 3 on Roosevelt (D-009) to: [lxd:8] options: - vip: 10.12.4.229 + vip: "10.12.4.229 10.12.8.229" os-public-hostname: keystone.omega.dc0.vr0.cloud.neumatrix.local bindings: *api-bindings constraints: arch=amd64 @@ -143,7 +143,7 @@ num_units: 1 to: [lxd:11] options: - vip: 10.12.4.228 + vip: "10.12.4.228 10.12.8.228" os-public-hostname: glance.omega.dc0.vr0.cloud.neumatrix.local bindings: *api-bindings constraints: arch=amd64 @@ -173,7 +173,7 @@ options: console-access-protocol: novnc network-manager: Neutron - vip: 10.12.4.232 + vip: "10.12.4.232 10.12.8.232" os-public-hostname: nova.omega.dc0.vr0.cloud.neumatrix.local bindings: *api-bindings constraints: arch=amd64 @@ -206,7 +206,7 @@ num_units: 1 to: [lxd:11] options: - vip: 10.12.4.235 + vip: "10.12.4.235 10.12.8.235" os-public-hostname: placement.omega.dc0.vr0.cloud.neumatrix.local bindings: *api-bindings constraints: arch=amd64 @@ -229,7 +229,7 @@ enable-ml2-port-security: true flat-network-providers: physnet1 neutron-security-groups: true - vip: 10.12.4.231 + vip: "10.12.4.231 10.12.8.231" os-public-hostname: neutron.omega.dc0.vr0.cloud.neumatrix.local bindings: *api-bindings constraints: arch=amd64 @@ -284,7 +284,7 @@ options: block-device: None glance-api-version: 2 - vip: 10.12.4.226 + vip: "10.12.4.226 10.12.8.226" os-public-hostname: cinder.omega.dc0.vr0.cloud.neumatrix.local bindings: *api-bindings constraints: arch=amd64 @@ -351,7 +351,7 @@ to: [lxd:10] options: debug: "false" - vip: 10.12.4.234 + vip: "10.12.4.234 10.12.8.234" os-public-hostname: horizon.omega.dc0.vr0.cloud.neumatrix.local bindings: *api-bindings constraints: arch=amd64 @@ -382,7 +382,7 @@ # juju deploy ./bundle.yaml \ # --overlay overlays/vr0-dc0-testcloud.yaml \ # --overlay overlays/octavia-pki.yaml - vip: 10.12.4.233 + vip: "10.12.4.233 10.12.8.233" os-public-hostname: octavia.omega.dc0.vr0.cloud.neumatrix.local bindings: *api-bindings constraints: arch=amd64 @@ -413,7 +413,7 @@ to: [lxd:11] options: openstack-origin: *openstack-origin - vip: 10.12.4.224 + vip: "10.12.4.224 10.12.8.224" os-public-hostname: barbican.omega.dc0.vr0.cloud.neumatrix.local bindings: *api-bindings constraints: arch=amd64 @@ -446,7 +446,7 @@ options: openstack-origin: *openstack-origin region: RegionOne - vip: 10.12.4.230 + vip: "10.12.4.230 10.12.8.230" os-public-hostname: magnum.omega.dc0.vr0.cloud.neumatrix.local bindings: *api-bindings constraints: arch=amd64 diff --git a/bundle.yaml.bak-20260529-030547 b/bundle.yaml.bak-20260529-030547 new file mode 100644 index 0000000..3757116 --- /dev/null +++ b/bundle.yaml.bak-20260529-030547 @@ -0,0 +1,625 @@ +# ============================================================ +# Caracal 2024.1 — VR0 DC0 Omega Cloud testcloud rebuild bundle +# ============================================================ +# Generated: 2026-05-22 +# Replaces: bundle-pre-destroy.yaml (Bobcat 2023.2) +# Charm channels: verified against Charmhub 2026-05-22 (see Caracal_Rebuild handoff D-002) +# Bindings: public:provider, else:metal for API charms; all-metal for backend charms +# HA chain: ALL hacluster subordinates + vip configs + :ha relations COMMENTED OUT +# until NetBox VIP allocations land in 10.12.4.224-.254 +# Vault HA: etcd backend + easyrsa CA bootstrap live; vault-hacluster commented +# Magnum: Layer A only — CAPI driver graft is Layer B (runbooks/04a + 05) +# Octavia: lb-mgmt PKI options present but VALUES commented out — source from +# either Bobcat backup (~/backups/pre-caracal-destroy-2026-05-22/) +# or fresh octavia-cert-runbook (TBD) +# OVN tunnels: remain on metal space (Bobcat-proven); enp8s0 3_data v2 improvement +# Resources: omitted — let charms use latest available resource revisions +# ============================================================ + +name: vr0-dc0-omega-caracal-testcloud +description: | + Charmed OpenStack Caracal (2024.1) on Ubuntu 22.04 LTS (Jammy) deployed via Juju 3.6 bundle + against MAAS-managed VMs (openstack0-3, virsh). + Decisions referenced (see Caracal_Rebuild handoff): + D-001 Path 2A (Juju-bundle paradigm) + D-002 channel matrix + D-003 Option B (provider /22 carries FIPs + API VIPs) + D-005 Ceph Squid + D-006 Vault HA via etcd + easyrsa + D-007 Magnum Layer A + Layer B graft + D-019 (supersedes D-008) Designate deferred to v2 + D-009 hacluster subordinates (decorative on testcloud) + D-016 IPv4-only v1 + D-018 MAAS-release-direct teardown + +default-base: ubuntu@22.04/stable + +variables: + # ----- UCA pocket + Ceph source ---------------------------------------------- + openstack-origin: &openstack-origin cloud:jammy-caracal + ceph-source: &ceph-source cloud:jammy-caracal + + # ----- Bindings for external-API-facing charms (public on provider) ---------- + api-bindings: &api-bindings + "": metal + public: provider + + # ----- Bindings for backend / internal-only charms (all metal) --------------- + # Used for ceph-mon (Ceph public network IS metal, not OpenStack public), + # ceph-osd, ovn-central, mysql-innodb-cluster, rabbitmq-server, nova-compute, etc. + internal-bindings: &internal-bindings + "": metal + +machines: + "8": + constraints: arch=amd64 tags=openstack + "9": + constraints: arch=amd64 tags=openstack + "10": + constraints: arch=amd64 tags=openstack + "11": + constraints: arch=amd64 tags=openstack + +applications: + + # ===================================================================== + # Datastores: MySQL InnoDB Cluster, RabbitMQ, Vault + HA backend + # ===================================================================== + + mysql-innodb-cluster: + charm: mysql-innodb-cluster + channel: 8.0/stable + num_units: 3 + to: [lxd:8, lxd:9, lxd:10] + bindings: *internal-bindings + constraints: arch=amd64 + + rabbitmq-server: + charm: rabbitmq-server + channel: 3.9/stable + num_units: 1 + to: [lxd:10] + bindings: *internal-bindings + constraints: arch=amd64 + + vault: + charm: vault + channel: 1.8/stable + num_units: 1 # 3 on Roosevelt (D-009) + to: [lxd:11] + bindings: *internal-bindings + constraints: arch=amd64 + + vault-mysql-router: + charm: mysql-router + channel: 8.0/stable + bindings: *internal-bindings + + etcd: + charm: etcd + channel: latest/stable # support charm; not in OS delivery table + num_units: 3 # Vault HA backend (D-006) + to: [lxd:8, lxd:9, lxd:10] + bindings: *internal-bindings + constraints: arch=amd64 + # Note: etcd charm has its OWN `channel:` config option (controls etcd snap). + # Leaving at charm default; revisit if a specific etcd binary version is needed. + + easyrsa: + charm: easyrsa + channel: latest/stable + num_units: 1 # One-shot CA for etcd bootstrap (D-006) + to: [lxd:8] + bindings: *internal-bindings + constraints: arch=amd64 + + # ===================================================================== + # Identity: Keystone + # ===================================================================== + + keystone: + charm: keystone + channel: 2024.1/stable + num_units: 1 # 3 on Roosevelt (D-009) + to: [lxd:8] + options: + vip: 10.12.4.229 + os-public-hostname: keystone.omega.dc0.vr0.cloud.neumatrix.local + bindings: *api-bindings + constraints: arch=amd64 + + keystone-mysql-router: + charm: mysql-router + channel: 8.0/stable + bindings: *internal-bindings + + # ===================================================================== + # Image: Glance + simplestreams-sync + # ===================================================================== + + glance: + charm: glance + channel: 2024.1/stable + num_units: 1 + to: [lxd:11] + options: + vip: 10.12.4.228 + os-public-hostname: glance.omega.dc0.vr0.cloud.neumatrix.local + bindings: *api-bindings + constraints: arch=amd64 + + glance-mysql-router: + charm: mysql-router + channel: 8.0/stable + bindings: *internal-bindings + + glance-simplestreams-sync: + charm: glance-simplestreams-sync + channel: 2024.1/stable + num_units: 1 + to: [lxd:8] + bindings: *internal-bindings + constraints: arch=amd64 + + # ===================================================================== + # Compute: Nova cloud-controller + compute + Placement + # ===================================================================== + + nova-cloud-controller: + charm: nova-cloud-controller + channel: 2024.1/stable + num_units: 1 + to: [lxd:11] + options: + console-access-protocol: novnc + network-manager: Neutron + vip: 10.12.4.232 + os-public-hostname: nova.omega.dc0.vr0.cloud.neumatrix.local + bindings: *api-bindings + constraints: arch=amd64 + + nova-compute: + charm: nova-compute + channel: 2024.1/stable + num_units: 3 + to: ["9", "10", "11"] + options: + config-flags: default_ephemeral_format=ext4 + enable-live-migration: true + enable-resize: true + migration-auth-type: ssh + resume-guests-state-on-host-boot: true + virt-type: qemu # Testcloud nested-KVM; Roosevelt will use 'kvm' + bindings: *internal-bindings + constraints: arch=amd64 + storage: + ephemeral-device: loop,10240M + + ncc-mysql-router: + charm: mysql-router + channel: 8.0/stable + bindings: *internal-bindings + + placement: + charm: placement + channel: 2024.1/stable + num_units: 1 + to: [lxd:11] + options: + vip: 10.12.4.235 + os-public-hostname: placement.omega.dc0.vr0.cloud.neumatrix.local + bindings: *api-bindings + constraints: arch=amd64 + + placement-mysql-router: + charm: mysql-router + channel: 8.0/stable + bindings: *internal-bindings + + # ===================================================================== + # Networking: Neutron + OVN + # ===================================================================== + + neutron-api: + charm: neutron-api + channel: 2024.1/stable + num_units: 1 + to: [lxd:9] + options: + enable-ml2-port-security: true + flat-network-providers: physnet1 + neutron-security-groups: true + vip: 10.12.4.231 + os-public-hostname: neutron.omega.dc0.vr0.cloud.neumatrix.local + bindings: *api-bindings + constraints: arch=amd64 + + neutron-api-mysql-router: + charm: mysql-router + channel: 8.0/stable + bindings: *internal-bindings + + neutron-api-plugin-ovn: + charm: neutron-api-plugin-ovn + channel: 2024.1/stable + + ovn-central: + charm: ovn-central + channel: 24.03/stable + num_units: 3 + to: [lxd:8, lxd:9, lxd:10] + bindings: *internal-bindings + constraints: arch=amd64 + + # ovn-chassis: subordinate to nova-compute. MAC-based bridge-interface-mappings + # captured from MAAS 2026-05-22 (Bobcat used hardcoded 'enp1s0' — anti-pattern fix). + # The charm picks whichever MAC is found locally per unit; non-matching MACs ignored. + ovn-chassis: + charm: ovn-chassis + channel: 24.03/stable + options: + ovn-bridge-mappings: physnet1:br-ex + bridge-interface-mappings: >- + br-ex:52:54:00:3d:fd:54 + br-ex:52:54:00:9d:63:77 + br-ex:52:54:00:89:7f:ce + br-ex:52:54:00:99:fc:c2 + + # ovn-chassis-octavia: separate ovn-chassis app, subordinate to octavia. + # No bridge-interface-mappings — matches Bobcat-proven pattern (Octavia mgmt + # traffic rides Neutron tenant overlay; no external physnet bridge needed here). + ovn-chassis-octavia: + charm: ovn-chassis + channel: 24.03/stable + + # ===================================================================== + # Block Storage: Cinder + cinder-ceph + # ===================================================================== + + cinder: + charm: cinder + channel: 2024.1/stable + num_units: 1 + to: [lxd:9] + options: + block-device: None + glance-api-version: 2 + vip: 10.12.4.226 + os-public-hostname: cinder.omega.dc0.vr0.cloud.neumatrix.local + bindings: *api-bindings + constraints: arch=amd64 + storage: + block-devices: loop,10240M + + cinder-mysql-router: + charm: mysql-router + channel: 8.0/stable + bindings: *internal-bindings + + cinder-ceph: + charm: cinder-ceph + channel: 2024.1/stable + + # ===================================================================== + # Ceph: mon + osd + radosgw (Squid release per D-005) + # ===================================================================== + + ceph-mon: + charm: ceph-mon + channel: squid/stable + num_units: 3 + to: [lxd:8, lxd:9, lxd:10] + options: + source: *ceph-source + expected-osd-count: 4 + monitor-count: 3 + bindings: *internal-bindings # Ceph 'public' here = clients on metal, NOT OS public API + constraints: arch=amd64 + + ceph-osd: + charm: ceph-osd + channel: squid/stable + num_units: 4 + to: ["8", "9", "10", "11"] + options: + source: *ceph-source + osd-devices: /dev/vdb # libvirt-attached, MAAS-untracked, wiped 2026-05-22 + bindings: *internal-bindings + constraints: arch=amd64 tags=openstack + + ceph-radosgw: + charm: ceph-radosgw + channel: squid/stable + num_units: 1 + to: [lxd:8] + options: + source: *ceph-source + # v2-deferred: ceph-radosgw HA deferred to v2 per workstream-2 decision. + # vip slot 10.12.4.225 reserved for ceph-radosgw VIP in v2. + # See also commented ceph-radosgw-hacluster app + :ha relation below. + bindings: *api-bindings # radosgw IS externally-facing (S3/Swift API) + constraints: arch=amd64 + + # ===================================================================== + # Dashboard: openstack-dashboard (Horizon) + # ===================================================================== + + openstack-dashboard: + charm: openstack-dashboard + channel: 2024.1/stable + num_units: 1 + to: [lxd:10] + options: + debug: "false" + vip: 10.12.4.234 + os-public-hostname: horizon.omega.dc0.vr0.cloud.neumatrix.local + bindings: *api-bindings + constraints: arch=amd64 + + dashboard-mysql-router: + charm: mysql-router + channel: 8.0/stable + bindings: *internal-bindings + + # ===================================================================== + # Load Balancer: Octavia + # ===================================================================== + # CRITICAL: vault:certificates must be in bundle from day-one (post-deploy add + # causes documented apache2/octavia-api masking bug — see test deployment v3 handoff) + + octavia: + charm: octavia + channel: 2024.1/stable + num_units: 1 + to: [lxd:11] + options: + debug: false + openstack-origin: *openstack-origin + # ----- PKI material ------------------------------------------------- + # 5 lb-mgmt-* options are supplied via overlays/octavia-pki.yaml + # (gitignored). Generated per runbooks/01a-octavia-pki-generation.md. + # Deploy with: + # juju deploy ./bundle.yaml \ + # --overlay overlays/vr0-dc0-testcloud.yaml \ + # --overlay overlays/octavia-pki.yaml + vip: 10.12.4.233 + os-public-hostname: octavia.omega.dc0.vr0.cloud.neumatrix.local + bindings: *api-bindings + constraints: arch=amd64 + + octavia-mysql-router: + charm: mysql-router + channel: 8.0/stable + bindings: *internal-bindings + + octavia-dashboard: + charm: octavia-dashboard + channel: 2024.1/stable + + octavia-diskimage-retrofit: + charm: octavia-diskimage-retrofit + channel: 2024.1/stable + options: + amp-image-tag: octavia-amphora + + # ===================================================================== + # Secrets: Barbican + # ===================================================================== + + barbican: + charm: barbican + channel: 2024.1/stable + num_units: 1 + to: [lxd:11] + options: + openstack-origin: *openstack-origin + vip: 10.12.4.224 + os-public-hostname: barbican.omega.dc0.vr0.cloud.neumatrix.local + bindings: *api-bindings + constraints: arch=amd64 + + barbican-mysql-router: + charm: mysql-router + channel: 8.0/stable + bindings: *internal-bindings + + barbican-vault: + charm: barbican-vault + channel: 2024.1/stable + + # ===================================================================== + # Kubernetes-as-a-Service: Magnum (Layer A — CAPI graft is Layer B) + # ===================================================================== + # NOTE: After bundle deploys, magnum/0 will show active/idle but CANNOT + # create K8s clusters. Layer B (post-deploy) brings it to life: + # 1. capi-mgmt VM with k3s + CAPI operators (runbook 04a) + # 2. pip install magnum-capi-helm==1.1.0 into magnum venv (runbook 05) + # 3. /etc/magnum/magnum.conf.d/99-capi.conf with enabled_drivers + # 4. Install kubeconfig at /etc/magnum/kubeconfig + # 5. Create Keystone capi-mgmt project + capo user + app credential + + magnum: + charm: magnum + channel: 2024.1/stable + num_units: 1 + to: [lxd:9] + options: + openstack-origin: *openstack-origin + region: RegionOne + vip: 10.12.4.230 + os-public-hostname: magnum.omega.dc0.vr0.cloud.neumatrix.local + bindings: *api-bindings + constraints: arch=amd64 + + magnum-mysql-router: + charm: mysql-router + channel: 8.0/stable + bindings: *internal-bindings + + magnum-dashboard: + charm: magnum-dashboard + channel: 2024.1/stable + + # ===================================================================== + # HA Cluster Subordinates (11 active for v1; ceph-radosgw + designate deferred to v2) + # ===================================================================== + # Channel: 2.4/stable (per Caracal Charm Delivery table, D-002 verified 2026-05-22). + # VIPs allocated from provider /22 range 10.12.4.224-.254 per D-003. + # NetBox IPAddress records queued post-deployment (engineer review pending). + # See workstream-2 decision (2026-05-22). + # + keystone-hacluster: { charm: hacluster, channel: 2.4/stable, options: { cluster_count: 1 } } + glance-hacluster: { charm: hacluster, channel: 2.4/stable, options: { cluster_count: 1 } } + neutron-api-hacluster: { charm: hacluster, channel: 2.4/stable, options: { cluster_count: 1 } } + nova-cloud-controller-hacluster: { charm: hacluster, channel: 2.4/stable, options: { cluster_count: 1 } } + placement-hacluster: { charm: hacluster, channel: 2.4/stable, options: { cluster_count: 1 } } + openstack-dashboard-hacluster: { charm: hacluster, channel: 2.4/stable, options: { cluster_count: 1 } } + cinder-hacluster: { charm: hacluster, channel: 2.4/stable, options: { cluster_count: 1 } } + octavia-hacluster: { charm: hacluster, channel: 2.4/stable, options: { cluster_count: 1 } } + barbican-hacluster: { charm: hacluster, channel: 2.4/stable, options: { cluster_count: 1 } } + magnum-hacluster: { charm: hacluster, channel: 2.4/stable, options: { cluster_count: 1 } } + # vault-hacluster: { charm: hacluster, channel: 2.4/stable } + # v2-deferred: ceph-radosgw-hacluster: { charm: hacluster, channel: 2.4/stable } + # v2-deferred (D-019): designate-hacluster: { charm: hacluster, channel: 2.4/stable } + + + # memcached: nova-cloud-controller token/cell caching (BUNDLEFIX-004) + memcached: + charm: memcached + channel: latest/stable + num_units: 1 + to: [lxd:8] + bindings: *internal-bindings + constraints: arch=amd64 + +relations: + - [nova-cloud-controller:memcache, memcached:cache] + + # ---- Vault HA backend chain (NEW for Caracal v1; chicken-and-egg via easyrsa) + - [easyrsa:client, etcd:certificates] # easyrsa issues etcd TLS one-time + - [vault:etcd, etcd:db] # vault uses etcd as HA backend + - [vault-mysql-router:db-router, mysql-innodb-cluster:db-router] + - [vault:shared-db, vault-mysql-router:shared-db] + - [mysql-innodb-cluster:certificates, vault:certificates] + # - [vault:ha, vault-hacluster:ha] + + # ---- Keystone (identity, hub of all OS service relations) + - [keystone-mysql-router:db-router, mysql-innodb-cluster:db-router] + - [keystone-mysql-router:shared-db, keystone:shared-db] + - [keystone:certificates, vault:certificates] + - [keystone:ha, keystone-hacluster:ha] + + # ---- Glance (image) + - [glance-mysql-router:db-router, mysql-innodb-cluster:db-router] + - [glance-mysql-router:shared-db, glance:shared-db] + - [glance:identity-service, keystone:identity-service] + - [glance:certificates, vault:certificates] + - [glance:ha, glance-hacluster:ha] + + # ---- Glance simplestreams sync (Octavia amphora pipeline source) + - [glance-simplestreams-sync:identity-service, keystone:identity-service] + - [glance-simplestreams-sync:certificates, vault:certificates] + + # ---- Nova cloud controller (NCC) + - [ncc-mysql-router:db-router, mysql-innodb-cluster:db-router] + - [ncc-mysql-router:shared-db, nova-cloud-controller:shared-db] + - [nova-cloud-controller:identity-service, keystone:identity-service] + - [nova-cloud-controller:amqp, rabbitmq-server:amqp] + - [nova-cloud-controller:image-service, glance:image-service] + - [nova-cloud-controller:neutron-api, neutron-api:neutron-api] + - [nova-cloud-controller:cloud-compute, nova-compute:cloud-compute] + - [nova-cloud-controller:cinder-volume-service, cinder:cinder-volume-service] + - [nova-cloud-controller:certificates, vault:certificates] + - [nova-cloud-controller:ha, nova-cloud-controller-hacluster:ha] + + # ---- Nova compute + - [nova-compute:amqp, rabbitmq-server:amqp] + - [nova-compute:image-service, glance:image-service] + + # ---- Placement + - [placement-mysql-router:db-router, mysql-innodb-cluster:db-router] + - [placement-mysql-router:shared-db, placement:shared-db] + - [placement:identity-service, keystone:identity-service] + - [placement:placement, nova-cloud-controller:placement] + - [placement:certificates, vault:certificates] + - [placement:ha, placement-hacluster:ha] + + # ---- Neutron API + OVN + - [neutron-api-mysql-router:db-router, mysql-innodb-cluster:db-router] + - [neutron-api-mysql-router:shared-db, neutron-api:shared-db] + - [neutron-api:identity-service, keystone:identity-service] + - [neutron-api:amqp, rabbitmq-server:amqp] + - [neutron-api:certificates, vault:certificates] + - [neutron-api-plugin-ovn:neutron-plugin, neutron-api:neutron-plugin-api-subordinate] + - [neutron-api-plugin-ovn:ovsdb-cms, ovn-central:ovsdb-cms] + - [neutron-api-plugin-ovn:certificates, vault:certificates] + - [ovn-central:certificates, vault:certificates] + - [ovn-chassis:ovsdb, ovn-central:ovsdb] + - [ovn-chassis:nova-compute, nova-compute:neutron-plugin] + - [ovn-chassis:certificates, vault:certificates] + - [neutron-api:ha, neutron-api-hacluster:ha] + + # ---- Cinder + cinder-ceph + - [cinder-mysql-router:db-router, mysql-innodb-cluster:db-router] + - [cinder-mysql-router:shared-db, cinder:shared-db] + - [cinder:identity-service, keystone:identity-service] + - [cinder:amqp, rabbitmq-server:amqp] + - [cinder:image-service, glance:image-service] + - [cinder:certificates, vault:certificates] + - [cinder-ceph:storage-backend, cinder:storage-backend] + - [cinder-ceph:ceph, ceph-mon:client] + - [cinder-ceph:ceph-access, nova-compute:ceph-access] + - [cinder:ha, cinder-hacluster:ha] + + # ---- Ceph mon + osd + radosgw + - [ceph-mon:osd, ceph-osd:mon] + - [ceph-mon:client, nova-compute:ceph] + - [ceph-mon:client, glance:ceph] + - [ceph-radosgw:mon, ceph-mon:radosgw] + - [ceph-radosgw:identity-service, keystone:identity-service] + - [ceph-radosgw:certificates, vault:certificates] + # v2-deferred: - [ceph-radosgw:ha, ceph-radosgw-hacluster:ha] + + # ---- OpenStack Dashboard (Horizon) + - [dashboard-mysql-router:db-router, mysql-innodb-cluster:db-router] + - [dashboard-mysql-router:shared-db, openstack-dashboard:shared-db] + - [openstack-dashboard:identity-service, keystone:identity-service] + - [openstack-dashboard:certificates, vault:certificates] + - [openstack-dashboard:ha, openstack-dashboard-hacluster:ha] + + # ---- Octavia (LBaaS) + # CRITICAL: octavia:certificates ↔ vault:certificates MUST be present at deploy time + - [octavia-mysql-router:db-router, mysql-innodb-cluster:db-router] + - [octavia-mysql-router:shared-db, octavia:shared-db] + - [octavia:identity-service, keystone:identity-service] + - [octavia:amqp, rabbitmq-server:amqp] + - [octavia:neutron-api, neutron-api:neutron-load-balancer] + - [octavia:certificates, vault:certificates] + - [octavia-dashboard:dashboard, openstack-dashboard:dashboard-plugin] + - [ovn-chassis-octavia:ovsdb, ovn-central:ovsdb] + - [ovn-chassis-octavia:ovsdb-subordinate, octavia:ovsdb-subordinate] + - [ovn-chassis-octavia:certificates, vault:certificates] + # Octavia amphora image pipeline + - [octavia-diskimage-retrofit:juju-info, glance-simplestreams-sync:juju-info] + - [octavia-diskimage-retrofit:identity-credentials, keystone:identity-credentials] + - [octavia:ha, octavia-hacluster:ha] + + # ---- Barbican (secrets) + - [barbican-mysql-router:db-router, mysql-innodb-cluster:db-router] + - [barbican-mysql-router:shared-db, barbican:shared-db] + - [barbican:identity-service, keystone:identity-service] + - [barbican:amqp, rabbitmq-server:amqp] + - [barbican:certificates, vault:certificates] + - [barbican:secrets, barbican-vault:secrets] + - [barbican-vault:certificates, vault:certificates] + - [barbican-vault:secrets-storage, vault:secrets] + - [barbican:ha, barbican-hacluster:ha] + + # ---- Magnum (Layer A only; CAPI graft is Layer B/runbook 05) + - [magnum-mysql-router:db-router, mysql-innodb-cluster:db-router] + - [magnum:shared-db, magnum-mysql-router:shared-db] + - [magnum:identity-service, keystone:identity-service] + - [magnum:amqp, rabbitmq-server:amqp] + - [magnum:certificates, vault:certificates] + - [magnum-dashboard:dashboard, openstack-dashboard:dashboard-plugin] + - [magnum:ha, magnum-hacluster:ha] diff --git a/fix-bundle-metal-vips.py b/fix-bundle-metal-vips.py new file mode 100644 index 0000000..0ac5049 --- /dev/null +++ b/fix-bundle-metal-vips.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python3 +""" +BUNDLEFIX-006 (D-020): append the metal HA VIP to each clustered API charm's `vip` option. + +For every line of the form `vip: 10.12.4.` where N is in the reserved provider API-VIP +range (224..254), rewrite it to `vip: "10.12.4. 10.12.8."` so the charm advertises a +provider VIP (public endpoint) AND a metal VIP (internal/admin endpoints). This is the +spaces-native dual-VIP fix validated live on placement: internal/admin bindings = metal, so +resolve_address matches the metal VIP; public binding = provider, matches the provider VIP. +No binding/anchor change and no os-*-network needed. + +Safety properties (same pattern as the prior fix scripts): + - pure line edit; never round-trips YAML, so anchors/aliases/comments are preserved + - STRICT match: only single `10.12.4.<224-254>` values are rewritten; anything else (already + dual, out of range, unexpected format) is left untouched -> fail-safe, never mangles + - idempotent: lines already carrying a `10.12.4.x 10.12.8.x` pair are skipped + - timestamped .bak, unified diff to stdout, and a best-effort yaml.safe_load semantic check + (skipped where PyYAML is absent, e.g. the Windows workstation; the jumphost re-verifies) +""" +import sys +import re +import datetime +import shutil +import difflib + +PROVIDER_NET = "10.12.4." +METAL_NET = "10.12.8." +VIP_LO, VIP_HI = 224, 254 # reserved API-VIP range (same last-octet on both nets) + +VIP_LINE = re.compile(r'^(?P\s*)vip:\s*(?P["\']?)(?P[^"\'\n]*)(?P=q)\s*$') +SINGLE = re.compile(r'^10\.12\.4\.(\d+)$') +DOUBLE = re.compile(r'^10\.12\.4\.(\d+)\s+10\.12\.8\.(\d+)$') + + +def main(): + if len(sys.argv) != 2: + print("usage: fix-bundle-metal-vips.py ") + return 2 + path = sys.argv[1] + try: + with open(path) as f: + original = f.read() + except OSError as e: + print(f"[ABORT] cannot read {path}: {e}") + return 3 + + lines = original.split("\n") + changed = 0 + skipped_already = 0 + untouched_unexpected = [] + + out = [] + for l in lines: + m = VIP_LINE.match(l) + if m: + val = m.group("val").strip() + if DOUBLE.match(val): + skipped_already += 1 + out.append(l) + continue + sm = SINGLE.match(val) + if sm: + octet = int(sm.group(1)) + if VIP_LO <= octet <= VIP_HI: + out.append(f'{m.group("indent")}vip: "{PROVIDER_NET}{octet} {METAL_NET}{octet}"') + changed += 1 + continue + # vip line, but not a single in-range provider VIP -> leave alone, but note it + untouched_unexpected.append(val) + out.append(l) + + if untouched_unexpected: + print(f"[NOTE] {len(untouched_unexpected)} vip line(s) left untouched (unexpected value/range): " + f"{untouched_unexpected}") + + if changed == 0: + if skipped_already: + print(f"[OK/IDEMPOTENT] {skipped_already} vip line(s) already carry a metal VIP; no change.") + return 0 + print("[ABORT] found no `vip: 10.12.4.224-254` lines to update.") + return 4 + + new = "\n".join(out) + if original.endswith("\n") and not new.endswith("\n"): + new += "\n" + + print("=== unified diff ===") + sys.stdout.writelines(difflib.unified_diff( + original.splitlines(keepends=True), + new.splitlines(keepends=True), + fromfile=f"{path} (orig)", tofile=f"{path} (new)")) + + try: + import yaml + d = yaml.safe_load(new) + apps = d.get("applications", {}) or {} + dual = sorted( + a for a, c in apps.items() + if isinstance(c, dict) and isinstance(c.get("options"), dict) + and isinstance(c["options"].get("vip"), str) + and len(c["options"]["vip"].split()) == 2 + ) + print(f"\n[VERIFY] yaml parses OK; {len(dual)} charm(s) now have a 2-address vip:") + for a in dual: + print(f" {a}: {apps[a]['options']['vip']}") + except ImportError: + print("\n[VERIFY] PyYAML not present (Windows workstation) - semantic check skipped; " + "jumphost will re-verify after pull.") + except Exception as e: + print(f"\n[ABORT] yaml verify failed, not writing: {e}") + return 5 + + ts = datetime.datetime.now().strftime("%Y%m%d-%H%M%S") + bak = f"{path}.bak-{ts}" + shutil.copy2(path, bak) + with open(path, "w") as f: + f.write(new) + print(f"\n[WROTE] {path} (backup: {bak})") + print(f"[SUMMARY] updated {changed} vip line(s); {skipped_already} already dual; " + f"{len(untouched_unexpected)} untouched.") + return 0 + + +if __name__ == "__main__": + sys.exit(main())