Consolidate MergeNode merge behavior to an inner merge function

Signed-off-by: Jonathon Anderson <janderson@ciq.com>
This commit is contained in:
Jonathon Anderson
2025-01-18 09:46:13 -07:00
parent e478adc45d
commit f0e634183e

View File

@@ -123,46 +123,15 @@ func (config *NodesYaml) MergeNode(id string) (node Node, fields fieldMap, err e
continue
} else {
profile := deepcopy.Copy(profile)
if err = mergo.Merge(&node.Profile, profile, mergo.WithAppendSlice, mergo.WithOverride, mergo.WithTransformers(InterfaceTransformer{})); err != nil {
if err = merge(&node.Profile, profile, fields, profileID, profileID); err != nil {
return node, fields, err
}
for _, fieldName := range listFields(profile) {
if value, err := getNestedFieldValue(profile, fieldName); err == nil && valueStr(value) != "" {
source := profileID
prevSource := fields.Source(fieldName)
if value.Kind() == reflect.Slice && prevSource != "" {
source = strings.Join([]string{prevSource, source}, ",")
}
if value, err := getNestedFieldString(node, fieldName); err == nil {
fields.Set(fieldName, source, value)
}
}
}
}
}
if err = mergo.Merge(&node, originalNode, mergo.WithAppendSlice, mergo.WithOverride, mergo.WithTransformers(InterfaceTransformer{})); err != nil {
if err = merge(&node, originalNode, fields, "", id); err != nil {
return node, fields, err
}
for _, fieldName := range listFields(originalNode) {
if value, err := getNestedFieldValue(originalNode, fieldName); err == nil && valueStr(value) != "" {
source := ""
prevSource := fields.Source(fieldName)
if prevSource != "" {
switch value.Kind() {
case reflect.Slice:
source = strings.Join([]string{prevSource, id}, ",")
case reflect.Interface:
if _, ok := value.Interface().([]interface{}); ok {
source = strings.Join([]string{prevSource, id}, ",")
}
}
}
if value, err := getNestedFieldString(node, fieldName); err == nil {
fields.Set(fieldName, source, value)
}
}
}
node.Profiles = originalNode.Profiles
if len(node.Profiles) > 0 {
@@ -177,3 +146,41 @@ func (config *NodesYaml) MergeNode(id string) (node Node, fields fieldMap, err e
node.updatePrimaryNetDev()
return node, fields, nil
}
// merge merges the fields of src (a data object) into dst (a pointer) associated with it. Used by
// MergeNode to provide consistent behavior when merging profiles and nodes.
//
// merge further tracks the source of each field in the provided fields.
//
// Because the source label behavior differs between multi-valued fields (e.g., slices) and
// single-valued slices, two source names must be provided: srcName is used for single-valued
// fields, and multipleSrcName is used for multi-sourced fields.
//
// Returns an error if the merging operation fails.
func merge(dest, src interface{}, fields fieldMap, srcName string, multipleSrcName string) error {
if err := mergo.Merge(dest, src, mergo.WithAppendSlice, mergo.WithOverride, mergo.WithTransformers(InterfaceTransformer{})); err != nil {
return err
}
for _, fieldName := range listFields(src) {
if value, err := getNestedFieldValue(src, fieldName); err == nil && valueStr(value) != "" {
srcName := srcName
prevSource := fields.Source(fieldName)
if prevSource != "" {
switch value.Kind() {
case reflect.Slice:
srcName = strings.Join([]string{prevSource, multipleSrcName}, ",")
case reflect.Interface:
if _, ok := value.Interface().([]interface{}); ok {
srcName = strings.Join([]string{prevSource, multipleSrcName}, ",")
}
}
}
if value, err := getNestedFieldString(reflect.ValueOf(dest).Elem().Interface(), fieldName); err == nil {
fields.Set(fieldName, srcName, value)
}
}
}
return nil
}