mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Kinds: Use apimachinery ObjectMeta for metadata (#68668)
This commit is contained in:
parent
f91c1b9897
commit
c66d5721f7
go.modgo.sum
pkg
codegen
kinds
services
dashboards
libraryelements/model
playlist
team
7
go.mod
7
go.mod
@ -121,7 +121,7 @@ require (
|
|||||||
gopkg.in/mail.v2 v2.3.1
|
gopkg.in/mail.v2 v2.3.1
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
xorm.io/builder v0.3.6
|
xorm.io/builder v0.3.6 // indirect
|
||||||
xorm.io/core v0.7.3
|
xorm.io/core v0.7.3
|
||||||
xorm.io/xorm v0.8.2
|
xorm.io/xorm v0.8.2
|
||||||
)
|
)
|
||||||
@ -300,6 +300,7 @@ require (
|
|||||||
github.com/getsentry/sentry-go v0.12.0 // indirect
|
github.com/getsentry/sentry-go v0.12.0 // indirect
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
|
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
|
||||||
github.com/google/go-querystring v1.1.0 // indirect
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
|
github.com/google/gofuzz v1.2.0 // indirect
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
|
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
|
||||||
github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd // indirect
|
github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd // indirect
|
||||||
github.com/grafana/sqlds/v2 v2.3.10 // indirect
|
github.com/grafana/sqlds/v2 v2.3.10 // indirect
|
||||||
@ -334,6 +335,10 @@ require (
|
|||||||
go.opentelemetry.io/otel/metric v0.37.0 // indirect
|
go.opentelemetry.io/otel/metric v0.37.0 // indirect
|
||||||
go.starlark.net v0.0.0-20221020143700-22309ac47eac // indirect
|
go.starlark.net v0.0.0-20221020143700-22309ac47eac // indirect
|
||||||
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
|
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
|
||||||
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
|
k8s.io/klog/v2 v2.90.1 // indirect
|
||||||
|
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
1
go.sum
1
go.sum
@ -2904,7 +2904,6 @@ k8s.io/apimachinery v0.26.2/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5
|
|||||||
k8s.io/client-go v0.25.3 h1:oB4Dyl8d6UbfDHD8Bv8evKylzs3BXzzufLiO27xuPs0=
|
k8s.io/client-go v0.25.3 h1:oB4Dyl8d6UbfDHD8Bv8evKylzs3BXzzufLiO27xuPs0=
|
||||||
k8s.io/client-go v0.25.3/go.mod h1:t39LPczAIMwycjcXkVc+CB+PZV69jQuNx4um5ORDjQA=
|
k8s.io/client-go v0.25.3/go.mod h1:t39LPczAIMwycjcXkVc+CB+PZV69jQuNx4um5ORDjQA=
|
||||||
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||||
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
|
|
||||||
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
||||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||||
|
@ -48,6 +48,7 @@ func (ag *ResourceGoTypesJenny) Generate(kind kindsys.Kind) (*codejen.File, erro
|
|||||||
if err := tmpls.Lookup("core_resource.tmpl").Execute(buf, tvars_resource{
|
if err := tmpls.Lookup("core_resource.tmpl").Execute(buf, tvars_resource{
|
||||||
PackageName: mname,
|
PackageName: mname,
|
||||||
KindName: kind.Props().Common().Name,
|
KindName: kind.Props().Common().Name,
|
||||||
|
Version: sch.Version().String(),
|
||||||
SubresourceNames: subr,
|
SubresourceNames: subr,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, fmt.Errorf("failed executing core resource template: %w", err)
|
return nil, fmt.Errorf("failed executing core resource template: %w", err)
|
||||||
|
@ -41,6 +41,7 @@ type (
|
|||||||
tvars_resource struct {
|
tvars_resource struct {
|
||||||
PackageName string
|
PackageName string
|
||||||
KindName string
|
KindName string
|
||||||
|
Version string
|
||||||
SubresourceNames []string
|
SubresourceNames []string
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -1,6 +1,29 @@
|
|||||||
package {{ .PackageName }}
|
package {{ .PackageName }}
|
||||||
|
|
||||||
// Resource is the wire representation of {{ .KindName }}. (TODO be better)
|
import (
|
||||||
|
"github.com/grafana/grafana/pkg/kinds"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Resource is the kubernetes style representation of {{ .KindName }}. (TODO be better)
|
||||||
|
type K8sResource = kinds.GrafanaResource[Spec, Status]
|
||||||
|
|
||||||
|
// NewResource creates a new instance of the resource with a given name (UID)
|
||||||
|
func NewK8sResource(name string, s *Spec) K8sResource {
|
||||||
|
return K8sResource{
|
||||||
|
Kind: "{{ .KindName }}",
|
||||||
|
APIVersion: "v{{ .Version }}-alpha",
|
||||||
|
Metadata: kinds.GrafanaResourceMetadata{
|
||||||
|
Name: name,
|
||||||
|
Annotations: make(map[string]string),
|
||||||
|
Labels: make(map[string]string),
|
||||||
|
},
|
||||||
|
Spec: s,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Resource is the wire representation of {{ .KindName }}.
|
||||||
|
// It currently will soon be merged into the k8s flavor (TODO be better)
|
||||||
type Resource struct {
|
type Resource struct {
|
||||||
{{- range .SubresourceNames }}
|
{{- range .SubresourceNames }}
|
||||||
{{ . }} {{ . }} `json:"{{ . | ToLower }}"`{{end}}
|
{{ . }} {{ . }} `json:"{{ . | ToLower }}"`{{end}}
|
||||||
|
@ -9,7 +9,30 @@
|
|||||||
|
|
||||||
package dashboard
|
package dashboard
|
||||||
|
|
||||||
// Resource is the wire representation of Dashboard. (TODO be better)
|
import (
|
||||||
|
"github.com/grafana/grafana/pkg/kinds"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Resource is the kubernetes style representation of Dashboard. (TODO be better)
|
||||||
|
type K8sResource = kinds.GrafanaResource[Spec, Status]
|
||||||
|
|
||||||
|
// NewResource creates a new instance of the resource with a given name (UID)
|
||||||
|
func NewK8sResource(name string, s *Spec) K8sResource {
|
||||||
|
return K8sResource{
|
||||||
|
Kind: "Dashboard",
|
||||||
|
APIVersion: "v0.0-alpha",
|
||||||
|
Metadata: kinds.GrafanaResourceMetadata{
|
||||||
|
Name: name,
|
||||||
|
Annotations: make(map[string]string),
|
||||||
|
Labels: make(map[string]string),
|
||||||
|
},
|
||||||
|
Spec: s,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Resource is the wire representation of Dashboard.
|
||||||
|
// It currently will soon be merged into the k8s flavor (TODO be better)
|
||||||
type Resource struct {
|
type Resource struct {
|
||||||
Metadata Metadata `json:"metadata"`
|
Metadata Metadata `json:"metadata"`
|
||||||
Spec Spec `json:"spec"`
|
Spec Spec `json:"spec"`
|
||||||
|
@ -9,7 +9,30 @@
|
|||||||
|
|
||||||
package folder
|
package folder
|
||||||
|
|
||||||
// Resource is the wire representation of Folder. (TODO be better)
|
import (
|
||||||
|
"github.com/grafana/grafana/pkg/kinds"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Resource is the kubernetes style representation of Folder. (TODO be better)
|
||||||
|
type K8sResource = kinds.GrafanaResource[Spec, Status]
|
||||||
|
|
||||||
|
// NewResource creates a new instance of the resource with a given name (UID)
|
||||||
|
func NewK8sResource(name string, s *Spec) K8sResource {
|
||||||
|
return K8sResource{
|
||||||
|
Kind: "Folder",
|
||||||
|
APIVersion: "v0.0-alpha",
|
||||||
|
Metadata: kinds.GrafanaResourceMetadata{
|
||||||
|
Name: name,
|
||||||
|
Annotations: make(map[string]string),
|
||||||
|
Labels: make(map[string]string),
|
||||||
|
},
|
||||||
|
Spec: s,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Resource is the wire representation of Folder.
|
||||||
|
// It currently will soon be merged into the k8s flavor (TODO be better)
|
||||||
type Resource struct {
|
type Resource struct {
|
||||||
Metadata Metadata `json:"metadata"`
|
Metadata Metadata `json:"metadata"`
|
||||||
Spec Spec `json:"spec"`
|
Spec Spec `json:"spec"`
|
||||||
|
150
pkg/kinds/general.go
Normal file
150
pkg/kinds/general.go
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
package kinds
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ResourceOriginInfo is saved in annotations. This is used to identify where the resource came from
|
||||||
|
// This object can model the same data as our existing provisioning table or a more general git sync
|
||||||
|
type ResourceOriginInfo struct {
|
||||||
|
// Name of the origin/provisioning source
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
|
||||||
|
// The path within the named origin above (external_id in the existing dashboard provisioing)
|
||||||
|
Path string `json:"path,omitempty"`
|
||||||
|
|
||||||
|
// Verification/identification key (check_sum in existing dashboard provisioning)
|
||||||
|
Key string `json:"key,omitempty"`
|
||||||
|
|
||||||
|
// Origin modification timestamp when the resource was saved
|
||||||
|
// This will be before the resource updated time
|
||||||
|
Timestamp *time.Time `json:"time,omitempty"`
|
||||||
|
|
||||||
|
// Avoid extending
|
||||||
|
_ interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GrafanaResourceMetadata is standard k8s object metadata with helper functions
|
||||||
|
type GrafanaResourceMetadata v1.ObjectMeta
|
||||||
|
|
||||||
|
// GrafanaResource is a generic kubernetes resource with a helper for the common grafana metadata
|
||||||
|
// This is a temporary solution until this object (or similar) can be moved to the app-sdk or kindsys
|
||||||
|
type GrafanaResource[Spec interface{}, Status interface{}] struct {
|
||||||
|
APIVersion string `json:"apiVersion"`
|
||||||
|
Kind string `json:"kind"`
|
||||||
|
|
||||||
|
Metadata GrafanaResourceMetadata `json:"metadata"`
|
||||||
|
Spec *Spec `json:"spec,omitempty"`
|
||||||
|
Status *Status `json:"status,omitempty"`
|
||||||
|
|
||||||
|
// Avoid extending
|
||||||
|
_ interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Annotation keys
|
||||||
|
const annoKeyCreatedBy = "grafana.com/createdBy"
|
||||||
|
const annoKeyUpdatedTimestamp = "grafana.com/updatedTimestamp"
|
||||||
|
const annoKeyUpdatedBy = "grafana.com/updatedBy"
|
||||||
|
|
||||||
|
// The folder identifier
|
||||||
|
const annoKeyFolder = "grafana.com/folder"
|
||||||
|
const annoKeySlug = "grafana.com/slug"
|
||||||
|
|
||||||
|
// Identify where values came from
|
||||||
|
const annoKeyOriginName = "grafana.com/origin/name"
|
||||||
|
const annoKeyOriginPath = "grafana.com/origin/path"
|
||||||
|
const annoKeyOriginKey = "grafana.com/origin/key"
|
||||||
|
const annoKeyOriginTime = "grafana.com/origin/time"
|
||||||
|
|
||||||
|
func (m *GrafanaResourceMetadata) GetUpdatedTimestamp() *time.Time {
|
||||||
|
v, ok := m.Annotations[annoKeyUpdatedTimestamp]
|
||||||
|
if ok {
|
||||||
|
t, err := time.Parse(time.RFC3339, v)
|
||||||
|
if err != nil {
|
||||||
|
return &t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GrafanaResourceMetadata) SetUpdatedTimestamp(v *time.Time) {
|
||||||
|
if v == nil {
|
||||||
|
delete(m.Annotations, annoKeyUpdatedTimestamp)
|
||||||
|
} else {
|
||||||
|
m.Annotations[annoKeyUpdatedTimestamp] = v.Format(time.RFC3339)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GrafanaResourceMetadata) GetCreatedBy() string {
|
||||||
|
return m.Annotations[annoKeyCreatedBy]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GrafanaResourceMetadata) SetCreatedBy(user string) {
|
||||||
|
m.Annotations[annoKeyCreatedBy] = user // user GRN
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GrafanaResourceMetadata) GetUpdatedBy() string {
|
||||||
|
return m.Annotations[annoKeyUpdatedBy]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GrafanaResourceMetadata) SetUpdatedBy(user string) {
|
||||||
|
m.Annotations[annoKeyUpdatedBy] = user // user GRN
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GrafanaResourceMetadata) GetFolder() string {
|
||||||
|
return m.Annotations[annoKeyFolder]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GrafanaResourceMetadata) SetFolder(uid string) {
|
||||||
|
m.Annotations[annoKeyFolder] = uid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GrafanaResourceMetadata) GetSlug() string {
|
||||||
|
return m.Annotations[annoKeySlug]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GrafanaResourceMetadata) SetSlug(v string) {
|
||||||
|
m.Annotations[annoKeySlug] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GrafanaResourceMetadata) SetOriginInfo(info *ResourceOriginInfo) {
|
||||||
|
delete(m.Annotations, annoKeyOriginName)
|
||||||
|
delete(m.Annotations, annoKeyOriginPath)
|
||||||
|
delete(m.Annotations, annoKeyOriginKey)
|
||||||
|
delete(m.Annotations, annoKeyOriginTime)
|
||||||
|
if info != nil || info.Name != "" {
|
||||||
|
m.Annotations[annoKeyOriginName] = info.Name
|
||||||
|
if info.Path != "" {
|
||||||
|
m.Annotations[annoKeyOriginPath] = info.Path
|
||||||
|
}
|
||||||
|
if info.Key != "" {
|
||||||
|
m.Annotations[annoKeyOriginKey] = info.Key
|
||||||
|
}
|
||||||
|
if info.Timestamp != nil {
|
||||||
|
m.Annotations[annoKeyOriginTime] = info.Timestamp.Format(time.RFC3339)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOriginInfo returns the origin info stored in k8s metadata annotations
|
||||||
|
func (m *GrafanaResourceMetadata) GetOriginInfo() *ResourceOriginInfo {
|
||||||
|
v, ok := m.Annotations[annoKeyOriginName]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
info := &ResourceOriginInfo{
|
||||||
|
Name: v,
|
||||||
|
Path: m.Annotations[annoKeyOriginPath],
|
||||||
|
Key: m.Annotations[annoKeyOriginKey],
|
||||||
|
}
|
||||||
|
v, ok = m.Annotations[annoKeyOriginTime]
|
||||||
|
if ok {
|
||||||
|
t, err := time.Parse(time.RFC3339, v)
|
||||||
|
if err != nil {
|
||||||
|
info.Timestamp = &t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return info
|
||||||
|
}
|
@ -9,7 +9,30 @@
|
|||||||
|
|
||||||
package librarypanel
|
package librarypanel
|
||||||
|
|
||||||
// Resource is the wire representation of LibraryPanel. (TODO be better)
|
import (
|
||||||
|
"github.com/grafana/grafana/pkg/kinds"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Resource is the kubernetes style representation of LibraryPanel. (TODO be better)
|
||||||
|
type K8sResource = kinds.GrafanaResource[Spec, Status]
|
||||||
|
|
||||||
|
// NewResource creates a new instance of the resource with a given name (UID)
|
||||||
|
func NewK8sResource(name string, s *Spec) K8sResource {
|
||||||
|
return K8sResource{
|
||||||
|
Kind: "LibraryPanel",
|
||||||
|
APIVersion: "v0.0-alpha",
|
||||||
|
Metadata: kinds.GrafanaResourceMetadata{
|
||||||
|
Name: name,
|
||||||
|
Annotations: make(map[string]string),
|
||||||
|
Labels: make(map[string]string),
|
||||||
|
},
|
||||||
|
Spec: s,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Resource is the wire representation of LibraryPanel.
|
||||||
|
// It currently will soon be merged into the k8s flavor (TODO be better)
|
||||||
type Resource struct {
|
type Resource struct {
|
||||||
Metadata Metadata `json:"metadata"`
|
Metadata Metadata `json:"metadata"`
|
||||||
Spec Spec `json:"spec"`
|
Spec Spec `json:"spec"`
|
||||||
|
@ -9,7 +9,30 @@
|
|||||||
|
|
||||||
package playlist
|
package playlist
|
||||||
|
|
||||||
// Resource is the wire representation of Playlist. (TODO be better)
|
import (
|
||||||
|
"github.com/grafana/grafana/pkg/kinds"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Resource is the kubernetes style representation of Playlist. (TODO be better)
|
||||||
|
type K8sResource = kinds.GrafanaResource[Spec, Status]
|
||||||
|
|
||||||
|
// NewResource creates a new instance of the resource with a given name (UID)
|
||||||
|
func NewK8sResource(name string, s *Spec) K8sResource {
|
||||||
|
return K8sResource{
|
||||||
|
Kind: "Playlist",
|
||||||
|
APIVersion: "v0.0-alpha",
|
||||||
|
Metadata: kinds.GrafanaResourceMetadata{
|
||||||
|
Name: name,
|
||||||
|
Annotations: make(map[string]string),
|
||||||
|
Labels: make(map[string]string),
|
||||||
|
},
|
||||||
|
Spec: s,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Resource is the wire representation of Playlist.
|
||||||
|
// It currently will soon be merged into the k8s flavor (TODO be better)
|
||||||
type Resource struct {
|
type Resource struct {
|
||||||
Metadata Metadata `json:"metadata"`
|
Metadata Metadata `json:"metadata"`
|
||||||
Spec Spec `json:"spec"`
|
Spec Spec `json:"spec"`
|
||||||
|
@ -9,7 +9,30 @@
|
|||||||
|
|
||||||
package preferences
|
package preferences
|
||||||
|
|
||||||
// Resource is the wire representation of Preferences. (TODO be better)
|
import (
|
||||||
|
"github.com/grafana/grafana/pkg/kinds"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Resource is the kubernetes style representation of Preferences. (TODO be better)
|
||||||
|
type K8sResource = kinds.GrafanaResource[Spec, Status]
|
||||||
|
|
||||||
|
// NewResource creates a new instance of the resource with a given name (UID)
|
||||||
|
func NewK8sResource(name string, s *Spec) K8sResource {
|
||||||
|
return K8sResource{
|
||||||
|
Kind: "Preferences",
|
||||||
|
APIVersion: "v0.0-alpha",
|
||||||
|
Metadata: kinds.GrafanaResourceMetadata{
|
||||||
|
Name: name,
|
||||||
|
Annotations: make(map[string]string),
|
||||||
|
Labels: make(map[string]string),
|
||||||
|
},
|
||||||
|
Spec: s,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Resource is the wire representation of Preferences.
|
||||||
|
// It currently will soon be merged into the k8s flavor (TODO be better)
|
||||||
type Resource struct {
|
type Resource struct {
|
||||||
Metadata Metadata `json:"metadata"`
|
Metadata Metadata `json:"metadata"`
|
||||||
Spec Spec `json:"spec"`
|
Spec Spec `json:"spec"`
|
||||||
|
@ -9,7 +9,30 @@
|
|||||||
|
|
||||||
package publicdashboard
|
package publicdashboard
|
||||||
|
|
||||||
// Resource is the wire representation of PublicDashboard. (TODO be better)
|
import (
|
||||||
|
"github.com/grafana/grafana/pkg/kinds"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Resource is the kubernetes style representation of PublicDashboard. (TODO be better)
|
||||||
|
type K8sResource = kinds.GrafanaResource[Spec, Status]
|
||||||
|
|
||||||
|
// NewResource creates a new instance of the resource with a given name (UID)
|
||||||
|
func NewK8sResource(name string, s *Spec) K8sResource {
|
||||||
|
return K8sResource{
|
||||||
|
Kind: "PublicDashboard",
|
||||||
|
APIVersion: "v0.0-alpha",
|
||||||
|
Metadata: kinds.GrafanaResourceMetadata{
|
||||||
|
Name: name,
|
||||||
|
Annotations: make(map[string]string),
|
||||||
|
Labels: make(map[string]string),
|
||||||
|
},
|
||||||
|
Spec: s,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Resource is the wire representation of PublicDashboard.
|
||||||
|
// It currently will soon be merged into the k8s flavor (TODO be better)
|
||||||
type Resource struct {
|
type Resource struct {
|
||||||
Metadata Metadata `json:"metadata"`
|
Metadata Metadata `json:"metadata"`
|
||||||
Spec Spec `json:"spec"`
|
Spec Spec `json:"spec"`
|
||||||
|
@ -9,7 +9,30 @@
|
|||||||
|
|
||||||
package serviceaccount
|
package serviceaccount
|
||||||
|
|
||||||
// Resource is the wire representation of ServiceAccount. (TODO be better)
|
import (
|
||||||
|
"github.com/grafana/grafana/pkg/kinds"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Resource is the kubernetes style representation of ServiceAccount. (TODO be better)
|
||||||
|
type K8sResource = kinds.GrafanaResource[Spec, Status]
|
||||||
|
|
||||||
|
// NewResource creates a new instance of the resource with a given name (UID)
|
||||||
|
func NewK8sResource(name string, s *Spec) K8sResource {
|
||||||
|
return K8sResource{
|
||||||
|
Kind: "ServiceAccount",
|
||||||
|
APIVersion: "v0.0-alpha",
|
||||||
|
Metadata: kinds.GrafanaResourceMetadata{
|
||||||
|
Name: name,
|
||||||
|
Annotations: make(map[string]string),
|
||||||
|
Labels: make(map[string]string),
|
||||||
|
},
|
||||||
|
Spec: s,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Resource is the wire representation of ServiceAccount.
|
||||||
|
// It currently will soon be merged into the k8s flavor (TODO be better)
|
||||||
type Resource struct {
|
type Resource struct {
|
||||||
Metadata Metadata `json:"metadata"`
|
Metadata Metadata `json:"metadata"`
|
||||||
Spec Spec `json:"spec"`
|
Spec Spec `json:"spec"`
|
||||||
|
@ -9,7 +9,30 @@
|
|||||||
|
|
||||||
package team
|
package team
|
||||||
|
|
||||||
// Resource is the wire representation of Team. (TODO be better)
|
import (
|
||||||
|
"github.com/grafana/grafana/pkg/kinds"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Resource is the kubernetes style representation of Team. (TODO be better)
|
||||||
|
type K8sResource = kinds.GrafanaResource[Spec, Status]
|
||||||
|
|
||||||
|
// NewResource creates a new instance of the resource with a given name (UID)
|
||||||
|
func NewK8sResource(name string, s *Spec) K8sResource {
|
||||||
|
return K8sResource{
|
||||||
|
Kind: "Team",
|
||||||
|
APIVersion: "v0.0-alpha",
|
||||||
|
Metadata: kinds.GrafanaResourceMetadata{
|
||||||
|
Name: name,
|
||||||
|
Annotations: make(map[string]string),
|
||||||
|
Labels: make(map[string]string),
|
||||||
|
},
|
||||||
|
Spec: s,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Resource is the wire representation of Team.
|
||||||
|
// It currently will soon be merged into the k8s flavor (TODO be better)
|
||||||
type Resource struct {
|
type Resource struct {
|
||||||
Metadata Metadata `json:"metadata"`
|
Metadata Metadata `json:"metadata"`
|
||||||
Spec Spec `json:"spec"`
|
Spec Spec `json:"spec"`
|
||||||
|
@ -6,6 +6,8 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
"github.com/grafana/grafana/pkg/infra/slugify"
|
"github.com/grafana/grafana/pkg/infra/slugify"
|
||||||
|
"github.com/grafana/grafana/pkg/kinds"
|
||||||
|
"github.com/grafana/grafana/pkg/kinds/dashboard"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/folder"
|
"github.com/grafana/grafana/pkg/services/folder"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
@ -13,6 +15,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/search/model"
|
"github.com/grafana/grafana/pkg/services/search/model"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
const RootFolderName = "General"
|
const RootFolderName = "General"
|
||||||
@ -60,6 +63,54 @@ func (d *Dashboard) SetVersion(version int) {
|
|||||||
d.Data.Set("version", version)
|
d.Data.Set("version", version)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Dashboard) ToResource() kinds.GrafanaResource[simplejson.Json, interface{}] {
|
||||||
|
parent := dashboard.NewK8sResource(d.UID, nil)
|
||||||
|
res := kinds.GrafanaResource[simplejson.Json, interface{}]{
|
||||||
|
Kind: parent.Kind,
|
||||||
|
APIVersion: parent.APIVersion,
|
||||||
|
Metadata: kinds.GrafanaResourceMetadata{
|
||||||
|
Name: d.UID,
|
||||||
|
Annotations: make(map[string]string),
|
||||||
|
Labels: make(map[string]string),
|
||||||
|
CreationTimestamp: v1.NewTime(d.Created),
|
||||||
|
ResourceVersion: fmt.Sprintf("%d", d.Version),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if d.Data != nil {
|
||||||
|
copy := &simplejson.Json{}
|
||||||
|
db, _ := d.Data.ToDB()
|
||||||
|
_ = copy.FromDB(db)
|
||||||
|
|
||||||
|
copy.Del("id")
|
||||||
|
copy.Del("version") // ???
|
||||||
|
copy.Del("uid") // duplicated to name
|
||||||
|
res.Spec = copy
|
||||||
|
}
|
||||||
|
|
||||||
|
d.UpdateSlug()
|
||||||
|
res.Metadata.SetUpdatedTimestamp(&d.Updated)
|
||||||
|
res.Metadata.SetSlug(d.Slug)
|
||||||
|
if d.CreatedBy > 0 {
|
||||||
|
res.Metadata.SetCreatedBy(fmt.Sprintf("user:%d", d.CreatedBy))
|
||||||
|
}
|
||||||
|
if d.UpdatedBy > 0 {
|
||||||
|
res.Metadata.SetUpdatedBy(fmt.Sprintf("user:%d", d.UpdatedBy))
|
||||||
|
}
|
||||||
|
if d.PluginID != "" {
|
||||||
|
res.Metadata.SetOriginInfo(&kinds.ResourceOriginInfo{
|
||||||
|
Name: "plugin",
|
||||||
|
Key: d.PluginID,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if d.FolderID > 0 {
|
||||||
|
res.Metadata.SetFolder(fmt.Sprintf("folder:%d", d.FolderID))
|
||||||
|
}
|
||||||
|
if d.IsFolder {
|
||||||
|
res.Kind = "Folder"
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
// NewDashboard creates a new dashboard
|
// NewDashboard creates a new dashboard
|
||||||
func NewDashboard(title string) *Dashboard {
|
func NewDashboard(title string) *Dashboard {
|
||||||
dash := &Dashboard{}
|
dash := &Dashboard{}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package dashboards
|
package dashboards
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@ -86,3 +89,53 @@ func TestSlugifyTitle(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestResourceConversion(t *testing.T) {
|
||||||
|
body := simplejson.New()
|
||||||
|
body.Set("title", "test dash")
|
||||||
|
body.Set("tags", []string{"hello", "world"})
|
||||||
|
|
||||||
|
dash := NewDashboardFromJson(body)
|
||||||
|
dash.SetUID("TheUID")
|
||||||
|
dash.SetVersion(10)
|
||||||
|
dash.Created = time.UnixMilli(946713600000).UTC() // 2000-01-01
|
||||||
|
dash.Updated = time.UnixMilli(1262332800000).UTC() // 2010-01-01
|
||||||
|
dash.CreatedBy = 10
|
||||||
|
dash.UpdatedBy = 11
|
||||||
|
dash.PluginID = "plugin-xyz"
|
||||||
|
dash.FolderID = 1234
|
||||||
|
dash.SetID(12345) // should be removed in resource version
|
||||||
|
|
||||||
|
dst := dash.ToResource()
|
||||||
|
require.Equal(t, int64(12345), dash.ID)
|
||||||
|
require.Equal(t, int64(12345), dash.Data.Get("id").MustInt64(0))
|
||||||
|
|
||||||
|
out, err := json.MarshalIndent(dst, "", " ")
|
||||||
|
require.NoError(t, err)
|
||||||
|
fmt.Printf("%s", string(out))
|
||||||
|
require.JSONEq(t, `{
|
||||||
|
"apiVersion": "v0.0-alpha",
|
||||||
|
"kind": "Dashboard",
|
||||||
|
"metadata": {
|
||||||
|
"name": "TheUID",
|
||||||
|
"resourceVersion": "10",
|
||||||
|
"creationTimestamp": "2000-01-01T08:00:00Z",
|
||||||
|
"annotations": {
|
||||||
|
"grafana.com/createdBy": "user:10",
|
||||||
|
"grafana.com/folder": "folder:1234",
|
||||||
|
"grafana.com/origin/key": "plugin-xyz",
|
||||||
|
"grafana.com/origin/name": "plugin",
|
||||||
|
"grafana.com/slug": "test-dash",
|
||||||
|
"grafana.com/updatedBy": "user:11",
|
||||||
|
"grafana.com/updatedTimestamp": "2010-01-01T08:00:00Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"tags": [
|
||||||
|
"hello",
|
||||||
|
"world"
|
||||||
|
],
|
||||||
|
"title": "test dash"
|
||||||
|
}
|
||||||
|
}`, string(out))
|
||||||
|
}
|
||||||
|
@ -3,9 +3,13 @@ package model
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
|
"github.com/grafana/grafana/pkg/kinds"
|
||||||
"github.com/grafana/grafana/pkg/kinds/librarypanel"
|
"github.com/grafana/grafana/pkg/kinds/librarypanel"
|
||||||
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LibraryConnectionKind int
|
type LibraryConnectionKind int
|
||||||
@ -78,6 +82,32 @@ type LibraryElementDTO struct {
|
|||||||
SchemaVersion int64 `json:"schemaVersion,omitempty"`
|
SchemaVersion int64 `json:"schemaVersion,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (dto *LibraryElementDTO) ToResource() kinds.GrafanaResource[simplejson.Json, simplejson.Json] {
|
||||||
|
body := &simplejson.Json{}
|
||||||
|
_ = body.FromDB(dto.Model)
|
||||||
|
parent := librarypanel.NewK8sResource(dto.UID, nil)
|
||||||
|
res := kinds.GrafanaResource[simplejson.Json, simplejson.Json]{
|
||||||
|
Kind: parent.Kind,
|
||||||
|
APIVersion: parent.APIVersion,
|
||||||
|
Metadata: kinds.GrafanaResourceMetadata{
|
||||||
|
Name: dto.UID,
|
||||||
|
Annotations: make(map[string]string),
|
||||||
|
Labels: make(map[string]string),
|
||||||
|
ResourceVersion: fmt.Sprintf("%d", dto.Version),
|
||||||
|
CreationTimestamp: v1.NewTime(dto.Meta.Created),
|
||||||
|
},
|
||||||
|
Spec: body,
|
||||||
|
}
|
||||||
|
|
||||||
|
if dto.FolderUID != "" {
|
||||||
|
res.Metadata.SetFolder(dto.FolderUID)
|
||||||
|
}
|
||||||
|
res.Metadata.SetCreatedBy(fmt.Sprintf("user:%d", dto.Meta.CreatedBy.Id))
|
||||||
|
res.Metadata.SetUpdatedBy(fmt.Sprintf("user:%d", dto.Meta.UpdatedBy.Id))
|
||||||
|
res.Metadata.SetUpdatedTimestamp(&dto.Meta.Updated)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
// LibraryElementSearchResult is the search result for entities.
|
// LibraryElementSearchResult is the search result for entities.
|
||||||
type LibraryElementSearchResult struct {
|
type LibraryElementSearchResult struct {
|
||||||
TotalCount int64 `json:"totalCount"`
|
TotalCount int64 `json:"totalCount"`
|
||||||
|
57
pkg/services/libraryelements/model/model_test.go
Normal file
57
pkg/services/libraryelements/model/model_test.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/kinds/librarypanel"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLibaryPanelConversion(t *testing.T) {
|
||||||
|
body := `{}`
|
||||||
|
|
||||||
|
src := LibraryElementDTO{
|
||||||
|
Kind: 0, // always library panel
|
||||||
|
FolderUID: "TheFolderUID",
|
||||||
|
UID: "TheUID",
|
||||||
|
Version: 10,
|
||||||
|
Model: json.RawMessage(body),
|
||||||
|
Meta: LibraryElementDTOMeta{
|
||||||
|
Created: time.UnixMilli(946713600000).UTC(), // 2000-01-01
|
||||||
|
Updated: time.UnixMilli(1262332800000).UTC(), // 2010-01-01,
|
||||||
|
CreatedBy: librarypanel.LibraryElementDTOMetaUser{
|
||||||
|
Id: 11,
|
||||||
|
},
|
||||||
|
UpdatedBy: librarypanel.LibraryElementDTOMetaUser{
|
||||||
|
Id: 12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
dst := src.ToResource()
|
||||||
|
|
||||||
|
require.Equal(t, src.UID, dst.Metadata.Name)
|
||||||
|
|
||||||
|
out, err := json.MarshalIndent(dst, "", " ")
|
||||||
|
require.NoError(t, err)
|
||||||
|
fmt.Printf("%s", string(out))
|
||||||
|
require.JSONEq(t, `{
|
||||||
|
"apiVersion": "v0.0-alpha",
|
||||||
|
"kind": "LibraryPanel",
|
||||||
|
"metadata": {
|
||||||
|
"name": "TheUID",
|
||||||
|
"resourceVersion": "10",
|
||||||
|
"creationTimestamp": "2000-01-01T08:00:00Z",
|
||||||
|
"annotations": {
|
||||||
|
"grafana.com/createdBy": "user:11",
|
||||||
|
"grafana.com/folder": "TheFolderUID",
|
||||||
|
"grafana.com/updatedBy": "user:12",
|
||||||
|
"grafana.com/updatedTimestamp": "2010-01-01T08:00:00Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"spec": {}
|
||||||
|
}`, string(out))
|
||||||
|
}
|
@ -81,3 +81,10 @@ type GetPlaylistItemsByUidQuery struct {
|
|||||||
PlaylistUID string
|
PlaylistUID string
|
||||||
OrgId int64
|
OrgId int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PlaylistToResource(p PlaylistDTO) playlist.K8sResource {
|
||||||
|
copy := p
|
||||||
|
r := playlist.NewK8sResource(p.Uid, ©)
|
||||||
|
copy.Uid = "" // remove it from the payload
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
64
pkg/services/playlist/model_test.go
Normal file
64
pkg/services/playlist/model_test.go
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package playlist
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/kinds/playlist"
|
||||||
|
"github.com/grafana/grafana/pkg/util"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPlaylistConversion(t *testing.T) {
|
||||||
|
src := PlaylistDTO{
|
||||||
|
Uid: "abc",
|
||||||
|
Name: "TeamA",
|
||||||
|
Interval: "10s",
|
||||||
|
Items: []playlist.Item{
|
||||||
|
{Title: util.Pointer("First"), Type: playlist.ItemTypeDashboardByUid, Value: "UID0"},
|
||||||
|
{Title: util.Pointer("Second"), Type: playlist.ItemTypeDashboardByTag, Value: "tagA"},
|
||||||
|
{Title: util.Pointer("Third"), Type: playlist.ItemTypeDashboardById, Value: "123"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
dst := PlaylistToResource(src)
|
||||||
|
|
||||||
|
require.Equal(t, "abc", src.Uid)
|
||||||
|
require.Equal(t, "abc", dst.Metadata.Name)
|
||||||
|
require.Equal(t, src.Name, dst.Spec.Name)
|
||||||
|
|
||||||
|
out, err := json.MarshalIndent(dst, "", " ")
|
||||||
|
require.NoError(t, err)
|
||||||
|
fmt.Printf("%s", string(out))
|
||||||
|
require.JSONEq(t, `{
|
||||||
|
"apiVersion": "v0.0-alpha",
|
||||||
|
"kind": "Playlist",
|
||||||
|
"metadata": {
|
||||||
|
"name": "abc",
|
||||||
|
"creationTimestamp": null
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"interval": "10s",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"title": "First",
|
||||||
|
"type": "dashboard_by_uid",
|
||||||
|
"value": "UID0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Second",
|
||||||
|
"type": "dashboard_by_tag",
|
||||||
|
"value": "tagA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Third",
|
||||||
|
"type": "dashboard_by_id",
|
||||||
|
"value": "123"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "TeamA",
|
||||||
|
"uid": ""
|
||||||
|
}
|
||||||
|
}`, string(out))
|
||||||
|
}
|
@ -4,8 +4,10 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/kinds/team"
|
||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Typed errors
|
// Typed errors
|
||||||
@ -32,6 +34,18 @@ type Team struct {
|
|||||||
Updated time.Time `json:"updated"`
|
Updated time.Time `json:"updated"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Team) ToResource() team.K8sResource {
|
||||||
|
r := team.NewK8sResource(t.UID, &team.Spec{
|
||||||
|
Name: t.Name,
|
||||||
|
})
|
||||||
|
r.Metadata.CreationTimestamp = v1.NewTime(t.Created)
|
||||||
|
r.Metadata.SetUpdatedTimestamp(&t.Updated)
|
||||||
|
if t.Email != "" {
|
||||||
|
r.Spec.Email = &t.Email
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------
|
// ---------------------
|
||||||
// COMMANDS
|
// COMMANDS
|
||||||
|
|
||||||
|
45
pkg/services/team/model_test.go
Normal file
45
pkg/services/team/model_test.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package team
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTeamConversion(t *testing.T) {
|
||||||
|
src := Team{
|
||||||
|
ID: 123,
|
||||||
|
UID: "abc",
|
||||||
|
Name: "TeamA",
|
||||||
|
Email: "team@a.org",
|
||||||
|
OrgID: 11,
|
||||||
|
Created: time.UnixMilli(946713600000).UTC(), // 2000-01-01
|
||||||
|
Updated: time.UnixMilli(1262332800000).UTC(), // 2010-01-01
|
||||||
|
}
|
||||||
|
|
||||||
|
dst := src.ToResource()
|
||||||
|
|
||||||
|
require.Equal(t, src.Name, dst.Spec.Name)
|
||||||
|
|
||||||
|
out, err := json.MarshalIndent(dst, "", " ")
|
||||||
|
require.NoError(t, err)
|
||||||
|
fmt.Printf("%s", string(out))
|
||||||
|
require.JSONEq(t, `{
|
||||||
|
"apiVersion": "v0.0-alpha",
|
||||||
|
"kind": "Team",
|
||||||
|
"metadata": {
|
||||||
|
"name": "abc",
|
||||||
|
"creationTimestamp": "2000-01-01T08:00:00Z",
|
||||||
|
"annotations": {
|
||||||
|
"grafana.com/updatedTimestamp": "2010-01-01T08:00:00Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"email": "team@a.org",
|
||||||
|
"name": "TeamA"
|
||||||
|
}
|
||||||
|
}`, string(out))
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user