From 3919dea8876a1fa37fe39da384004f5ce3ec7950 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Tue, 18 Mar 2025 11:30:15 -0600 Subject: [PATCH] Fix display of dotted field names - Fixes: #1825 Signed-off-by: Jonathon Anderson --- CHANGELOG.md | 1 + internal/pkg/node/fields.go | 41 ++++++++++++++++++++++++++++++++- internal/pkg/node/mergo_test.go | 12 ++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e93e1f3..63650bc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Replaced unreadable >= character external sphinx module for pdf doc build. - Handle missing ipmi fields during bmc commands. #1768 - Properly configure a default IPMI template during `wwctl upgrade nodes --add-defaults`. +- Fixed display of dotted field names. #1825 ### Changed diff --git a/internal/pkg/node/fields.go b/internal/pkg/node/fields.go index 6b32664b..a9992bd5 100644 --- a/internal/pkg/node/fields.go +++ b/internal/pkg/node/fields.go @@ -114,7 +114,7 @@ func getNestedFieldValue(obj interface{}, name string) (value reflect.Value, err value = value.Elem() } - fieldNames := strings.Split(name, ".") + fieldNames := splitFieldName(name) for _, fieldName := range fieldNames { var key string fieldName, key = parseMapField(fieldName) @@ -141,6 +141,45 @@ func getNestedFieldValue(obj interface{}, name string) (value reflect.Value, err return } +// splitName splits a string into components using the '.' character as a delimiter, +// except when the '.' appears inside square brackets. +// +// For example, given the input "NetDevs[eth0.100].Type", it returns: +// +// []string{"NetDevs[eth0.100]", "Type"} +func splitFieldName(s string) []string { + var parts []string + var current []rune + inBracket := false + + for _, r := range s { + switch r { + case '[': + inBracket = true + current = append(current, r) + case ']': + inBracket = false + current = append(current, r) + case '.': + if inBracket { + // If we're inside brackets, keep the dot. + current = append(current, r) + } else { + // Outside brackets, split here. + parts = append(parts, string(current)) + current = nil + } + default: + current = append(current, r) + } + } + // Append any remaining characters as the last part. + if len(current) > 0 { + parts = append(parts, string(current)) + } + return parts +} + // getNestedFieldString retrieves the string representation // of a nested field as returned by getNestedFieldValue. // diff --git a/internal/pkg/node/mergo_test.go b/internal/pkg/node/mergo_test.go index ac569a82..f95f8046 100644 --- a/internal/pkg/node/mergo_test.go +++ b/internal/pkg/node/mergo_test.go @@ -672,6 +672,18 @@ nodeprofiles: source: "", value: "p1,p2", }, + "dotted netdev name": { + nodesConf: ` +nodes: + n1: + network devices: + eth0.100: + type: Ethernet`, + node: "n1", + field: "NetDevs[eth0.100].Type", + source: "", + value: "Ethernet", + }, "node netdev tag": { nodesConf: ` nodes: