# 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.