# LP draft 2026-08-01 -- charm-ceph-osd, IPv6 static addresses (LP #2061836)

**STATUS: DRAFT. The operator files this; Claude does not post to Launchpad.**
Precedent: `docs/audit/lp-draft-20260721-maas-agent-resolver.md`.

**Target: add a comment to the EXISTING bug LP #2061836 and ask for the
`charm-ceph-osd` task to be closed. Do NOT file a new bug** -- the defect is
already reported there, the `charm-ceph-mon` task is `Fix Committed` (2024-06-14),
and only the `charm-ceph-osd` task remains `New` and unfixed.

Ruled under D-139 "B plus C" (2026-08-01, operator: *"B plus C"*): pursue the
upstream fix, because it is one word and already merged on the sibling charm.

---

## Suggested comment text

> Confirming this is still present in `charm-ceph-osd` and asking whether the
> ceph-osd task can be closed the same way the ceph-mon task was.
>
> Measured against the **published `ceph-osd` revision 953** (the current
> `2024.1/stable` artifact), `get_ipv6_addr()` is still called **without**
> `dynamic_only=False` at two sites:
>
> * `hooks/utils.py:205` -- inside `get_host_ip()`:
>
>   ```python
>   def get_host_ip(hostname=None):
>       if config('prefer-ipv6'):
>           return get_ipv6_addr()[0]
>   ```
>
> * `hooks/ceph_hooks.py:547` -- inside the `prefer-ipv6` branch that builds the
>   ceph context:
>
>   ```python
>   if config('prefer-ipv6'):
>       cephcontext['ms_bind_ipv4'] = False
>       cephcontext['ms_bind_ipv6'] = True
>       dynamic_ipv6_address = get_ipv6_addr()[0]
>   ```
>
> The default `dynamic_only=True` restricts the result to dynamically-assigned
> (SLAAC/RA) addresses. On a deployment where the provisioning layer assigns
> **static** IPv6 addresses -- in our case MAAS assigning a static per node on each
> of six bound spaces -- there is no dynamic address to find, so the lookup does not
> return the address the node actually holds.
>
> This matches the original report on this bug, where the reporter noted:
> *"I replaced all the get_ipv6_addr() calls with get_ipv6_addr(dynamic_only=False)
> ... The machines have a single global static ipv6 address. Everything works
> correctly."*
>
> The equivalent change has already landed on `charm-ceph-mon`. Is there anything
> blocking the same one-word change on `charm-ceph-osd`, or can that task be moved
> to Fix Committed as well?
>
> **Context on why this matters beyond cosmetics.** With `prefer-ipv6=false` the
> alternative path is also IPv4-only: `get_host_ip()` falls through to
> `socket.inet_aton(hostname)` and then `dns.resolver.query(hostname, 'A')`
> (`hooks/utils.py:208-217`), which cannot resolve an IPv6 literal -- the code's own
> comment acknowledges this "may throw an NXDOMAIN exception ... just let it kill
> the hook". So on a genuinely IPv6-only storage/cluster network, **both** settings
> of `prefer-ipv6` currently fail, in different ways. That second path appears to be
> what LP #2109798 is reporting.

---

## Notes for the operator, NOT part of the comment

* **Every code claim above was read from the artifact**, not from a repo note: the
  `ceph-osd_953.charm` was downloaded and `hooks/utils.py` / `hooks/ceph_hooks.py`
  extracted and quoted. Line numbers are from that revision and should be
  re-checked if a newer revision has published before filing.
* **Do not cite LP #1590598 in support.** It is `Fix Released` and about
  IPv6-**only** host interfaces not being bridged into containers -- a different
  defect. Citing it here would be an inverted citation, which this repo has been
  bitten by before.
* **This bug is not, by itself, what blocks a v6-only Ceph plane for us.** Measured
  separately: setting the charm's `ceph-public-network` / `ceph-cluster-network`
  options to the v6 CIDRs means the buggy call is never used for address selection,
  because both assignments are guarded by `if not public_network:` /
  `if not cluster_network:`. The fix is still worth pursuing -- it removes a
  config-dependent workaround and closes a real defect -- but the local path does
  not depend on it landing.
* Filing this is the "C" half of the 2026-08-01 ruling. The "B" half (the
  storage+replication v6-only experiment) is independent and does not wait on it.
