ResourceServer: Add resource server protobuf and wrapper (#90007)
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"mime"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
@@ -20,6 +23,8 @@ const AnnoKeyUpdatedTimestamp = "grafana.app/updatedTimestamp"
|
||||
const AnnoKeyUpdatedBy = "grafana.app/updatedBy"
|
||||
const AnnoKeyFolder = "grafana.app/folder"
|
||||
const AnnoKeySlug = "grafana.app/slug"
|
||||
const AnnoKeyBlob = "grafana.app/blob"
|
||||
const AnnoKeyMessage = "grafana.app/message"
|
||||
|
||||
// Identify where values came from
|
||||
|
||||
@@ -53,6 +58,7 @@ type GrafanaMetaAccessor interface {
|
||||
metav1.Object
|
||||
|
||||
GetGroupVersionKind() schema.GroupVersionKind
|
||||
GetRuntimeObject() (runtime.Object, bool)
|
||||
|
||||
// Helper to get resource versions as int64, however this is not required
|
||||
// See: https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions
|
||||
@@ -68,11 +74,16 @@ type GrafanaMetaAccessor interface {
|
||||
SetUpdatedBy(user string)
|
||||
GetFolder() string
|
||||
SetFolder(uid string)
|
||||
GetMessage() string
|
||||
SetMessage(msg string)
|
||||
SetAnnotation(key string, val string)
|
||||
|
||||
GetSlug() string
|
||||
SetSlug(v string)
|
||||
|
||||
SetBlob(v *BlobInfo)
|
||||
GetBlob() *BlobInfo
|
||||
|
||||
GetOriginInfo() (*ResourceOriginInfo, error)
|
||||
SetOriginInfo(info *ResourceOriginInfo)
|
||||
GetOriginName() string
|
||||
@@ -80,6 +91,8 @@ type GrafanaMetaAccessor interface {
|
||||
GetOriginHash() string
|
||||
GetOriginTimestamp() (*time.Time, error)
|
||||
|
||||
GetSpec() (any, error)
|
||||
|
||||
// Find a title in the object
|
||||
// This will reflect the object and try to get:
|
||||
// * spec.title
|
||||
@@ -123,6 +136,11 @@ func (m *grafanaMetaAccessor) GetResourceVersionInt64() (int64, error) {
|
||||
return strconv.ParseInt(v, 10, 64)
|
||||
}
|
||||
|
||||
func (m *grafanaMetaAccessor) GetRuntimeObject() (runtime.Object, bool) {
|
||||
obj, ok := m.raw.(runtime.Object)
|
||||
return obj, ok
|
||||
}
|
||||
|
||||
func (m *grafanaMetaAccessor) SetResourceVersionInt64(rv int64) {
|
||||
m.obj.SetResourceVersion(strconv.FormatInt(rv, 10))
|
||||
}
|
||||
@@ -192,6 +210,17 @@ func (m *grafanaMetaAccessor) SetUpdatedBy(user string) {
|
||||
m.SetAnnotation(AnnoKeyUpdatedBy, user)
|
||||
}
|
||||
|
||||
func (m *grafanaMetaAccessor) GetBlob() *BlobInfo {
|
||||
return ParseBlobInfo(m.get(AnnoKeyBlob))
|
||||
}
|
||||
|
||||
func (m *grafanaMetaAccessor) SetBlob(info *BlobInfo) {
|
||||
if info == nil {
|
||||
m.SetAnnotation(AnnoKeyBlob, "") // delete
|
||||
}
|
||||
m.SetAnnotation(AnnoKeyBlob, info.String())
|
||||
}
|
||||
|
||||
func (m *grafanaMetaAccessor) GetFolder() string {
|
||||
return m.get(AnnoKeyFolder)
|
||||
}
|
||||
@@ -200,6 +229,14 @@ func (m *grafanaMetaAccessor) SetFolder(uid string) {
|
||||
m.SetAnnotation(AnnoKeyFolder, uid)
|
||||
}
|
||||
|
||||
func (m *grafanaMetaAccessor) GetMessage() string {
|
||||
return m.get(AnnoKeyMessage)
|
||||
}
|
||||
|
||||
func (m *grafanaMetaAccessor) SetMessage(uid string) {
|
||||
m.SetAnnotation(AnnoKeyMessage, uid)
|
||||
}
|
||||
|
||||
func (m *grafanaMetaAccessor) GetSlug() string {
|
||||
return m.get(AnnoKeySlug)
|
||||
}
|
||||
@@ -457,6 +494,16 @@ func (m *grafanaMetaAccessor) GetGroupVersionKind() schema.GroupVersionKind {
|
||||
return gvk
|
||||
}
|
||||
|
||||
func (m *grafanaMetaAccessor) GetSpec() (spec any, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("error reading spec")
|
||||
}
|
||||
}()
|
||||
spec = m.r.FieldByName("Spec").Interface()
|
||||
return
|
||||
}
|
||||
|
||||
func (m *grafanaMetaAccessor) FindTitle(defaultTitle string) string {
|
||||
// look for Spec.Title or Spec.Name
|
||||
spec := m.r.FieldByName("Spec")
|
||||
@@ -477,3 +524,82 @@ func (m *grafanaMetaAccessor) FindTitle(defaultTitle string) string {
|
||||
}
|
||||
return defaultTitle
|
||||
}
|
||||
|
||||
type BlobInfo struct {
|
||||
UID string `json:"uid"`
|
||||
Size int64 `json:"size,omitempty"`
|
||||
Hash string `json:"hash,omitempty"`
|
||||
MimeType string `json:"mime,omitempty"`
|
||||
Charset string `json:"charset,omitempty"` // content type = mime+charset
|
||||
}
|
||||
|
||||
// Content type is mime + charset
|
||||
func (b *BlobInfo) SetContentType(v string) {
|
||||
var params map[string]string
|
||||
var err error
|
||||
|
||||
b.Charset = ""
|
||||
b.MimeType, params, err = mime.ParseMediaType(v)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
b.Charset = params["charset"]
|
||||
}
|
||||
|
||||
// Content type is mime + charset
|
||||
func (b *BlobInfo) ContentType() string {
|
||||
sb := bytes.NewBufferString(b.MimeType)
|
||||
if b.Charset != "" {
|
||||
sb.WriteString("; charset=")
|
||||
sb.WriteString(b.Charset)
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func (b *BlobInfo) String() string {
|
||||
sb := bytes.NewBufferString(b.UID)
|
||||
if b.Size > 0 {
|
||||
sb.WriteString(fmt.Sprintf("; size=%d", b.Size))
|
||||
}
|
||||
if b.Hash != "" {
|
||||
sb.WriteString("; hash=")
|
||||
sb.WriteString(b.Hash)
|
||||
}
|
||||
if b.MimeType != "" {
|
||||
sb.WriteString("; mime=")
|
||||
sb.WriteString(b.MimeType)
|
||||
}
|
||||
if b.Charset != "" {
|
||||
sb.WriteString("; charset=")
|
||||
sb.WriteString(b.Charset)
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func ParseBlobInfo(v string) *BlobInfo {
|
||||
if v == "" {
|
||||
return nil
|
||||
}
|
||||
info := &BlobInfo{}
|
||||
for i, part := range strings.Split(v, ";") {
|
||||
if i == 0 {
|
||||
info.UID = part
|
||||
continue
|
||||
}
|
||||
kv := strings.Split(strings.TrimSpace(part), "=")
|
||||
if len(kv) == 2 {
|
||||
val := kv[1]
|
||||
switch kv[0] {
|
||||
case "size":
|
||||
info.Size, _ = strconv.ParseInt(val, 10, 64)
|
||||
case "hash":
|
||||
info.Hash = val
|
||||
case "mime":
|
||||
info.MimeType = val
|
||||
case "charset":
|
||||
info.Charset = val
|
||||
}
|
||||
}
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
@@ -172,6 +172,14 @@ func TestMetaAccessor(t *testing.T) {
|
||||
require.Equal(t, int64(12345), rv)
|
||||
})
|
||||
|
||||
t.Run("blob info", func(t *testing.T) {
|
||||
info := &utils.BlobInfo{UID: "AAA", Size: 123, Hash: "xyz", MimeType: "application/json", Charset: "utf-8"}
|
||||
anno := info.String()
|
||||
require.Equal(t, "AAA; size=123; hash=xyz; mime=application/json; charset=utf-8", anno)
|
||||
copy := utils.ParseBlobInfo(anno)
|
||||
require.Equal(t, info, copy)
|
||||
})
|
||||
|
||||
t.Run("find titles", func(t *testing.T) {
|
||||
// with a k8s object that has Spec.Title
|
||||
obj := &TestResource{
|
||||
@@ -220,5 +228,13 @@ func TestMetaAccessor(t *testing.T) {
|
||||
}, obj2.GetAnnotations())
|
||||
|
||||
require.Equal(t, "xxx", meta.FindTitle("xxx"))
|
||||
|
||||
rt, ok := meta.GetRuntimeObject()
|
||||
require.Equal(t, obj2, rt)
|
||||
require.True(t, ok)
|
||||
|
||||
spec, err := meta.GetSpec()
|
||||
require.Equal(t, obj2.Spec, spec)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user