diff --git a/pkg/apimachinery/utils/meta.go b/pkg/apimachinery/utils/meta.go index 17f69da01a5..bdf9a100540 100644 --- a/pkg/apimachinery/utils/meta.go +++ b/pkg/apimachinery/utils/meta.go @@ -836,7 +836,7 @@ func (m *grafanaMetaAccessor) SetSourceProperties(v SourceProperties) { func (m *grafanaMetaAccessor) GetSecureValues() (vals common.InlineSecureValues, err error) { defer func() { if r := recover(); r != nil { - err = fmt.Errorf("error reading spec") + err = fmt.Errorf("error reading secure values") } }() @@ -888,7 +888,7 @@ func (m *grafanaMetaAccessor) GetSecureValues() (vals common.InlineSecureValues, if f.Kind() == reflect.Struct { num := f.NumField() vals = make(common.InlineSecureValues, num) - for i := 0; i < f.NumField(); i++ { + for i := range num { val := f.Field(i) if val.IsValid() && val.CanInterface() { property = val.Interface() @@ -901,14 +901,7 @@ func (m *grafanaMetaAccessor) GetSecureValues() (vals common.InlineSecureValues, continue // nothing } - field := f.Type().Field(i) - fname := field.Tag.Get("json") - if fname == "" { - fname = field.Name - } else { - fname, _ = strings.CutSuffix(fname, ",omitempty") - } - vals[fname] = inline + vals[getJSONFieldName(f, i)] = inline continue } return nil, fmt.Errorf("value not an interface") @@ -923,12 +916,36 @@ func (m *grafanaMetaAccessor) GetSecureValues() (vals common.InlineSecureValues, func (m *grafanaMetaAccessor) SetSecureValues(vals common.InlineSecureValues) (err error) { defer func() { if r := recover(); r != nil { - err = fmt.Errorf("error setting spec") + fmt.Printf("ERR: %v", r) + err = fmt.Errorf("error writing secure values") } }() f := m.r.FieldByName("Secure") if f.IsValid() && f.CanSet() { + if f.Kind() == reflect.Struct { + keys := make(map[string]bool, len(vals)) + for k := range vals { + keys[k] = true + } + for i := 0; i < f.NumField(); i++ { + val := f.Field(i) + if val.IsValid() && val.CanInterface() && val.CanSet() { + k := getJSONFieldName(f, i) + sv := vals[k] + val.Set(reflect.ValueOf(sv)) + delete(keys, k) + } else { + return fmt.Errorf("invalid secure value: %v", val) + } + } + if len(keys) > 0 { + return fmt.Errorf("invalid secure value key: %v", keys) + } + return + } + + // It should be a generic map f.Set(reflect.ValueOf(vals)) return } @@ -943,6 +960,16 @@ func (m *grafanaMetaAccessor) SetSecureValues(vals common.InlineSecureValues) (e return fmt.Errorf("unable to set secure values on (%T)", m.raw) } +func getJSONFieldName(f reflect.Value, idx int) string { + field := f.Type().Field(idx) + fname := field.Tag.Get("json") + if fname == "" { + return field.Name + } + fname, _ = strings.CutSuffix(fname, ",omitempty") + return fname +} + func ToObjectReference(obj GrafanaMetaAccessor) common.ObjectReference { gvk := obj.GetGroupVersionKind() return common.ObjectReference{ diff --git a/pkg/apimachinery/utils/meta_test.go b/pkg/apimachinery/utils/meta_test.go index 7bc63884699..54db0fbe976 100644 --- a/pkg/apimachinery/utils/meta_test.go +++ b/pkg/apimachinery/utils/meta_test.go @@ -400,6 +400,20 @@ func TestMetaAccessor(t *testing.T) { secure, err := meta.GetSecureValues() require.NoError(t, err) require.JSONEq(t, `{"v1": {"name": "hello"}}`, asJSON(secure, true)) + + // Check that we can write + err = meta.SetSecureValues(common.InlineSecureValues{ + "v2": {Name: "bbb"}, + }) + require.NoError(t, err) + secure, err = meta.GetSecureValues() + require.NoError(t, err) + require.JSONEq(t, `{"v2": {"name": "bbb"}}`, asJSON(secure, true)) // NOTE: v1 was removed + + err = meta.SetSecureValues(common.InlineSecureValues{ + "UNKNOWN": {Name: "bbb"}, // not a valid name + }) + require.Error(t, err) }) t.Run("test reading old repo fields (now manager+source)", func(t *testing.T) {