From 7b780612355057dca97b903fa15cde8de82f44c8 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Mon, 4 Dec 2023 18:20:17 -0800 Subject: [PATCH] K8s: Add grafana metadata accessor (#79050) --- pkg/kinds/general.go | 216 ++++++++++++++++++++++++++++++++++++-- pkg/kinds/general_test.go | 35 ++++++ 2 files changed, 240 insertions(+), 11 deletions(-) create mode 100644 pkg/kinds/general_test.go diff --git a/pkg/kinds/general.go b/pkg/kinds/general.go index 691e7cd2528..e8fd41e3e19 100644 --- a/pkg/kinds/general.go +++ b/pkg/kinds/general.go @@ -136,7 +136,7 @@ func (m *GrafanaResourceMetadata) SetOriginInfo(info *ResourceOriginInfo) { delete(m.Annotations, annoKeyOriginPath) delete(m.Annotations, annoKeyOriginKey) delete(m.Annotations, annoKeyOriginTimestamp) - if info != nil || info.Name != "" { + if info != nil && info.Name != "" { m.set(annoKeyOriginName, info.Name) m.set(annoKeyOriginKey, info.Key) m.set(annoKeyOriginPath, info.Path) @@ -152,17 +152,211 @@ func (m *GrafanaResourceMetadata) GetOriginInfo() *ResourceOriginInfo { if !ok { return nil } - info := &ResourceOriginInfo{ - Name: v, - Path: m.Annotations[annoKeyOriginPath], - Key: m.Annotations[annoKeyOriginKey], + return &ResourceOriginInfo{ + Name: v, + Path: m.GetOriginPath(), + Key: m.GetOriginKey(), + Timestamp: m.GetOriginTimestamp(), } - v, ok = m.Annotations[annoKeyOriginTimestamp] - if ok { - t, err := time.Parse(time.RFC3339, v) - if err != nil { - info.Timestamp = &t +} + +func (m *GrafanaResourceMetadata) GetOriginName() string { + return m.Annotations[annoKeyOriginName] +} + +func (m *GrafanaResourceMetadata) GetOriginPath() string { + return m.Annotations[annoKeyOriginPath] +} + +func (m *GrafanaResourceMetadata) GetOriginKey() string { + return m.Annotations[annoKeyOriginKey] +} + +func (m *GrafanaResourceMetadata) GetOriginTimestamp() *time.Time { + v, ok := m.Annotations[annoKeyOriginTimestamp] + if !ok { + return nil + } + t, err := time.Parse(time.RFC3339, v) + if err != nil { + return nil + } + return &t +} + +// Accessor functions for k8s objects +type GrafanaResourceMetaAccessor interface { + GetUpdatedTimestamp() *time.Time + SetUpdatedTimestamp(v *time.Time) + GetCreatedBy() string + SetCreatedBy(user string) + GetUpdatedBy() string + SetUpdatedBy(user string) + GetFolder() string + SetFolder(uid string) + GetSlug() string + SetSlug(v string) + GetOriginInfo() *ResourceOriginInfo + SetOriginInfo(info *ResourceOriginInfo) + GetOriginName() string + GetOriginPath() string + GetOriginKey() string + GetOriginTimestamp() *time.Time +} + +var _ GrafanaResourceMetaAccessor = (*grafanaResourceMetaAccessor)(nil) +var _ GrafanaResourceMetaAccessor = (*GrafanaResourceMetadata)(nil) + +type grafanaResourceMetaAccessor struct { + obj v1.Object +} + +func MetaAccessor(obj v1.Object) GrafanaResourceMetaAccessor { + return &grafanaResourceMetaAccessor{obj} +} + +func (m *grafanaResourceMetaAccessor) set(key string, val string) { + anno := m.obj.GetAnnotations() + if val == "" { + if anno != nil { + delete(anno, key) + } + } else { + if anno == nil { + anno = make(map[string]string) + } + anno[key] = val + } + m.obj.SetAnnotations(anno) +} + +func (m *grafanaResourceMetaAccessor) get(key string) string { + return m.obj.GetAnnotations()[key] +} + +func (m *grafanaResourceMetaAccessor) GetUpdatedTimestamp() *time.Time { + v, ok := m.obj.GetAnnotations()[annoKeyUpdatedTimestamp] + if !ok { + return nil + } + t, err := time.Parse(time.RFC3339, v) + if err != nil { + return nil + } + return &t +} + +func (m *grafanaResourceMetaAccessor) SetUpdatedTimestampMillis(v int64) { + if v > 0 { + t := time.UnixMilli(v) + m.SetUpdatedTimestamp(&t) + } else { + m.SetUpdatedTimestamp(nil) + } +} + +func (m *grafanaResourceMetaAccessor) SetUpdatedTimestamp(v *time.Time) { + txt := "" + if v != nil { + txt = v.UTC().Format(time.RFC3339) + } + m.set(annoKeyUpdatedTimestamp, txt) +} + +func (m *grafanaResourceMetaAccessor) GetCreatedBy() string { + return m.get(annoKeyCreatedBy) +} + +func (m *grafanaResourceMetaAccessor) SetCreatedBy(user string) { + m.set(annoKeyCreatedBy, user) +} + +func (m *grafanaResourceMetaAccessor) GetUpdatedBy() string { + return m.get(annoKeyUpdatedBy) +} + +func (m *grafanaResourceMetaAccessor) SetUpdatedBy(user string) { + m.set(annoKeyUpdatedBy, user) +} + +func (m *grafanaResourceMetaAccessor) GetFolder() string { + return m.get(annoKeyFolder) +} + +func (m *grafanaResourceMetaAccessor) SetFolder(uid string) { + m.set(annoKeyFolder, uid) +} + +func (m *grafanaResourceMetaAccessor) GetSlug() string { + return m.get(annoKeySlug) +} + +func (m *grafanaResourceMetaAccessor) SetSlug(v string) { + m.set(annoKeySlug, v) +} + +func (m *grafanaResourceMetaAccessor) SetOriginInfo(info *ResourceOriginInfo) { + anno := m.obj.GetAnnotations() + if anno == nil { + if info == nil { + return + } + anno = make(map[string]string, 0) + m.obj.SetAnnotations(anno) + } + + delete(anno, annoKeyOriginName) + delete(anno, annoKeyOriginPath) + delete(anno, annoKeyOriginKey) + delete(anno, annoKeyOriginTimestamp) + if info != nil && info.Name != "" { + anno[annoKeyOriginName] = info.Name + if info.Path != "" { + anno[annoKeyOriginPath] = info.Path + } + if info.Key != "" { + anno[annoKeyOriginKey] = info.Key + } + if info.Timestamp != nil { + anno[annoKeyOriginTimestamp] = info.Timestamp.Format(time.RFC3339) } } - return info + m.obj.SetAnnotations(anno) +} + +func (m *grafanaResourceMetaAccessor) GetOriginInfo() *ResourceOriginInfo { + v, ok := m.obj.GetAnnotations()[annoKeyOriginName] + if !ok { + return nil + } + return &ResourceOriginInfo{ + Name: v, + Path: m.GetOriginPath(), + Key: m.GetOriginKey(), + Timestamp: m.GetOriginTimestamp(), + } +} + +func (m *grafanaResourceMetaAccessor) GetOriginName() string { + return m.get(annoKeyOriginName) +} + +func (m *grafanaResourceMetaAccessor) GetOriginPath() string { + return m.get(annoKeyOriginPath) +} + +func (m *grafanaResourceMetaAccessor) GetOriginKey() string { + return m.get(annoKeyOriginKey) +} + +func (m *grafanaResourceMetaAccessor) GetOriginTimestamp() *time.Time { + v, ok := m.obj.GetAnnotations()[annoKeyOriginTimestamp] + if !ok { + return nil + } + t, err := time.Parse(time.RFC3339, v) + if err != nil { + return nil + } + return &t } diff --git a/pkg/kinds/general_test.go b/pkg/kinds/general_test.go new file mode 100644 index 00000000000..6f5f74d7bd1 --- /dev/null +++ b/pkg/kinds/general_test.go @@ -0,0 +1,35 @@ +package kinds + +import ( + "testing" + + "github.com/stretchr/testify/require" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" +) + +func TestMetaAccessor(t *testing.T) { + originInfo := &ResourceOriginInfo{ + Name: "test", + Path: "a/b/c", + Key: "kkk", + } + + // Verify that you can set annotations when they do not exist + dummy := &GrafanaResourceMetadata{} + dummy.SetOriginInfo(originInfo) + dummy.SetFolder("folderUID") + + // with any k8s object + obj := &unstructured.Unstructured{} + meta := MetaAccessor(obj) + meta.SetOriginInfo(originInfo) + meta.SetFolder("folderUID") + + require.Equal(t, map[string]string{ + "grafana.app/originName": "test", + "grafana.app/originPath": "a/b/c", + "grafana.app/originKey": "kkk", + "grafana.app/folder": "folderUID", + }, dummy.Annotations) + require.Equal(t, dummy.Annotations, obj.GetAnnotations()) +}