diff --git a/pkg/util/attributes/parser.go b/pkg/util/attributes/parser.go index 28e17b6b81..cef7359855 100644 --- a/pkg/util/attributes/parser.go +++ b/pkg/util/attributes/parser.go @@ -48,7 +48,8 @@ func ParseV2Attributes(attrs []string, excl []string) ([]*netmap.NodeAttribute, key := pair[0] value := pair[1] - if at, ok := cache[key]; ok && at.Value() != value { + attribute, present := cache[key] + if present && attribute.Value() != value { return nil, errNonUniqueBucket } @@ -56,20 +57,26 @@ func ParseV2Attributes(attrs []string, excl []string) ([]*netmap.NodeAttribute, return nil, errUnexpectedKey } - // replace non-printable symbols with escaped symbols without escape character - key = replaceEscaping(key, true) - value = replaceEscaping(value, true) + if !present { + // replace non-printable symbols with escaped symbols without escape character + key = replaceEscaping(key, true) + value = replaceEscaping(value, true) - attribute := netmap.NewNodeAttribute() - attribute.SetKey(key) - attribute.SetValue(value) + attribute = netmap.NewNodeAttribute() + attribute.SetKey(key) + attribute.SetValue(value) + + cache[key] = attribute + } if parentKey != "" { - attribute.SetParentKeys(parentKey) + parentKeys := attribute.ParentKeys() + if !hasString(parentKeys, parentKey) { + attribute.SetParentKeys(append(parentKeys, parentKey)...) + } } parentKey = key - cache[key] = attribute } } @@ -106,3 +113,12 @@ func replaceEscaping(target string, rollback bool) (s string) { return } + +func hasString(lst []string, v string) bool { + for i := range lst { + if lst[i] == v { + return true + } + } + return false +} diff --git a/pkg/util/attributes/parser_test.go b/pkg/util/attributes/parser_test.go index bd06644f98..305f55830c 100644 --- a/pkg/util/attributes/parser_test.go +++ b/pkg/util/attributes/parser_test.go @@ -25,7 +25,6 @@ func TestParseV2Attributes(t *testing.T) { bad := append(good, "StorageType:SSD/Cell:QLC") _, err = attributes.ParseV2Attributes(bad, nil) require.Error(t, err) - }) t.Run("malformed", func(t *testing.T) { @@ -69,4 +68,30 @@ func TestParseV2Attributes(t *testing.T) { require.Equal(t, attrs[1].Key(), `Ke/y2`) require.Equal(t, attrs[1].Value(), `Va:lue`) }) + + t.Run("same attributes", func(t *testing.T) { + from := []string{"/a:b", "/a:b"} + attrs, err := attributes.ParseV2Attributes(from, nil) + require.NoError(t, err) + require.Len(t, attrs, 1) + }) + + t.Run("multiple parents", func(t *testing.T) { + from := []string{ + "/parent1:x/child:x", + "/parent2:x/child:x", + "/parent2:x/child:x/subchild:x", + } + attrs, err := attributes.ParseV2Attributes(from, nil) + require.NoError(t, err) + + var flag bool + for _, attr := range attrs { + if attr.Key() == "child" { + flag = true + require.Equal(t, attr.ParentKeys(), []string{"parent1", "parent2"}) + } + } + require.True(t, flag) + }) }