Skip to content

cell: Decode config fields implementing encoding.TextUnmarshaler - #79

Merged
joamaki merged 1 commit into
mainfrom
pr/HadrienPatte/TextUnmarshaler
Aug 21, 2026
Merged

joamaki merged 1 commit into
mainfrom
pr/HadrienPatte/TextUnmarshaler

Conversation

@HadrienPatte

Copy link
Copy Markdown
Member

Config struct fields whose type implements encoding.TextUnmarshaler, such as netip.Addr, netip.Prefix or time.Time, currently fail to decode with "expected a map, got 'string'". Each such type needs a bespoke decode hook passed in via DecodeHooks. There's currently one in cilium/cilium that handles netip.Prefix.

This PR adds the more generic mapstructure.TextUnmarshallerHookFunc() to the default decode hooks so all of them work out of the box. It is placed before the slice hooks: StringToSliceHookFunc matches on the target's reflect.Kind, so it would otherwise comma-split types that are themselves slices, such as net.IP.

Note: This PR addresses this TODO in a more generic way than expressed in the TODO comment and will allow us to delete that bespoke decode hook once hive is bumped in cilium/cilium to a version that includes this PR.

Config struct fields whose type implements `encoding.TextUnmarshaler`,
such as `netip.Addr`, `netip.Prefix` or `time.Time`, currently fail to
decode with `"expected a map, got 'string'"`. Each such type needs a
bespoke decode hook passed in via `DecodeHooks`. There's currently one
in cilium/cilium that handles `netip.Prefix`, see https://github.com/cilium/cilium/blob/4c38f075cad5e7e7b54744c3c613f4e10fcdac0b/pkg/hive/hive.go#L145-L146

This PR adds the more generic `mapstructure.TextUnmarshallerHookFunc()`
to the default decode hooks so all of them work out of the box. It is
placed before the slice hooks: `StringToSliceHookFunc` matches on the
target's `reflect.Kind`, so it would otherwise comma-split types that
are themselves slices, such as `net.IP`.

Signed-off-by: Hadrien Patte <hadrien.patte@datadoghq.com>
@HadrienPatte
HadrienPatte marked this pull request as ready for review August 16, 2026 03:01
@HadrienPatte
HadrienPatte requested a review from a team as a code owner August 16, 2026 03:01
@HadrienPatte
HadrienPatte requested review from joamaki and removed request for a team August 16, 2026 03:01
@joamaki
joamaki merged commit 3fd0ce8 into main Aug 21, 2026
1 check passed
@joamaki
joamaki deleted the pr/HadrienPatte/TextUnmarshaler branch August 21, 2026 12:58
HadrienPatte added a commit that referenced this pull request Sep 29, 2026
The [mitchellh/mapstructure](https://github.com/mitchellh/mapstructure) package is archived and no longer receives updates (see mitchellh/mapstructure#349). The blessed fork (see https://gist.github.com/mitchellh/90029601268e59a29e64e55bab1c5bdc) is [go-viper/mapstructure](https://github.com/go-viper/mapstructure), which viper itself has used since v1.20.

This migration was attempted before in #49 and reverted in #53 because it broke Cilium's `TestNodeAddressWhitelist`.

The API is almost the same, but go-viper/mapstructure#6 changed `StringToSliceHookFunc` so it only fires when the target type is exactly `[]string`. The mitchellh version fired for any slice kind. As a result, a comma-separated string coming from the environment or a configmap is no longer split before being decoded into slices of other element types, such as `[]netip.Prefix`. Each element then gets the whole unsplit string. Swapping only the import path, as #49 did, silently changes this behavior.

Use `StringToWeakSliceHookFunc` instead. go-viper/mapstructure provides it to bring back the pre-v2 behavior, and its implementation matches the mitchellh `StringToSliceHookFunc`. Hook ordering is unchanged: `TextUnmarshallerHookFunc` still runs before the slice split, so types like `net.IP` (`[]byte`) are not split on commas.

`TestHiveTextUnmarshaler` (added in #79, after the revert) covers the case that broke Cilium: it decodes "10.0.0.0/8,192.168.0.0/16" from the configmap into a `[]netip.Prefix`. It fails with a plain import swap and passes with this change.

Signed-off-by: Hadrien Patte <hadrien.patte@datadoghq.com>
meefs pushed a commit to meefs/cilium that referenced this pull request Sep 30, 2026
`cilium/hive` v1.0.6 includes cilium/hive#79, which adds
`mapstructure.TextUnmarshallerHookFunc()` to the default config decode
hooks. Config fields of any type implementing `encoding.TextUnmarshaler`,
including `netip.Prefix`, now decode out of the box.

The default hooks run before the extra hooks passed via
`Options.DecodeHooks`, so the `netip.Prefix` hook in `pkg/hive` never sees
a string input anymore and is dead code. Remove it, along with the
associated TODO, which waited on go-viper/mapstructure#85 and is now
obsolete.

Signed-off-by: Hadrien Patte <hadrien.patte@datadoghq.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants