diff --git a/api/integreatly/v1alpha1/grafanadashboard_types.go b/api/integreatly/v1alpha1/grafanadashboard_types.go index 2a5624f8c..135673d1a 100644 --- a/api/integreatly/v1alpha1/grafanadashboard_types.go +++ b/api/integreatly/v1alpha1/grafanadashboard_types.go @@ -20,12 +20,10 @@ import ( "bytes" "crypto/sha1" // nolint "crypto/sha256" - "encoding/base64" "encoding/json" "fmt" "io" "io/ioutil" - "strings" "compress/gzip" @@ -39,7 +37,7 @@ import ( // GrafanaDashboardSpec defines the desired state of GrafanaDashboard type GrafanaDashboardSpec struct { Json string `json:"json,omitempty"` - GzipJson string `json:"gzipJson,omitempty"` + GzipJson []byte `json:"gzipJson,omitempty"` Jsonnet string `json:"jsonnet,omitempty"` Plugins PluginList `json:"plugins,omitempty"` Url string `json:"url,omitempty"` @@ -108,7 +106,7 @@ func (d *GrafanaDashboard) Hash() string { } io.WriteString(hash, d.Spec.Json) // nolint - io.WriteString(hash, d.Spec.GzipJson) // nolint + hash.Write(d.Spec.GzipJson) // nolint io.WriteString(hash, d.Spec.Url) // nolint io.WriteString(hash, d.Spec.Jsonnet) // nolint io.WriteString(hash, d.Namespace) // nolint @@ -135,9 +133,9 @@ func (d *GrafanaDashboard) Hash() string { func (d *GrafanaDashboard) Parse(optional string) (map[string]interface{}, error) { var dashboardBytes []byte - if d.Spec.GzipJson != "" { + if d.Spec.GzipJson != nil { var err error - dashboardBytes, err = DecodeBase64Gzip(d.Spec.GzipJson) + dashboardBytes, err = Gunzip(d.Spec.GzipJson) if err != nil { return nil, err } @@ -168,15 +166,7 @@ func (d *GrafanaDashboard) UID() string { return fmt.Sprintf("%x", sha1.Sum([]byte(d.Namespace+d.Name))) // nolint } -func DecodeBase64Gzip(encoded string) ([]byte, error) { - decoder, err := gzip.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(encoded))) - if err != nil { - return nil, err - } - return ioutil.ReadAll(decoder) -} - -func DecodeGzip(compressed []byte) ([]byte, error) { +func Gunzip(compressed []byte) ([]byte, error) { decoder, err := gzip.NewReader(bytes.NewReader(compressed)) if err != nil { return nil, err diff --git a/api/integreatly/v1alpha1/grafanadashboard_types_test.go b/api/integreatly/v1alpha1/grafanadashboard_types_test.go index d36ae0ee6..161f479a4 100644 --- a/api/integreatly/v1alpha1/grafanadashboard_types_test.go +++ b/api/integreatly/v1alpha1/grafanadashboard_types_test.go @@ -50,30 +50,6 @@ const decodedDashboard = ` } ` -func TestDecodeDecompress(t *testing.T) { - var expected map[string]interface{} - var actual map[string]interface{} - decoded, err := DecodeBase64Gzip(encodedCompressedDashboard) - if err != nil { - t.Log("Failed to decompress/decode", err) - t.Fail() - } - err = json.Unmarshal([]byte(decoded), &actual) - if err != nil { - t.Log("Failed to parse JSON from decoded", err) - t.Fail() - } - err = json.Unmarshal([]byte(decodedDashboard), &expected) - if err != nil { - t.Log("Failed to parse JSON from ground truth", err) - t.Fail() - } - if !reflect.DeepEqual(expected, actual) { - t.Log("Decoded JSONs were not the same") - t.Fail() - } -} - func TestDecompress(t *testing.T) { var expected map[string]interface{} var actual map[string]interface{} @@ -82,7 +58,7 @@ func TestDecompress(t *testing.T) { t.Log("Failed to decode", err) t.Fail() } - decompressed, err := DecodeGzip(decoded) + decompressed, err := Gunzip(decoded) if err != nil { t.Log("Failed to decompress", err) t.Fail() diff --git a/api/integreatly/v1alpha1/zz_generated.deepcopy.go b/api/integreatly/v1alpha1/zz_generated.deepcopy.go index 92e0af375..a0e213b2d 100644 --- a/api/integreatly/v1alpha1/zz_generated.deepcopy.go +++ b/api/integreatly/v1alpha1/zz_generated.deepcopy.go @@ -1427,6 +1427,11 @@ func (in *GrafanaDashboardRef) DeepCopy() *GrafanaDashboardRef { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GrafanaDashboardSpec) DeepCopyInto(out *GrafanaDashboardSpec) { *out = *in + if in.GzipJson != nil { + in, out := &in.GzipJson, &out.GzipJson + *out = make([]byte, len(*in)) + copy(*out, *in) + } if in.Plugins != nil { in, out := &in.Plugins, &out.Plugins *out = make(PluginList, len(*in)) diff --git a/config/crd/bases/integreatly.org_grafanadashboards.yaml b/config/crd/bases/integreatly.org_grafanadashboards.yaml index 44232a90f..9c56feca6 100644 --- a/config/crd/bases/integreatly.org_grafanadashboards.yaml +++ b/config/crd/bases/integreatly.org_grafanadashboards.yaml @@ -94,6 +94,7 @@ spec: - key type: object gzipJson: + format: byte type: string json: type: string diff --git a/controllers/grafanadashboard/dashboard_pipeline.go b/controllers/grafanadashboard/dashboard_pipeline.go index d9fd57fcf..7b185ba20 100644 --- a/controllers/grafanadashboard/dashboard_pipeline.go +++ b/controllers/grafanadashboard/dashboard_pipeline.go @@ -160,9 +160,9 @@ func (r *DashboardPipelineImpl) obtainJson() error { } } - if r.Dashboard.Spec.GzipJson != "" { + if r.Dashboard.Spec.GzipJson != nil { r.Logger.Info("TODO: REMOVE --- gzipJson was provided") - jsonBytes, err := v1alpha1.DecodeBase64Gzip(r.Dashboard.Spec.GzipJson) + jsonBytes, err := v1alpha1.Gunzip(r.Dashboard.Spec.GzipJson) if err != nil { r.Logger.Error(err, "failed to decode/decompress gzipped json") } else { @@ -417,7 +417,7 @@ func (r *DashboardPipelineImpl) loadDashboardFromConfigMap(ref *corev1.ConfigMap } if binaryCompressed { - jsonBytes, err := v1alpha1.DecodeGzip(cm.BinaryData[ref.Key]) + jsonBytes, err := v1alpha1.Gunzip(cm.BinaryData[ref.Key]) if err != nil { return err } diff --git a/deploy/examples/dashboards/CompressedDashboard.yaml b/deploy/examples/dashboards/CompressedDashboard.yaml index d25b2b25e..76afaa5f1 100644 --- a/deploy/examples/dashboards/CompressedDashboard.yaml +++ b/deploy/examples/dashboards/CompressedDashboard.yaml @@ -6,8 +6,4 @@ metadata: app: grafana spec: gzipJson: |- - H4sIAAAAAAAAA3WQwU7DMAyG73uKqmeQ4ABIXMcjIC4ITe7iNtbSOLK9TTDt3UnS0sKBm//Pv/1b - vmyapiXXPjfxGMJNUUYWMIN2y2MSVEXXvID6jkFcO1lg0Ox4/6hK7XMacCCH2UAjfnGstBM+K8rU - QEcGXbWbHLEyTw63HE04lK09BJ0ag0Dyr8zBKOXGfYUJIoZf6SUqq0uus+qFxxIa+Xz76Gtm8fDM - 2qyvy1ii/SEftgwXtuNkxHENyFywz3/wO4qGcoI5fV2FYwpgFId1VSC1vy6IkQ1+dv9rm7PKvQ86 - /Uz3Hkd4Q9E8XP7wVPFpAXdVB4qH+bLr5huze+uv2AEAAA== + H4sIAAAAAAAAA3WQwU7DMAyG73uKqmeQ4ABIXMcjIC4ITe7iNtbSOLK9TTDt3UnS0sKBm//Pv/1bvmyapiXXPjfxGMJNUUYWMIN2y2MSVEXXvID6jkFcO1lg0Ox4/6hK7XMacCCH2UAjfnGstBM+K8rUQEcGXbWbHLEyTw63HE04lK09BJ0ag0Dyr8zBKOXGfYUJIoZf6SUqq0uus+qFxxIa+Xz76Gtm8fDM2qyvy1ii/SEftgwXtuNkxHENyFywz3/wO4qGcoI5fV2FYwpgFId1VSC1vy6IkQ1+dv9rm7PKvQ86/Uz3Hkd4Q9E8XP7wVPFpAXdVB4qH+bLr5huze+uv2AEAAA== diff --git a/deploy/manifests/latest/crds.yaml b/deploy/manifests/latest/crds.yaml index e13128008..ec6678682 100644 --- a/deploy/manifests/latest/crds.yaml +++ b/deploy/manifests/latest/crds.yaml @@ -92,6 +92,7 @@ spec: - key type: object gzipJson: + format: byte type: string json: type: string diff --git a/documentation/api.md b/documentation/api.md index 95fa49aad..c43e4c55c 100644 --- a/documentation/api.md +++ b/documentation/api.md @@ -129,6 +129,8 @@ GrafanaDashboardSpec defines the desired state of GrafanaDashboard string
+
+ Format: byte
false diff --git a/documentation/dashboards.md b/documentation/dashboards.md index 2f985e26f..04d3760b5 100644 --- a/documentation/dashboards.md +++ b/documentation/dashboards.md @@ -215,5 +215,11 @@ You can compress a dashboard from the command line like so: ```bash # yq can be obtained from https://github.com/mikefarah/yq -COMPRESSED_DASHBOARD="$(cat ${dashboard_json_file} | gzip | base64)" yq -i '.spec.gzipJson = strenv(COMPRESSED_DASHBOARD)' ${grafanadashboard_yaml_file} +COMPRESSED_DASHBOARD="$(cat ${dashboard_json_file} | gzip | base64 -w0)" yq -i '.spec.gzipJson = strenv(COMPRESSED_DASHBOARD)' ${grafanadashboard_yaml_file} +``` + +You can similarly compress a dashboard into a ConfigMap like so: + +```bash +COMPRESSED_DASHBOARD="$(cat ${dashboard_json_file} | gzip | base64 -w0)" yq -i ".binaryData.${dashboard_key} = strenv(COMPRESSED_DASHBOARD)" ${configmap_yaml_file} ```