# overlays/dc-dc-ipv6-family-matrix.yaml
#
# D-101 IPv6 family-matrix overlay (tooling gap register item #13).
# Researched 2026-07-09/10 against real charm source/config (not memory --
# see docs/dc-dc-ipv6-charm-research.md for full sourcing, per-charm
# confidence level, and the one significant open risk this overlay does
# NOT attempt to close). Applied ALONGSIDE bundle.yaml's other overlays,
# e.g.:
#   juju deploy ./bundle.yaml \
#     --overlay overlays/octavia-pki.yaml \
#     --overlay "overlays/${DC}-hostnames.yaml" \
#     --overlay overlays/dc-dc-ipv6-family-matrix.yaml \
#     -m "${DC_MODEL}"
#
# NOT YET APPLIED to any live model -- authored prep-only, no live cloud
# reachable this session. Every VIP/CIDR value below is an explicit
# {{TOKEN}} placeholder (this repo's established convention, matching
# opentofu/templates/opnsense-config.xml.tmpl) -- render/substitute with
# real, measured per-DC values before use; do not fill in a guessed
# address.
#
# CONFIRMED mechanism, sourced 2026-07-09/10:
# - charms.openstack-family API charms (confirmed directly for
#   charm-keystone's config.yaml, and for charm-nova-cloud-controller's
#   actual "Dual Stack VIPs" commit) expose a `prefer-ipv6` boolean. When
#   True, HAProxy binds BOTH `*:port` (v4, wildcard) AND `:::port` (v6,
#   wildcard) SIMULTANEOUSLY -- this is genuinely ADDITIVE dual-stack, not
#   an either/or switch, confirmed by reading the actual haproxy.cfg
#   Jinja template diff in that commit. The existing `vip:` option (already
#   a space-separated multi-network list in this bundle, per D-020's triple-
#   VIP pattern) takes the ADDITIONAL v6/GUA VIP literals alongside the
#   existing v4 ones once `prefer-ipv6: true` is set.
# - charm-ceph-mon exposes `prefer-ipv6` (bool) + `ceph-public-network` /
#   `ceph-cluster-network` (space-delimited CIDR list). Per that charm's own
#   docs, `prefer-ipv6=False` (default) means IPv4 is expected -- this
#   reads as a straight EITHER/OR switch for ceph-mon specifically (unlike
#   the additive HAProxy behavior above), which is actually the CORRECT
#   shape for storage/replication: D-101 wants those ULA-ONLY, not
#   dual-stack, so a clean switch to v6-only is exactly right here.
# - OVN (ovn-central/ovn-chassis, charm-layer-ovn base) has NO explicit
#   IPv6/encapsulation config option at all (confirmed: read the full
#   config.yaml, no such key exists). geneve-over-v6 for the data-tenant
#   plane is therefore NOT a charm-config concern -- it is governed purely
#   by which IP family the unit's bound interface on that plane actually
#   has. Since data-tenant is ULA-only (no v4 present) per D-101, the
#   geneve tunnel endpoint address will naturally be the unit's v6 address
#   with NO overlay entry needed for OVN at all.
# - charm-vault's cert-issuance code (`vault_pki.py`'s `sort_sans()`)
#   confirmed to have NO IPv4/IPv6 distinction when building IP SANs --
#   D-109's "Vault issues v4+IPv6-SAN certs" requirement is technically
#   supported by the charm's own code, not just assumed.
#
# NOT independently confirmed per-charm (inferred by shared-framework
# pattern only): glance, neutron-api, placement, cinder, barbican, magnum,
# openstack-dashboard, ceph-radosgw all share the same charms.openstack
# base classes as keystone/nova-cloud-controller, so `prefer-ipv6` and the
# additive dual-stack HAProxy behavior is EXPECTED to apply identically --
# but only keystone's config.yaml and nova-cloud-controller's actual code
# were read directly. Confirm each charm's real `prefer-ipv6` presence via
# `juju config <app>` once deployed, before assuming this overlay is
# complete for all of them.
#
# ONE SIGNIFICANT OPEN RISK, deliberately NOT addressed by this overlay:
# Octavia's lb-mgmt-net (the amphora management network D-101 wants
# ULA-only) is a NEUTRON tenant network the octavia charm itself creates
# (`create-mgmt-network` option), not a Juju-space-bound interface like
# ceph-mon's -- a fundamentally different mechanism. Real, still-open
# upstream bug reports exist describing IPv6 lb-mgmt-net failures
# (Launchpad #1911788 "IPv6 mgmt network not working, octavia can't talk
# to amphora"; #1913409 "octavia_amp_network does not support IPv6" against
# kolla-ansible, the same underlying Octavia limitation). #1911788's root
# cause traces to an OVN/LXD/MAAS hostname-resolution mismatch (marked
# duplicate of #1896630, "managing /etc/hosts for containers") -- the SAME
# CLASS of problem this repo's own D-008 bootstrap order (static /etc/hosts
# -> os-public-hostname -> vault certs -> Designate) already exists to
# harden against, so it is NOT necessarily fatal here, but it is a REAL,
# documented, open upstream risk, not a solved problem. This overlay
# deliberately does NOT attempt an Octavia lb-mgmt-net IPv6 config change --
# that needs its own decision (present to the operator: accept the risk and
# test it for real once DC1 exists, or keep Octavia's lb-mgmt-net dual-stack/
# v4 as a deliberate, logged D-101 exception) rather than being silently
# forced through in an overlay file.

applications:
  # ---- Dual-stack API charms (metal-internal ULA leg + provider-public
  # GUA leg, per D-101's family matrix) ----
  keystone:
    options:
      prefer-ipv6: true
      # Existing vip (D-020 triple: provider/metal-admin/metal-internal v4)
      # gets the v6/GUA legs appended -- do NOT replace the v4 entries,
      # append only. Render with real per-DC measured addresses.
      vip: "{{KEYSTONE_VIP_PROVIDER_V4}} {{KEYSTONE_VIP_METAL_ADMIN_V4}} {{KEYSTONE_VIP_METAL_INTERNAL_V4}} {{KEYSTONE_VIP_PROVIDER_GUA}} {{KEYSTONE_VIP_METAL_ADMIN_ULA}} {{KEYSTONE_VIP_METAL_INTERNAL_ULA}}"

  glance:
    options:
      prefer-ipv6: true
      vip: "{{GLANCE_VIP_PROVIDER_V4}} {{GLANCE_VIP_METAL_ADMIN_V4}} {{GLANCE_VIP_METAL_INTERNAL_V4}} {{GLANCE_VIP_PROVIDER_GUA}} {{GLANCE_VIP_METAL_ADMIN_ULA}} {{GLANCE_VIP_METAL_INTERNAL_ULA}}"

  neutron-api:
    options:
      prefer-ipv6: true
      vip: "{{NEUTRON_VIP_PROVIDER_V4}} {{NEUTRON_VIP_METAL_ADMIN_V4}} {{NEUTRON_VIP_METAL_INTERNAL_V4}} {{NEUTRON_VIP_PROVIDER_GUA}} {{NEUTRON_VIP_METAL_ADMIN_ULA}} {{NEUTRON_VIP_METAL_INTERNAL_ULA}}"

  nova-cloud-controller:
    options:
      prefer-ipv6: true   # CONFIRMED: this charm's actual "Dual Stack VIPs" commit is the direct source for this whole overlay's design
      vip: "{{NCC_VIP_PROVIDER_V4}} {{NCC_VIP_METAL_ADMIN_V4}} {{NCC_VIP_METAL_INTERNAL_V4}} {{NCC_VIP_PROVIDER_GUA}} {{NCC_VIP_METAL_ADMIN_ULA}} {{NCC_VIP_METAL_INTERNAL_ULA}}"

  placement:
    options:
      prefer-ipv6: true
      vip: "{{PLACEMENT_VIP_PROVIDER_V4}} {{PLACEMENT_VIP_METAL_ADMIN_V4}} {{PLACEMENT_VIP_METAL_INTERNAL_V4}} {{PLACEMENT_VIP_PROVIDER_GUA}} {{PLACEMENT_VIP_METAL_ADMIN_ULA}} {{PLACEMENT_VIP_METAL_INTERNAL_ULA}}"

  cinder:
    options:
      prefer-ipv6: true
      vip: "{{CINDER_VIP_PROVIDER_V4}} {{CINDER_VIP_METAL_ADMIN_V4}} {{CINDER_VIP_METAL_INTERNAL_V4}} {{CINDER_VIP_PROVIDER_GUA}} {{CINDER_VIP_METAL_ADMIN_ULA}} {{CINDER_VIP_METAL_INTERNAL_ULA}}"

  barbican:
    options:
      prefer-ipv6: true
      vip: "{{BARBICAN_VIP_PROVIDER_V4}} {{BARBICAN_VIP_METAL_ADMIN_V4}} {{BARBICAN_VIP_METAL_INTERNAL_V4}} {{BARBICAN_VIP_PROVIDER_GUA}} {{BARBICAN_VIP_METAL_ADMIN_ULA}} {{BARBICAN_VIP_METAL_INTERNAL_ULA}}"

  magnum:
    options:
      prefer-ipv6: true
      vip: "{{MAGNUM_VIP_PROVIDER_V4}} {{MAGNUM_VIP_METAL_ADMIN_V4}} {{MAGNUM_VIP_METAL_INTERNAL_V4}} {{MAGNUM_VIP_PROVIDER_GUA}} {{MAGNUM_VIP_METAL_ADMIN_ULA}} {{MAGNUM_VIP_METAL_INTERNAL_ULA}}"

  openstack-dashboard:
    options:
      prefer-ipv6: true
      vip: "{{DASHBOARD_VIP_PROVIDER_V4}} {{DASHBOARD_VIP_METAL_ADMIN_V4}} {{DASHBOARD_VIP_METAL_INTERNAL_V4}} {{DASHBOARD_VIP_PROVIDER_GUA}} {{DASHBOARD_VIP_METAL_ADMIN_ULA}} {{DASHBOARD_VIP_METAL_INTERNAL_ULA}}"

  ceph-radosgw:
    options:
      prefer-ipv6: true
      vip: "{{RADOSGW_VIP_PROVIDER_V4}} {{RADOSGW_VIP_METAL_ADMIN_V4}} {{RADOSGW_VIP_METAL_INTERNAL_V4}} {{RADOSGW_VIP_PROVIDER_GUA}} {{RADOSGW_VIP_METAL_ADMIN_ULA}} {{RADOSGW_VIP_METAL_INTERNAL_ULA}}"

  # octavia: deliberately NOT included here -- see "ONE SIGNIFICANT OPEN
  # RISK" above. Its VIP (metal-admin/metal-internal/provider-public,
  # matching the pattern above) COULD take the same prefer-ipv6 + appended-
  # VIP treatment for its own API endpoint (that part is no different from
  # the other charms above) -- what's genuinely unresolved is its SEPARATE
  # lb-mgmt-net (amphora management) IPv6 support, a different mechanism
  # entirely. If the operator wants Octavia's API endpoint dual-stacked
  # while leaving lb-mgmt-net v4-only as a deliberate exception, add:
  #   octavia:
  #     options:
  #       prefer-ipv6: true
  #       vip: "{{OCTAVIA_VIP_PROVIDER_V4}} {{OCTAVIA_VIP_METAL_ADMIN_V4}} {{OCTAVIA_VIP_METAL_INTERNAL_V4}} {{OCTAVIA_VIP_PROVIDER_GUA}} {{OCTAVIA_VIP_METAL_ADMIN_ULA}} {{OCTAVIA_VIP_METAL_INTERNAL_ULA}}"
  # -- but decide this explicitly, don't silently activate it via this file.

  # ---- ULA-only planes (storage, replication) -- Ceph-over-v6 ----
  ceph-mon:
    options:
      prefer-ipv6: true    # CONFIRMED real option, charm-ceph-mon config.yaml
      ceph-public-network: "{{DC_STORAGE_ULA_CIDR}}"
      ceph-cluster-network: "{{DC_REPLICATION_ULA_CIDR}}"
      # NOTE: prefer-ipv6 privacy-extension caveat (charm's own docs):
      # "IPv6 privacy extension... must be disabled and a non-temporary
      # address must be configured/available" on every ceph-mon unit's
      # storage/replication interface -- a real host/OS-level prerequisite,
      # not something this overlay can set.

  # data-tenant (OVN geneve): deliberately NO overlay entry. Confirmed no
  # charm-config toggle exists for ovn-central/ovn-chassis; the plane being
  # ULA-only (no v4 present, per D-101) is sufficient on its own -- geneve
  # encapsulation follows whatever address family the bound interface has.
