exclude false values
This commit is contained in:
@@ -29,7 +29,7 @@ func (u *UnstructuredSpec) Set(key string, val any) *UnstructuredSpec {
|
||||
if u.Object == nil {
|
||||
u.Object = make(map[string]any)
|
||||
}
|
||||
if val == nil || val == "" {
|
||||
if val == nil || val == "" || val == false {
|
||||
delete(u.Object, key)
|
||||
} else {
|
||||
u.Object[key] = val
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"maps"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
@@ -28,19 +29,17 @@ type converter struct {
|
||||
}
|
||||
|
||||
func (r *converter) asDataSource(ds *datasources.DataSource) (*datasourceV0.DataSource, error) {
|
||||
cfg := &datasourceV0.DataSource{
|
||||
obj := &datasourceV0.DataSource{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: ds.UID,
|
||||
Namespace: r.mapper(ds.OrgID),
|
||||
CreationTimestamp: metav1.NewTime(ds.Created),
|
||||
ResourceVersion: fmt.Sprintf("%d", ds.Updated.UnixMilli()),
|
||||
Generation: int64(ds.Version),
|
||||
Name: ds.UID,
|
||||
Namespace: r.mapper(ds.OrgID),
|
||||
Generation: int64(ds.Version),
|
||||
},
|
||||
Spec: datasourceV0.UnstructuredSpec{},
|
||||
Secure: ToInlineSecureValues(ds.Type, ds.UID, maps.Keys(ds.SecureJsonData)),
|
||||
}
|
||||
cfg.UID = gapiutil.CalculateClusterWideUID(cfg)
|
||||
cfg.Spec.SetTitle(ds.Name).
|
||||
obj.UID = gapiutil.CalculateClusterWideUID(obj)
|
||||
obj.Spec.SetTitle(ds.Name).
|
||||
SetAccess(string(ds.Access)).
|
||||
SetURL(ds.URL).
|
||||
SetDatabase(ds.Database).
|
||||
@@ -53,13 +52,26 @@ func (r *converter) asDataSource(ds *datasources.DataSource) (*datasourceV0.Data
|
||||
SetReadOnly(ds.ReadOnly).
|
||||
SetJSONData(ds.JsonData)
|
||||
|
||||
if ds.ID > 0 {
|
||||
cfg.Labels = map[string]string{
|
||||
utils.LabelKeyDeprecatedInternalID: strconv.FormatInt(ds.ID, 10),
|
||||
if !ds.Created.IsZero() {
|
||||
obj.CreationTimestamp = metav1.NewTime(ds.Created)
|
||||
}
|
||||
if !ds.Updated.IsZero() {
|
||||
obj.ResourceVersion = fmt.Sprintf("%d", ds.Updated.UnixMilli())
|
||||
obj.Annotations = map[string]string{
|
||||
utils.AnnoKeyUpdatedTimestamp: ds.Updated.Format(time.RFC3339),
|
||||
}
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
if ds.APIVersion != "" {
|
||||
obj.APIVersion = fmt.Sprintf("%s/%s", r.group, ds.APIVersion)
|
||||
}
|
||||
|
||||
if ds.ID > 0 {
|
||||
obj.Labels = map[string]string{
|
||||
utils.LabelKeyDeprecatedInternalID: strconv.FormatInt(ds.ID, 10),
|
||||
}
|
||||
}
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
// ToInlineSecureValues converts secure json into InlineSecureValues with reference names
|
||||
@@ -85,7 +97,7 @@ func ToInlineSecureValues(dsType string, dsUID string, keys iter.Seq[string]) co
|
||||
}
|
||||
|
||||
func (r *converter) toAddCommand(ds *datasourceV0.DataSource) (*datasources.AddDataSourceCommand, error) {
|
||||
if r.group != "" && !strings.HasPrefix(ds.APIVersion, r.group) {
|
||||
if r.group != "" && ds.APIVersion != "" && !strings.HasPrefix(ds.APIVersion, r.group) {
|
||||
return nil, fmt.Errorf("expecting APIGroup: %s", r.group)
|
||||
}
|
||||
info, err := types.ParseNamespace(ds.Namespace)
|
||||
@@ -120,7 +132,7 @@ func (r *converter) toAddCommand(ds *datasourceV0.DataSource) (*datasources.AddD
|
||||
}
|
||||
|
||||
func (r *converter) toUpdateCommand(ds *datasourceV0.DataSource) (*datasources.UpdateDataSourceCommand, error) {
|
||||
if r.group != "" && !strings.HasPrefix(ds.APIVersion, r.group) {
|
||||
if r.group != "" && ds.APIVersion != "" && !strings.HasPrefix(ds.APIVersion, r.group) {
|
||||
return nil, fmt.Errorf("expecting APIGroup: %s", r.group)
|
||||
}
|
||||
info, err := types.ParseNamespace(ds.Namespace)
|
||||
|
||||
@@ -11,20 +11,22 @@ import (
|
||||
|
||||
"github.com/grafana/authlib/types"
|
||||
"github.com/grafana/grafana/pkg/apis/datasource/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
)
|
||||
|
||||
func TestConverter(t *testing.T) {
|
||||
t.Run("resource to command", func(t *testing.T) {
|
||||
obj := &v0alpha1.DataSource{}
|
||||
converter := converter{
|
||||
mapper: types.OrgNamespaceFormatter,
|
||||
dstype: "test-datasource",
|
||||
group: "testdata.grafana.datasource.app",
|
||||
}
|
||||
check := []string{
|
||||
"convert-testdata-A",
|
||||
"convert-resource-A",
|
||||
}
|
||||
for _, name := range check {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
obj := &v0alpha1.DataSource{}
|
||||
fpath := filepath.Join("testdata", name+".json")
|
||||
raw, err := os.ReadFile(fpath) // nolint:gosec
|
||||
require.NoError(t, err)
|
||||
@@ -32,7 +34,7 @@ func TestConverter(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// The add command
|
||||
fpath = filepath.Join("testdata", name+"-cmd-add.json")
|
||||
fpath = filepath.Join("testdata", name+"-to-cmd-add.json")
|
||||
add, err := converter.toAddCommand(obj)
|
||||
require.NoError(t, err)
|
||||
out, err := json.MarshalIndent(add, "", " ")
|
||||
@@ -43,7 +45,7 @@ func TestConverter(t *testing.T) {
|
||||
}
|
||||
|
||||
// The update command
|
||||
fpath = filepath.Join("testdata", name+"-cmd-update.json")
|
||||
fpath = filepath.Join("testdata", name+"-to-cmd-update.json")
|
||||
update, err := converter.toUpdateCommand(obj)
|
||||
require.NoError(t, err)
|
||||
out, err = json.MarshalIndent(update, "", " ")
|
||||
@@ -52,6 +54,62 @@ func TestConverter(t *testing.T) {
|
||||
if !assert.JSONEq(t, string(raw), string(out)) {
|
||||
_ = os.WriteFile(fpath, out, 0600)
|
||||
}
|
||||
|
||||
// Round trip the update (NOTE, not all properties will be included)
|
||||
ds := &datasources.DataSource{}
|
||||
err = json.Unmarshal(raw, ds) // the add command is also a DataSource
|
||||
require.NoError(t, err)
|
||||
|
||||
roundtrip, err := converter.asDataSource(ds)
|
||||
require.NoError(t, err)
|
||||
|
||||
fpath = filepath.Join("testdata", name+"-to-cmd-update-roundtrip.json")
|
||||
out, err = json.MarshalIndent(roundtrip, "", " ")
|
||||
require.NoError(t, err)
|
||||
raw, _ = os.ReadFile(fpath) // nolint:gosec
|
||||
if !assert.JSONEq(t, string(raw), string(out)) {
|
||||
_ = os.WriteFile(fpath, out, 0600)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("db to resource", func(t *testing.T) {
|
||||
converter := converter{
|
||||
mapper: types.OrgNamespaceFormatter,
|
||||
dstype: "test-datasource",
|
||||
group: "testdata.grafana.datasource.app",
|
||||
}
|
||||
check := []string{
|
||||
"convert-db-B",
|
||||
}
|
||||
for _, name := range check {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
ds := &datasources.DataSource{}
|
||||
fpath := filepath.Join("testdata", name+".json")
|
||||
raw, err := os.ReadFile(fpath) // nolint:gosec
|
||||
require.NoError(t, err)
|
||||
err = json.Unmarshal(raw, ds)
|
||||
require.NoError(t, err)
|
||||
|
||||
// if true {
|
||||
// ds.Created = time.Unix(100000000, 0).UTC()
|
||||
// ds.Updated = time.Unix(500000000, 0).UTC()
|
||||
// out, _ := json.MarshalIndent(ds, "", " ")
|
||||
// fmt.Printf("%s\n", string(out))
|
||||
// t.FailNow()
|
||||
// }
|
||||
|
||||
// As an object
|
||||
fpath = filepath.Join("testdata", name+"-to-resource.json")
|
||||
obj, err := converter.asDataSource(ds)
|
||||
require.NoError(t, err)
|
||||
out, err := json.MarshalIndent(obj, "", " ")
|
||||
require.NoError(t, err)
|
||||
raw, _ = os.ReadFile(fpath) // nolint:gosec
|
||||
if !assert.JSONEq(t, string(raw), string(out)) {
|
||||
_ = os.WriteFile(fpath, out, 0600)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"apiVersion": "testdata.grafana.datasource.app/v2alpha1",
|
||||
"metadata": {
|
||||
"name": "unique-identifier",
|
||||
"namespace": "org-0",
|
||||
"uid": "YpaSG5GQAdxtLZtF6BqQWCeYXOhbVi5C4Cg4oILnJC0X",
|
||||
"resourceVersion": "1083805200000",
|
||||
"generation": 2,
|
||||
"creationTimestamp": "2002-03-04T01:00:00Z",
|
||||
"labels": {
|
||||
"grafana.app/deprecatedInternalID": "1234"
|
||||
},
|
||||
"annotations": {
|
||||
"grafana.app/updatedTimestamp": "2004-05-06T01:00:00Z"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"access": "proxy",
|
||||
"basicAuth": true,
|
||||
"basicAuthUser": "xxx",
|
||||
"database": "db",
|
||||
"isDefault": true,
|
||||
"jsonData": {
|
||||
"aaa": "bbb",
|
||||
"bbb": true,
|
||||
"ccc": 1.234
|
||||
},
|
||||
"readOnly": true,
|
||||
"title": "Hello",
|
||||
"url": "http://something/",
|
||||
"user": "A",
|
||||
"withCredentials": true
|
||||
},
|
||||
"secure": {
|
||||
"password": {
|
||||
"name": "ds-c429ac622e"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"id": 1234,
|
||||
"version": 2,
|
||||
"name": "Hello",
|
||||
"uid": "unique-identifier",
|
||||
"type": "grafana-test-datasource",
|
||||
"access": "proxy",
|
||||
"url": "http://something/",
|
||||
"user": "A",
|
||||
"database": "db",
|
||||
"basicAuth": true,
|
||||
"basicAuthUser": "xxx",
|
||||
"withCredentials": true,
|
||||
"isDefault": true,
|
||||
"jsonData": {
|
||||
"aaa": "bbb",
|
||||
"bbb": true,
|
||||
"ccc": 1.234
|
||||
},
|
||||
"secureJsonData": {
|
||||
"password": "XXXX"
|
||||
},
|
||||
"readOnly": true,
|
||||
"apiVersion": "v2alpha1",
|
||||
"created": "2002-03-04T01:00:00Z",
|
||||
"updated": "2004-05-06T01:00:00Z"
|
||||
}
|
||||
+7
-5
@@ -1,19 +1,21 @@
|
||||
{
|
||||
"name": "grafana-testdata-datasource",
|
||||
"name": "Hello testdata",
|
||||
"type": "test-datasource",
|
||||
"access": "proxy",
|
||||
"url": "http://something/",
|
||||
"user": "",
|
||||
"database": "db",
|
||||
"basicAuth": false,
|
||||
"basicAuthUser": "",
|
||||
"withCredentials": false,
|
||||
"basicAuth": true,
|
||||
"basicAuthUser": "xxx",
|
||||
"withCredentials": true,
|
||||
"isDefault": true,
|
||||
"jsonData": {
|
||||
"aaa": "bbb",
|
||||
"bbb": true,
|
||||
"ccc": 1.234
|
||||
},
|
||||
"secureJsonData": {},
|
||||
"secureJsonData": {
|
||||
"password": "XXXX"
|
||||
},
|
||||
"uid": "cejobd88i85j4d"
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"metadata": {
|
||||
"name": "cejobd88i85j4d",
|
||||
"namespace": "org-0",
|
||||
"uid": "boDNh7zU3nXj46rOXIJI7r44qaxjs8yy9I9dOj1MyBoX",
|
||||
"generation": 2,
|
||||
"creationTimestamp": null
|
||||
},
|
||||
"spec": {
|
||||
"access": "proxy",
|
||||
"basicAuth": true,
|
||||
"basicAuthUser": "xxx",
|
||||
"database": "db",
|
||||
"isDefault": true,
|
||||
"jsonData": {
|
||||
"aaa": "bbb",
|
||||
"bbb": true,
|
||||
"ccc": 1.234
|
||||
},
|
||||
"title": "Hello testdata",
|
||||
"url": "http://something/",
|
||||
"withCredentials": true
|
||||
},
|
||||
"secure": {
|
||||
"password": {
|
||||
"name": "ds-fdb9f6717d"
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-5
@@ -1,20 +1,22 @@
|
||||
{
|
||||
"name": "grafana-testdata-datasource",
|
||||
"name": "Hello testdata",
|
||||
"type": "test-datasource",
|
||||
"access": "proxy",
|
||||
"url": "http://something/",
|
||||
"user": "",
|
||||
"database": "db",
|
||||
"basicAuth": false,
|
||||
"basicAuthUser": "",
|
||||
"withCredentials": false,
|
||||
"basicAuth": true,
|
||||
"basicAuthUser": "xxx",
|
||||
"withCredentials": true,
|
||||
"isDefault": true,
|
||||
"jsonData": {
|
||||
"aaa": "bbb",
|
||||
"bbb": true,
|
||||
"ccc": 1.234
|
||||
},
|
||||
"secureJsonData": {},
|
||||
"secureJsonData": {
|
||||
"password": "XXXX"
|
||||
},
|
||||
"uid": "cejobd88i85j4d",
|
||||
"version": 2
|
||||
}
|
||||
+10
-3
@@ -5,14 +5,21 @@
|
||||
"uid": "IGIUtEQS21DtLpBG2rSGfuDoUX8cwsGrtb5aXauYeA4X",
|
||||
"resourceVersion": "1745320815000",
|
||||
"generation": 2,
|
||||
"creationTimestamp": "2025-04-22T11:20:11Z"
|
||||
"creationTimestamp": "2025-04-22T11:20:11Z",
|
||||
"labels": {
|
||||
"grafana.app/deprecatedInternalID": "12345"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"title": "grafana-testdata-datasource",
|
||||
"title": "Hello testdata",
|
||||
"access": "proxy",
|
||||
"isDefault": true,
|
||||
"readOnly": true,
|
||||
"url": "http://something/",
|
||||
"database": "db",
|
||||
"basicAuth": true,
|
||||
"basicAuthUser": "xxx",
|
||||
"withCredentials": true,
|
||||
"jsonData": {
|
||||
"aaa": "bbb",
|
||||
"bbb": true,
|
||||
@@ -20,6 +27,6 @@
|
||||
}
|
||||
},
|
||||
"secure": {
|
||||
"password": { "input": "XXXX" }
|
||||
"password": { "create": "XXXX" }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user