diff --git a/Makefile b/Makefile index 50e62ec3e..e6858fa5c 100644 --- a/Makefile +++ b/Makefile @@ -156,6 +156,11 @@ test: $(ENVTEST) manifests generate vet golangci-lint api-docs kustomize-lint he $(info $(M) running $@) KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(BIN) -p path)" go test ./... -coverprofile cover.out +.PHONY: test-short +test-short: ## Skips slow integration tests + $(info $(M) running $@) + go test ./... -short -coverprofile cover.out + .PHONY: vet vet: ## Run go vet against code. $(info $(M) running $@) diff --git a/api/v1beta1/suite_test.go b/api/v1beta1/suite_test.go index 4ca8ba565..6f817eb20 100644 --- a/api/v1beta1/suite_test.go +++ b/api/v1beta1/suite_test.go @@ -43,6 +43,10 @@ var ( ) func TestAPIs(t *testing.T) { + if testing.Short() { + t.Skip("-short was passed, skipping CRDs") + } + RegisterFailHandler(Fail) RunSpecs(t, "CRDs Suite") diff --git a/controllers/config/operator_constants.go b/controllers/config/operator_constants.go index 056534004..a1b5dfade 100644 --- a/controllers/config/operator_constants.go +++ b/controllers/config/operator_constants.go @@ -18,6 +18,7 @@ const ( // Grafana env vars and admin user DefaultAdminUser = "admin" + DefaultAdminPassword = "admin" GrafanaAdminUserEnvVar = "GF_SECURITY_ADMIN_USER" GrafanaAdminPasswordEnvVar = "GF_SECURITY_ADMIN_PASSWORD" // #nosec G101 GrafanaPluginsEnvVar = "GF_INSTALL_PLUGINS" diff --git a/controllers/content/fetchers/suite_test.go b/controllers/content/fetchers/suite_test.go index 57840c629..e5ece6d00 100644 --- a/controllers/content/fetchers/suite_test.go +++ b/controllers/content/fetchers/suite_test.go @@ -21,6 +21,10 @@ var ( ) func TestAPIs(t *testing.T) { + if testing.Short() { + t.Skip("-short was passed, skipping Fetchers") + } + RegisterFailHandler(Fail) RunSpecs(t, "Fetchers Suite") diff --git a/controllers/content/suite_test.go b/controllers/content/suite_test.go index 398c4fa7d..7906c666a 100644 --- a/controllers/content/suite_test.go +++ b/controllers/content/suite_test.go @@ -81,6 +81,10 @@ func (in *NopContentResource) DeepCopyInto(out *NopContentResource) { } func TestAPIs(t *testing.T) { + if testing.Short() { + t.Skip("-short was passed, skipping Content") + } + RegisterFailHandler(Fail) RunSpecs(t, "Content Suite") diff --git a/controllers/controller_shared_test.go b/controllers/controller_shared_test.go index 04cf46d53..e1a3c140a 100644 --- a/controllers/controller_shared_test.go +++ b/controllers/controller_shared_test.go @@ -17,7 +17,6 @@ limitations under the License. package controllers import ( - "context" "testing" "github.com/grafana/grafana-operator/v5/api/v1beta1" @@ -28,7 +27,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" - logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/client" ) // Reusable objectMetas and CommonSpecs to make test tables less verbose @@ -73,6 +72,16 @@ var ( MatchLabels: map[string]string{"invalid-spec": "test"}, }, } + + objectMetaSynchronized = metav1.ObjectMeta{ + Namespace: "default", + Name: "synchronized", + } + commonSpecSynchronized = v1beta1.GrafanaCommonSpec{ + InstanceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"synchronized": "test"}, + }, + } ) func requestFromMeta(obj metav1.ObjectMeta) ctrl.Request { @@ -345,24 +354,19 @@ func TestMergeReconcileErrors(t *testing.T) { } var _ = Describe("GetMatchingInstances functions", Ordered, func() { - ns1 := corev1.Namespace{ObjectMeta: metav1.ObjectMeta{ - Name: "get-matching-test", - }} - ns2 := corev1.Namespace{ObjectMeta: metav1.ObjectMeta{ - Name: "additional-grafana-namespace", + ns := corev1.Namespace{ObjectMeta: metav1.ObjectMeta{ + Name: "matching-instances", }} allowFolder := v1beta1.GrafanaFolder{ ObjectMeta: metav1.ObjectMeta{ + Namespace: ns.Name, Name: "allow-cross-namespace", - Namespace: ns1.Name, }, Spec: v1beta1.GrafanaFolderSpec{ GrafanaCommonSpec: v1beta1.GrafanaCommonSpec{ AllowCrossNamespaceImport: true, InstanceSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "test": "folder", - }, + MatchLabels: map[string]string{"matching-instances": "test"}, }, }, }, @@ -373,69 +377,58 @@ var _ = Describe("GetMatchingInstances functions", Ordered, func() { denyFolder.Spec.AllowCrossNamespaceImport = false matchAllFolder := allowFolder.DeepCopy() - matchAllFolder.Name = "invalid-match-labels" + matchAllFolder.Name = "match-all-grafanas" matchAllFolder.Spec.InstanceSelector = &metav1.LabelSelector{} // InstanceSelector is never nil - DefaultGrafana := v1beta1.Grafana{ + BaseGrafana := v1beta1.Grafana{ ObjectMeta: metav1.ObjectMeta{ + Namespace: ns.Name, Name: "instance", - Namespace: ns2.Name, - Labels: map[string]string{ - "test": "folder", - }, + Labels: map[string]string{"matching-instances": "test"}, }, Spec: v1beta1.GrafanaSpec{}, } - matchesNothingGrafana := DefaultGrafana.DeepCopy() - matchesNothingGrafana.Name = "match-nothing-instance" + matchesNothingGrafana := BaseGrafana.DeepCopy() + matchesNothingGrafana.Name = "no-labels-instance" matchesNothingGrafana.Labels = nil - secondNamespaceGrafana := DefaultGrafana.DeepCopy() - secondNamespaceGrafana.Name = "second-namespace-instance" - secondNamespaceGrafana.Namespace = ns1.Name - // Status update is skipped for this - unreadyGrafana := DefaultGrafana.DeepCopy() + unreadyGrafana := BaseGrafana.DeepCopy() unreadyGrafana.Name = "unready-instance" - ctx := context.Background() - testLog := logf.FromContext(ctx).WithSink(logf.NullLogSink{}) - ctx = logf.IntoContext(ctx, testLog) + createCRs := []client.Object{&ns, &allowFolder, denyFolder, matchAllFolder, unreadyGrafana} // Pre-create all resources BeforeAll(func() { // Necessary to use assertions - Expect(k8sClient.Create(ctx, &ns1)).NotTo(HaveOccurred()) - Expect(k8sClient.Create(ctx, &ns2)).NotTo(HaveOccurred()) - Expect(k8sClient.Create(ctx, &allowFolder)).NotTo(HaveOccurred()) - Expect(k8sClient.Create(ctx, denyFolder)).NotTo(HaveOccurred()) - Expect(k8sClient.Create(ctx, matchAllFolder)).NotTo(HaveOccurred()) - Expect(k8sClient.Create(ctx, unreadyGrafana)).NotTo(HaveOccurred()) + for _, cr := range createCRs { + Expect(k8sClient.Create(testCtx, cr)).Should(Succeed()) + } - grafanas := []v1beta1.Grafana{DefaultGrafana, *matchesNothingGrafana, *secondNamespaceGrafana} + grafanas := []v1beta1.Grafana{BaseGrafana, *matchesNothingGrafana} for _, instance := range grafanas { - Expect(k8sClient.Create(ctx, &instance)).NotTo(HaveOccurred()) + Expect(k8sClient.Create(testCtx, &instance)).NotTo(HaveOccurred()) // Apply status to pass instance ready check instance.Status.Stage = v1beta1.OperatorStageComplete instance.Status.StageStatus = v1beta1.OperatorStageResultSuccess - Expect(k8sClient.Status().Update(ctx, &instance)).ToNot(HaveOccurred()) + Expect(k8sClient.Status().Update(testCtx, &instance)).ToNot(HaveOccurred()) } }) Context("Ensure AllowCrossNamespaceImport is upheld by GetScopedMatchingInstances", func() { It("Finds all ready instances when instanceSelector is empty", func() { - instances, err := GetScopedMatchingInstances(ctx, k8sClient, matchAllFolder) + instances, err := GetScopedMatchingInstances(testCtx, k8sClient, matchAllFolder) Expect(err).ToNot(HaveOccurred()) - Expect(instances).To(HaveLen(3 + 1)) // +1 To account for instance created in suite_test.go to provoke ApplyFailed conditions + Expect(instances).To(HaveLen(2 + 2)) // +2 To account for instances created in controllers/suite_test.go to provoke conditions }) It("Finds all ready and Matching instances", func() { - instances, err := GetScopedMatchingInstances(ctx, k8sClient, &allowFolder) + instances, err := GetScopedMatchingInstances(testCtx, k8sClient, &allowFolder) Expect(err).ToNot(HaveOccurred()) Expect(instances).ToNot(BeEmpty()) Expect(instances).To(HaveLen(2)) }) It("Finds matching and ready and matching instance in namespace", func() { - instances, err := GetScopedMatchingInstances(ctx, k8sClient, denyFolder) + instances, err := GetScopedMatchingInstances(testCtx, k8sClient, denyFolder) Expect(err).ToNot(HaveOccurred()) Expect(instances).ToNot(BeEmpty()) Expect(instances).To(HaveLen(1)) diff --git a/controllers/datasource_controller_test.go b/controllers/datasource_controller_test.go index 2bae2f108..77add2435 100644 --- a/controllers/datasource_controller_test.go +++ b/controllers/datasource_controller_test.go @@ -5,6 +5,7 @@ import ( "testing" v1beta1 "github.com/grafana/grafana-operator/v5/api/v1beta1" + grafanaclient "github.com/grafana/grafana-operator/v5/controllers/client" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" @@ -42,64 +43,132 @@ func TestGetDatasourceContent(t *testing.T) { }) } -var _ = Describe("Datasource: Reconciler", func() { +var _ = Describe("Datasource: substitute reference values", func() { It("Correctly substitutes valuesFrom", func() { - cm := corev1.ConfigMap{ + cm := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ - Name: "test-valuesfrom-plain", Namespace: "default", + Name: "ds-valuesfrom-configmap", }, Data: map[string]string{ - "CUSTOM_URL": "https://demo.promlabs.com", - "CUSTOM_TRACEID": "substituted", + "customTraceId": "substituted", }, } - err := k8sClient.Create(testCtx, &cm) - Expect(err).ToNot(HaveOccurred()) - cr := &v1beta1.GrafanaDatasource{ + sc := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "ds-values-from-secret", + }, + StringData: map[string]string{ + "PROMETHEUS_TOKEN": "secret_token", + "URL": "https://demo.promlabs.com", + }, + } + ds := &v1beta1.GrafanaDatasource{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", + Name: "substitute-reference-values", }, Spec: v1beta1.GrafanaDatasourceSpec{ + GrafanaCommonSpec: v1beta1.GrafanaCommonSpec{ + InstanceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "dashboards": "grafana", + }, + }, + }, + CustomUID: "substitute", ValuesFrom: []v1beta1.ValueFrom{ + { + TargetPath: "secureJsonData.httpHeaderValue1", + ValueFrom: v1beta1.ValueFromSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: sc.Name, + }, + Key: "PROMETHEUS_TOKEN", + }, + }, + }, { TargetPath: "url", ValueFrom: v1beta1.ValueFromSource{ - ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ + SecretKeyRef: &corev1.SecretKeySelector{ LocalObjectReference: corev1.LocalObjectReference{ - Name: cm.Name, + Name: sc.Name, }, - Key: "CUSTOM_URL", + Key: "URL", }, }, }, { - TargetPath: "jsonData.list[0].value", + TargetPath: "jsonData.exemplarTraceIdDestinations[1].name", ValueFrom: v1beta1.ValueFromSource{ ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ LocalObjectReference: corev1.LocalObjectReference{ Name: cm.Name, }, - Key: "CUSTOM_TRACEID", + Key: "customTraceId", }, }, }, }, Datasource: &v1beta1.GrafanaDatasourceInternal{ - URL: "${CUSTOM_URL}", - JSONData: json.RawMessage([]byte(`{"list":[{"value":"${CUSTOM_TRACEID}"}]}`)), + Name: "substitute-prometheus", + Type: "prometheus", + Access: "proxy", + URL: "${URL}", + JSONData: json.RawMessage([]byte(`{ + "tlsSkipVerify": true, + "timeInterval": "10s", + "httpHeaderName1": "Authorization", + "exemplarTraceIdDestinations": [ + {"name": "traceID"}, + {"name": "${customTraceId}"} + ] + }`)), + SecureJSONData: json.RawMessage([]byte(`{ + "httpHeaderValue1": "Bearer ${PROMETHEUS_TOKEN}" + }`)), }, }, } + Expect(k8sClient.Create(testCtx, cm)).Should(Succeed()) + Expect(k8sClient.Create(testCtx, sc)).Should(Succeed()) + Expect(k8sClient.Create(testCtx, ds)).Should(Succeed()) - r := GrafanaDatasourceReconciler{Client: k8sClient} - content, hash, err := r.buildDatasourceModel(testCtx, cr) + req := requestFromMeta(ds.ObjectMeta) + r := GrafanaDatasourceReconciler{Client: k8sClient, Scheme: k8sClient.Scheme()} + _, err := r.Reconcile(testCtx, req) Expect(err).ToNot(HaveOccurred()) - Expect(hash).ToNot(BeEmpty()) - Expect(content.URL).To(Equal(cm.Data["CUSTOM_URL"])) - marshaled, err := json.Marshal(content.JSONData) + + Expect(r.Get(testCtx, req.NamespacedName, ds)).Should(Succeed()) + Expect(ds.Status.Conditions).Should(ContainElement(HaveField("Type", conditionDatasourceSynchronized))) + Expect(ds.Status.Conditions).Should(ContainElement(HaveField("Reason", conditionReasonApplySuccessful))) + + cl, err := grafanaclient.NewGeneratedGrafanaClient(testCtx, k8sClient, externalGrafanaCr) + Expect(err).ToNot(HaveOccurred()) + + model, err := cl.Datasources.GetDataSourceByUID(ds.Spec.CustomUID) + Expect(err).ToNot(HaveOccurred()) + + Expect(model.Payload.URL).To(Equal("https://demo.promlabs.com")) + Expect(model.Payload.SecureJSONFields["httpHeaderValue1"]).To(BeTrue()) + + // Serialize and Derserialize jsonData + b, err := json.Marshal(model.Payload.JSONData) + Expect(err).ToNot(HaveOccurred()) + + type ExemplarTraceIDDestination struct { + Name string `json:"name"` + } + type SubstitutedJSONData struct { + ExemplarTraceIDDestinations []ExemplarTraceIDDestination `json:"exemplarTraceIdDestinations"` + } + var jsonData SubstitutedJSONData // map with array of + err = json.Unmarshal(b, &jsonData) Expect(err).ToNot(HaveOccurred()) - Expect(marshaled).To(ContainSubstring(cm.Data["CUSTOM_TRACEID"])) + Expect(jsonData.ExemplarTraceIDDestinations[1].Name).To(Equal("substituted")) }) }) diff --git a/controllers/e2e_force_delete_folder_test.go b/controllers/e2e_force_delete_folder_test.go new file mode 100644 index 000000000..78949ba45 --- /dev/null +++ b/controllers/e2e_force_delete_folder_test.go @@ -0,0 +1,134 @@ +package controllers + +import ( + "time" + + "github.com/grafana/grafana-openapi-client-go/client/folders" + "github.com/grafana/grafana-operator/v5/api/v1beta1" + grafanaclient "github.com/grafana/grafana-operator/v5/controllers/client" + v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +var _ = Describe("Successfully delete GrafanaFolder with GrafanaAlertRuleGroup referencing it", func() { + f := &v1beta1.GrafanaFolder{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "force-delete", + }, + Spec: v1beta1.GrafanaFolderSpec{ + GrafanaCommonSpec: commonSpecSynchronized, + CustomUID: "force-delete", + }, + } + noDataState := "NoData" + arg := &v1beta1.GrafanaAlertRuleGroup{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "force-delete", + }, + Spec: v1beta1.GrafanaAlertRuleGroupSpec{ + GrafanaCommonSpec: commonSpecSynchronized, + FolderRef: f.Name, + Interval: metav1.Duration{Duration: 60 * time.Second}, + Rules: []v1beta1.AlertRule{ + { + Title: "TestRule", + UID: "akdj-wonvo", + Condition: "A", + Data: []*v1beta1.AlertQuery{ + { + RefID: "A", + RelativeTimeRange: nil, + DatasourceUID: "__expr__", + Model: &v1.JSON{Raw: []byte(`{ + "conditions": [ + { + "evaluator": { + "params": [ + 0, + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "datasource": { + "name": "Expression", + "type": "__expr__", + "uid": "__expr__" + }, + "expression": "1 > 0", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 100, + "refId": "B", + "type": "math" + }`)}, + }, + }, + NoDataState: &noDataState, + ExecErrState: "Error", + For: &metav1.Duration{Duration: 60 * time.Second}, + Annotations: map[string]string{}, + Labels: map[string]string{}, + IsPaused: true, + }, + }, + }, + } + + It("Creates folder and rule group, deletes folder, checks folder got deleted", func() { + Expect(k8sClient.Create(testCtx, f)).To(Succeed()) + Expect(k8sClient.Create(testCtx, arg)).To(Succeed()) + + By("Reconcile Folder") + req := requestFromMeta(f.ObjectMeta) + fr := GrafanaFolderReconciler{Client: k8sClient, Scheme: k8sClient.Scheme()} + _, err := fr.Reconcile(testCtx, req) + Expect(err).ToNot(HaveOccurred()) + + By("Reconcile AlertRuleGroup") + req = requestFromMeta(arg.ObjectMeta) + argr := GrafanaAlertRuleGroupReconciler{Client: k8sClient, Scheme: k8sClient.Scheme()} + _, err = argr.Reconcile(testCtx, req) + Expect(err).ToNot(HaveOccurred()) + + cl, err := grafanaclient.NewGeneratedGrafanaClient(testCtx, k8sClient, externalGrafanaCr) + Expect(err).ToNot(HaveOccurred()) + + By("Verifying folder and alert rule group exist") + _, err = cl.Folders.GetFolderByUID(f.Spec.CustomUID) // nolint:errcheck + Expect(err).NotTo(HaveOccurred(), "Folder should exist in Grafana") + + _, err = cl.Provisioning.GetAlertRuleGroup(arg.GroupName(), f.Spec.CustomUID) // nolint:errcheck + Expect(err).NotTo(HaveOccurred(), "AlertRuleGroup should exist in Grafana") + + By("Deleting folder") + Expect(k8sClient.Delete(testCtx, f)).Should(Succeed()) + + _, err = fr.Reconcile(testCtx, req) + Expect(err).ToNot(HaveOccurred()) + + By("Verifying folder is missing") + _, err = cl.Folders.GetFolderByUID(f.Spec.CustomUID) // nolint:errcheck + Expect(err).To(HaveOccurred()) + + var notFound *folders.GetFolderByUIDNotFound + Expect(err).Should(BeAssignableToTypeOf(notFound), "Folder should have been removed from Grafana") + }) +}) diff --git a/controllers/reconcilers/grafana/suite_test.go b/controllers/reconcilers/grafana/suite_test.go index 5e822ccf3..1614d1381 100644 --- a/controllers/reconcilers/grafana/suite_test.go +++ b/controllers/reconcilers/grafana/suite_test.go @@ -41,9 +41,13 @@ var ( ) func TestAPIs(t *testing.T) { + if testing.Short() { + t.Skip("-short was passed, skipping Reconcilers") + } + RegisterFailHandler(Fail) - RunSpecs(t, "Controller Suite") + RunSpecs(t, "Reconcilers Suite") } var _ = BeforeSuite(func() { diff --git a/controllers/suite_test.go b/controllers/suite_test.go index 41be46f30..3ecc70d68 100644 --- a/controllers/suite_test.go +++ b/controllers/suite_test.go @@ -21,35 +21,53 @@ import ( "fmt" "path/filepath" "testing" - "time" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes/scheme" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/envtest" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" + "github.com/docker/go-connections/nat" "github.com/grafana/grafana-operator/v5/api/v1beta1" "github.com/grafana/grafana-operator/v5/controllers/config" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/wait" //+kubebuilder:scaffold:imports ) // These tests use Ginkgo (BDD-style Go testing framework). Refer to // http://onsi.github.io/ginkgo/ to learn more about Ginkgo. +const ( + grafanaName = "external-grafana" + grafanaUser = "root" + grafanaPass = "secret" +) + var ( - k8sClient client.Client - testEnv *envtest.Environment - testCtx context.Context + k8sClient client.Client + testEnv *envtest.Environment + testCtx context.Context + grafanaContainer testcontainers.Container + externalGrafanaCr *v1beta1.Grafana + + grafanaPort = nat.Port(fmt.Sprint(config.GrafanaHTTPPort)) //nolint ) func TestAPIs(t *testing.T) { + if testing.Short() { + t.Skip("-short was passed, skipping Controllers") + } + RegisterFailHandler(Fail) - RunSpecs(t, "Controller Suite") + RunSpecs(t, "Controllers Suite") } var _ = BeforeSuite(func() { @@ -74,20 +92,55 @@ var _ = BeforeSuite(func() { //+kubebuilder:scaffold:scheme + By("Instantiating k8sClient") k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) Expect(err).NotTo(HaveOccurred()) Expect(k8sClient).NotTo(BeNil()) - // NOTE(Baarsgaard) Ensure k8sClient is 100% ready - // ENVTEST sometimes fail all tests with a 401 Unauthorized - time.Sleep(100 * time.Millisecond) + By("Starting Grafana TestContainer") + grafanaContainer, err = testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + Started: true, + ContainerRequest: testcontainers.ContainerRequest{ + Name: fmt.Sprintf("%s-%d", grafanaName, GinkgoRandomSeed()), + Image: fmt.Sprintf("%s:%s", config.GrafanaImage, config.GrafanaVersion), + ExposedPorts: []string{grafanaPort.Port()}, + WaitingFor: wait.ForHTTP("/").WithPort(grafanaPort), + }, + }) + Expect(err).NotTo(HaveOccurred()) + + createSharedTestCRs() +}) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + testcontainers.CleanupContainer(GinkgoTB(), grafanaContainer) + Expect(testEnv.Stop()).To(Succeed()) +}) + +func createSharedTestCRs() { + GinkgoHelper() + + By("Creating GrafanaFolder for testing") + + folderCR := &v1beta1.GrafanaFolder{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "apply-failed-helper", + }, + Spec: v1beta1.GrafanaFolderSpec{ + GrafanaCommonSpec: commonSpecApplyFailed, + }, + } + Expect(k8sClient.Create(testCtx, folderCR)).ToNot(HaveOccurred()) + + By("Creating Grafana CRs. One Fake and one External") - By("Create a dummy 'invalid' instance to provoke conditions") intP := 1 - grafanaCr := &v1beta1.Grafana{ + dummy := &v1beta1.Grafana{ ObjectMeta: metav1.ObjectMeta{ - Name: "dummy", Namespace: "default", + Name: "dummy", Labels: map[string]string{ "apply-failed": "test", "invalid-spec": "test", @@ -96,40 +149,64 @@ var _ = BeforeSuite(func() { }, Spec: v1beta1.GrafanaSpec{ Client: &v1beta1.GrafanaClient{TimeoutSeconds: &intP}, + }, + } + + // External Endpoint + endpoint, err := grafanaContainer.PortEndpoint(testCtx, grafanaPort, "http") + Expect(err).NotTo(HaveOccurred()) + + external := &v1beta1.Grafana{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: grafanaName, + Labels: map[string]string{ + "synchronized": "test", + "matching-instances": "test", + "dashboards": "grafana", + }, + }, + Spec: v1beta1.GrafanaSpec{ + External: &v1beta1.External{ + URL: endpoint, + }, Config: map[string]map[string]string{ "security": { - "admin_user": "root", - "admin_password": "secret", + "admin_user": config.DefaultAdminUser, + "admin_password": config.DefaultAdminPassword, }, }, + Client: &v1beta1.GrafanaClient{TimeoutSeconds: &intP}, }, } - Expect(k8sClient.Create(testCtx, grafanaCr)).NotTo(HaveOccurred()) - grafanaCr.Status = v1beta1.GrafanaStatus{ + Expect(k8sClient.Create(testCtx, dummy)).Should(Succeed()) + Expect(k8sClient.Create(testCtx, external)).Should(Succeed()) + + dummy.Status = v1beta1.GrafanaStatus{ Stage: v1beta1.OperatorStageComplete, StageStatus: v1beta1.OperatorStageResultSuccess, AdminURL: fmt.Sprintf("http://%s-service", "invalid"), Version: config.GrafanaVersion, } - Expect(k8sClient.Status().Update(testCtx, grafanaCr)).ToNot(HaveOccurred()) + Expect(k8sClient.Status().Update(testCtx, dummy)).ToNot(HaveOccurred()) - // Should not be reconciled - By("Creating folder to use when provoking ApplyFailed conditions") - folderCr := &v1beta1.GrafanaFolder{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: objectMetaApplyFailed.Namespace, - Name: "apply-failed-helper", - }, - Spec: v1beta1.GrafanaFolderSpec{ - GrafanaCommonSpec: commonSpecApplyFailed, - }, + By("Reconciling External Grafana") + + r := GrafanaReconciler{ + Client: k8sClient, + Scheme: k8sClient.Scheme(), + IsOpenShift: false, } - Expect(k8sClient.Create(testCtx, folderCr)).ToNot(HaveOccurred()) -}) + reg := requestFromMeta(external.ObjectMeta) + _, err = r.Reconcile(testCtx, reg) + Expect(err).ToNot(HaveOccurred()) -var _ = AfterSuite(func() { - By("tearing down the test environment") - err := testEnv.Stop() - Expect(err).NotTo(HaveOccurred()) -}) + By("Get External Grafana") + + externalGrafanaCr = &v1beta1.Grafana{} + Expect(k8sClient.Get(testCtx, types.NamespacedName{ + Namespace: external.Namespace, + Name: external.Name, + }, externalGrafanaCr)).Should(Succeed()) +} diff --git a/go.mod b/go.mod index 99505901c..784bd4922 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/KimMachineGun/automemlimit v0.7.4 github.com/bitly/go-simplejson v0.5.1 github.com/blang/semver/v4 v4.0.0 + github.com/docker/go-connections v0.5.0 github.com/go-logr/logr v1.4.3 github.com/go-openapi/strfmt v0.23.0 github.com/google/go-jsonnet v0.21.0 @@ -16,6 +17,7 @@ require ( github.com/prometheus/client_golang v1.22.0 github.com/spyzhov/ajson v0.9.6 github.com/stretchr/testify v1.10.0 + github.com/testcontainers/testcontainers-go v0.38.0 go.uber.org/automaxprocs v1.6.0 k8s.io/api v0.33.3 k8s.io/apimachinery v0.33.3 @@ -24,10 +26,25 @@ require ( ) require ( + dario.cat/mergo v1.0.1 // indirect + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/containerd/errdefs v1.0.0 // indirect + github.com/containerd/errdefs/pkg v0.3.0 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/containerd/platforms v0.2.1 // indirect + github.com/cpuguy83/dockercfg v0.3.2 // indirect + github.com/distribution/reference v0.6.0 // indirect + github.com/docker/docker v28.2.2+incompatible // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/ebitengine/purego v0.8.4 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-openapi/analysis v0.23.0 // indirect github.com/go-openapi/errors v0.22.0 // indirect github.com/go-openapi/loads v0.22.0 // indirect @@ -38,19 +55,39 @@ require ( github.com/google/btree v1.1.3 // indirect github.com/google/gnostic-models v0.6.9 // indirect github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect + github.com/klauspost/compress v1.18.0 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/magiconair/properties v1.8.10 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/go-archive v0.1.0 // indirect + github.com/moby/patternmatcher v0.6.0 // indirect + github.com/moby/sys/sequential v0.6.0 // indirect + github.com/moby/sys/user v0.4.0 // indirect + github.com/moby/sys/userns v0.1.0 // indirect + github.com/moby/term v0.5.0 // indirect + github.com/morikuni/aec v1.0.0 // indirect github.com/oklog/ulid v1.3.1 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.1 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/shirou/gopsutil/v4 v4.25.5 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect github.com/x448/float16 v0.8.4 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect go.mongodb.org/mongo-driver v1.14.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/otel v1.33.0 // indirect - go.opentelemetry.io/otel/metric v1.33.0 // indirect - go.opentelemetry.io/otel/trace v1.33.0 // indirect - golang.org/x/crypto v0.36.0 // indirect - golang.org/x/sync v0.12.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect + go.opentelemetry.io/otel v1.35.0 // indirect + go.opentelemetry.io/otel/metric v1.35.0 // indirect + go.opentelemetry.io/otel/trace v1.35.0 // indirect + golang.org/x/crypto v0.37.0 // indirect + golang.org/x/sync v0.13.0 // indirect golang.org/x/tools v0.31.0 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect sigs.k8s.io/randfill v1.0.0 // indirect @@ -85,8 +122,8 @@ require ( golang.org/x/net v0.38.0 // indirect golang.org/x/oauth2 v0.27.0 // indirect golang.org/x/sys v0.32.0 // indirect - golang.org/x/term v0.30.0 // indirect - golang.org/x/text v0.23.0 // indirect + golang.org/x/term v0.31.0 // indirect + golang.org/x/text v0.24.0 // indirect golang.org/x/time v0.9.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/protobuf v1.36.5 // indirect diff --git a/go.sum b/go.sum index b7912435e..f3c5b4d83 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,13 @@ +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/KimMachineGun/automemlimit v0.7.4 h1:UY7QYOIfrr3wjjOAqahFmC3IaQCLWvur9nmfIn6LnWk= github.com/KimMachineGun/automemlimit v0.7.4/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -8,18 +16,44 @@ github.com/bitly/go-simplejson v0.5.1 h1:xgwPbetQScXt1gh9BmoJ6j9JMr3TElvuIyjR8pg github.com/bitly/go-simplejson v0.5.1/go.mod h1:YOPVLzCfwK14b4Sff3oP1AmGhI9T9Vsg84etUnlyp+Q= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= +github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= +github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= +github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= +github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= +github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/docker v28.2.2+incompatible h1:CjwRSksz8Yo4+RmQ339Dp/D2tGO5JxwYeqtMOEe0LDw= +github.com/docker/docker v28.2.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= +github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= @@ -31,6 +65,8 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU= github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo= github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w= @@ -59,6 +95,7 @@ github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= @@ -73,6 +110,9 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grafana/grafana-openapi-client-go v0.0.0-20250108132429-8d7e1f158f65 h1:AnfwjPE8TXJO8CX0Q5PvtzGta9Ls3iRASWVV4jHl4KA= github.com/grafana/grafana-openapi-client-go v0.0.0-20250108132429-8d7e1f158f65/go.mod h1:hiZnMmXc9KXNUlvkV2BKFsiWuIFF/fF4wGgYWEjBitI= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -87,15 +127,37 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= +github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ= +github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo= +github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw= +github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs= +github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= +github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= +github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= +github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= +github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= +github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= @@ -104,6 +166,10 @@ github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/openshift/api v0.0.0-20190924102528-32369d4db2ad h1:MiZEukiPd7ll8BQDwBfc3LKBxbqyeXIx+wl4CzVj5EQ= github.com/openshift/api v0.0.0-20190924102528-32369d4db2ad/go.mod h1:dh9o4Fs58gpFXGSYfnVxGR9PnV53I8TW84pQaJDdGiY= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= @@ -115,6 +181,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= @@ -129,6 +197,10 @@ github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/shirou/gopsutil/v4 v4.25.5 h1:rtd9piuSMGeU8g1RMXjZs9y9luK5BwtnG7dZaQUJAsc= +github.com/shirou/gopsutil/v4 v4.25.5/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spyzhov/ajson v0.9.6 h1:iJRDaLa+GjhCDAt1yFtU/LKMtLtsNVKkxqlpvrHHlpQ= @@ -137,24 +209,41 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/testcontainers/testcontainers-go v0.38.0 h1:d7uEapLcv2P8AvH8ahLqDMMxda2W9gQN1nRbHS28HBw= +github.com/testcontainers/testcontainers-go v0.38.0/go.mod h1:C52c9MoHpWO+C4aqmgSU+hxlR5jlEayWtgYrb8Pzz1w= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw= -go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I= -go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ= -go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= +go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= +go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0 h1:Vh5HayB/0HHfOQA7Ctx69E/Y/DcQSMPpKANYVMQ7fBA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0/go.mod h1:cpgtDBaqD/6ok/UG0jT15/uKjAY8mRA53diogHBg3UI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= +go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= +go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= go.opentelemetry.io/otel/sdk v1.33.0 h1:iax7M131HuAm9QkZotNHEfstof92xM+N8sr3uHXc2IM= go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM= -go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= -go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= +go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= +go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg= +go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY= go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -166,8 +255,8 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= +golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -181,19 +270,25 @@ golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= +golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= -golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= +golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= +golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -208,6 +303,13 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= +google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ= +google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q= +google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0= +google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw= google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -217,8 +319,11 @@ gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSP gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= k8s.io/api v0.33.3 h1:SRd5t//hhkI1buzxb288fy2xvjubstenEKL9K51KBI8= k8s.io/api v0.33.3/go.mod h1:01Y/iLUjNBM3TAvypct7DIj0M0NIZc+PzAHCIo0CYGE= k8s.io/apiextensions-apiserver v0.33.3 h1:qmOcAHN6DjfD0v9kxL5udB27SRP6SG/MTopmge3MwEs= diff --git a/tests/e2e/datasource_values_from/chainsaw-test.yaml b/tests/e2e/datasource_values_from/chainsaw-test.yaml deleted file mode 100644 index a3e80291e..000000000 --- a/tests/e2e/datasource_values_from/chainsaw-test.yaml +++ /dev/null @@ -1,100 +0,0 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json -apiVersion: chainsaw.kyverno.io/v1alpha1 -kind: Test -metadata: - name: datasource-variable-substitution -spec: - bindings: - - name: USER - value: root - - name: PASS - value: secret - steps: - - name: Create resources - try: - - apply: - file: ./resources.yaml - - - assert: - resource: - apiVersion: v1 - kind: Pod - metadata: - (contains(name, 'testdata-deployment')): true - - - wait: - apiVersion: v1 - kind: Pod - timeout: 1m - for: - condition: - name: Ready - value: 'true' - - - assert: - resource: - apiVersion: grafana.integreatly.org/v1beta1 - kind: Grafana - metadata: - name: testdata - status: - stage: complete - stageStatus: success - - - assert: - resource: - apiVersion: grafana.integreatly.org/v1beta1 - kind: GrafanaDatasource - metadata: - name: grafanadatasource-sample - status: - conditions: - - reason: ApplySuccessful - status: "True" - type: DatasourceSynchronized - - - name: Ensure data source exists in Grafana - try: - - apply: - resource: - apiVersion: batch/v1 - kind: Job - metadata: - name: folder-curl - spec: - backoffLimit: 1 - template: - spec: - restartPolicy: Never - containers: - - name: curl - image: alpine/curl:latest - command: ["ash", "-c"] - args: - - | - curl --fail --silent --show-error \ - -u ${BASIC_USER}:${BASIC_PASS} \ - "http://testdata-service.${NS}.svc:3000/api/datasources/uid/testdata-uid" > /tmp/response.json || exit 1; - grep 'customTraceId' /tmp/response.json || exit 1; - grep 'demo.promlabs.com' /tmp/response.json || exit 1; - env: - - name: BASIC_USER - value: ($USER) - - name: BASIC_PASS - value: ($PASS) - - name: NS - value: ($namespace) - - assert: - resource: - apiVersion: batch/v1 - kind: Job - metadata: - name: folder-curl - status: - (conditions[?type == 'Complete']): - - status: "True" - - delete: - ref: - apiVersion: batch/v1 - kind: Job - name: folder-curl diff --git a/tests/e2e/datasource_values_from/resources.yaml b/tests/e2e/datasource_values_from/resources.yaml deleted file mode 100644 index 63c046d9a..000000000 --- a/tests/e2e/datasource_values_from/resources.yaml +++ /dev/null @@ -1,74 +0,0 @@ -kind: Secret -apiVersion: v1 -metadata: - name: credentials -stringData: - PROMETHEUS_TOKEN: secret_token - URL: 'https://demo.promlabs.com' -type: Opaque ---- -kind: ConfigMap -apiVersion: v1 -metadata: - name: dynamic-settings -data: - dynamicTraceId: customTraceId ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaDatasource -metadata: - name: grafanadatasource-sample -spec: - uid: 'testdata-uid' - valuesFrom: - - targetPath: "secureJsonData.httpHeaderValue1" - valueFrom: - secretKeyRef: - name: "credentials" - key: "PROMETHEUS_TOKEN" - - targetPath: "url" - valueFrom: - secretKeyRef: - name: "credentials" - key: "URL" - - targetPath: 'jsonData.exemplarTraceIdDestinations[1].name' - valueFrom: - configMapKeyRef: - name: dynamic-settings - key: dynamicTraceId - instanceSelector: - matchLabels: - test: ($test.metadata.name) - datasource: - name: prometheus - type: prometheus - access: proxy - basicAuth: true - url: '${URL}' - isDefault: true - jsonData: - "tlsSkipVerify": true - "timeInterval": "5s" - httpHeaderName1: "Authorization" - exemplarTraceIdDestinations: - - name: 'traceID' - - name: '${dynamicTraceId}' - secureJsonData: - "httpHeaderValue1": "Bearer ${PROMETHEUS_TOKEN}" ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: Grafana -metadata: - name: testdata - labels: - test: ($test.metadata.name) -spec: - config: - log: - mode: "console" - auth: - disable_login_form: "false" - security: - admin_user: ($USER) - admin_password: ($PASS) ---- diff --git a/tests/e2e/force_delete_folder/chainsaw-test.yaml b/tests/e2e/force_delete_folder/chainsaw-test.yaml deleted file mode 100644 index 15683194a..000000000 --- a/tests/e2e/force_delete_folder/chainsaw-test.yaml +++ /dev/null @@ -1,130 +0,0 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json -apiVersion: chainsaw.kyverno.io/v1alpha1 -kind: Test -metadata: - name: force-delete-folders -spec: - bindings: - - name: USER - value: root - - name: PASS - value: secret - steps: - - name: Create Grafana with testdata resources - try: - - apply: - file: ../testdata-resources.yaml - - - assert: - resource: - apiVersion: v1 - kind: Pod - metadata: - (contains(name, 'testdata-deployment')): true - - - wait: - apiVersion: v1 - kind: Pod - timeout: 1m - for: - condition: - name: Ready - value: 'true' - - - assert: - resource: - apiVersion: grafana.integreatly.org/v1beta1 - kind: Grafana - metadata: - name: testdata - status: - stage: complete - stageStatus: success - - - assert: - resource: - apiVersion: grafana.integreatly.org/v1beta1 - kind: GrafanaFolder - metadata: - name: testdata - status: - conditions: - - reason: ApplySuccessful - status: "True" - type: FolderSynchronized - - - assert: - resource: - apiVersion: grafana.integreatly.org/v1beta1 - kind: GrafanaAlertRuleGroup - metadata: - name: testdata - status: - conditions: - - reason: ApplySuccessful - status: "True" - type: AlertGroupSynchronized - - - name: Ensure folder exists in Grafana - try: - - apply: &curlJob - resource: - apiVersion: batch/v1 - kind: Job - metadata: - name: folder-curl - spec: - backoffLimit: 1 - template: - spec: - restartPolicy: Never - containers: - - name: curl - image: alpine/curl:latest - command: ["ash", "-c"] - args: - - | - curl --fail --silent --show-error \ - -u ${BASIC_USER}:${BASIC_PASS} \ - "http://testdata-service.${NS}.svc:3000/api/folders/testdata-uid" - env: - - name: BASIC_USER - value: ($USER) - - name: BASIC_PASS - value: ($PASS) - - name: NS - value: ($namespace) - - assert: - resource: - apiVersion: batch/v1 - kind: Job - metadata: - name: folder-curl - status: - (conditions[?type == 'Complete']): - - status: "True" - - delete: - ref: - apiVersion: batch/v1 - kind: Job - name: folder-curl - - - name: Delete Folder and verify it's removed in Grafana - try: - - delete: - ref: - apiVersion: grafana.integreatly.org/v1beta1 - kind: GrafanaFolder - name: testdata - - - apply: *curlJob - - - assert: - resource: - apiVersion: batch/v1 - kind: Job - metadata: - name: folder-curl - status: - (conditions[?type == 'Failed']): - - status: "True" diff --git a/tests/e2e/testdata-assertions.yaml b/tests/e2e/testdata-assertions.yaml deleted file mode 100644 index a7e57b8eb..000000000 --- a/tests/e2e/testdata-assertions.yaml +++ /dev/null @@ -1,92 +0,0 @@ ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaNotificationTemplate -metadata: - name: testdata -status: - conditions: - - reason: ApplySuccessful - status: "True" - type: NotificationTemplateSynchronized ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaContactPoint -metadata: - name: testdata -status: - conditions: - - reason: ApplySuccessful - status: "True" - type: ContactPointSynchronized ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaNotificationPolicy -metadata: - name: testdata -status: - conditions: - - reason: ApplySuccessful - status: "True" - type: NotificationPolicySynchronized ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaNotificationPolicyRoute -metadata: - name: team-b -status: {} ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaNotificationPolicyRoute -metadata: - name: team-c -status: {} ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaFolder -metadata: - name: testdata -status: - conditions: - - reason: ApplySuccessful - status: "True" - type: FolderSynchronized ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaAlertRuleGroup -metadata: - name: testdata -status: - conditions: - - reason: ApplySuccessful - status: "True" - type: AlertGroupSynchronized ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaMuteTiming -metadata: - name: testdata -status: - conditions: - - reason: ApplySuccessful - status: "True" - type: MuteTimingSynchronized ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaDashboard -metadata: - name: testdata -status: - conditions: - - reason: ApplySuccessful - status: "True" - type: DashboardSynchronized ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaDatasource -metadata: - name: testdata -status: - conditions: - - reason: ApplySuccessful - status: "True" - type: DatasourceSynchronized diff --git a/tests/e2e/testdata-resources.yaml b/tests/e2e/testdata-resources.yaml deleted file mode 100644 index edd0d97fe..000000000 --- a/tests/e2e/testdata-resources.yaml +++ /dev/null @@ -1,482 +0,0 @@ ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaNotificationTemplate -metadata: - name: testdata -spec: - name: emailtestdata - instanceSelector: - matchLabels: - test: ($test.metadata.name) - resyncPeriod: 3s - template: | - {{ define "emailAlert" }} - [{{.Status}}] {{ .Labels.alertname }} - {{ .Annotations.AlertValues }} - {{ end }} - - {{ define "emailAlertMessage" }} - {{ if gt (len .Alerts.Firing) 0 }} - {{ len .Alerts.Firing }} firing: - {{ range .Alerts.Firing }} {{ template "emailAlert" . }} {{ end }} - {{ end }} - {{ if gt (len .Alerts.Resolved) 0 }} - {{ len .Alerts.Resolved }} resolved: - {{ range .Alerts.Resolved }} {{ template "emailAlert" . }} {{ end }} - {{ end }} - {{ end }} - - {{ template "emailAlertMessage" . }} ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaContactPoint -metadata: - name: testdata -spec: - name: testdata - type: email - instanceSelector: - matchLabels: - test: ($test.metadata.name) - resyncPeriod: 3s - settings: - addresses: "void@testdata.invalid" ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaNotificationPolicy -metadata: - name: testdata -spec: - instanceSelector: - matchLabels: - test: ($test.metadata.name) - resyncPeriod: 3s - route: - receiver: grafana-default-email - group_by: - - grafana_folder - - alertname - routes: - - receiver: grafana-default-email - object_matchers: - - - team - - = - - a - routeSelector: - matchLabels: - team-a: "child" ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaNotificationPolicyRoute -metadata: - labels: - team-a: "child" - name: team-b -spec: - receiver: grafana-default-email - object_matchers: - - - team - - = - - b - routeSelector: - matchLabels: - team-b: "child" ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaNotificationPolicyRoute -metadata: - labels: - team-b: "child" - name: team-c -spec: - receiver: grafana-default-email - object_matchers: - - - team - - = - - c ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaNotificationPolicyRoute -metadata: - labels: - team-a: "child" - name: team-d -spec: - receiver: grafana-default-email - object_matchers: - - - team - - = - - d ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaFolder -metadata: - name: testdata -spec: - resyncPeriod: 3s - instanceSelector: - matchLabels: - test: ($test.metadata.name) - uid: testdata-uid - title: "Test Data" ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaDatasource -metadata: - name: testdata -spec: - resyncPeriod: 3s - instanceSelector: - matchLabels: - test: "($test.metadata.name)" - datasource: - orgId: 1 - isDefault: true - uid: grafana-testdata - name: grafana-testdata-datasource - type: grafana-testdata-datasource - access: proxy - basicAuth: false ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaMuteTiming -metadata: - name: testdata -spec: - resyncPeriod: 3s - instanceSelector: - matchLabels: - test: "($test.metadata.name)" - name: testdata - editable: false - time_intervals: - - times: - - start_time: "20:00" - end_time: "23:59" - - start_time: "00:00" - end_time: "06:00" - weekdays: [saturday, sunday] - location: Europe/Amsterdam ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaAlertRuleGroup -metadata: - name: testdata -spec: - folderRef: testdata - resyncPeriod: 3s - instanceSelector: - matchLabels: - test: ($test.metadata.name) - interval: 5m - rules: - - uid: ae1rhq - title: Test - condition: C - data: - - refId: A - relativeTimeRange: - from: 600 - to: 0 - datasourceUid: grafana-testdata - model: - drop: 0 - intervalMs: 1000 - labels: "" - max: 50 - maxDataPoints: 43200 - min: -50 - noise: 0 - refId: A - scenarioId: random_walk - seriesCount: 3 - spread: 5 - startValue: 0 - stringInput: 1,20,90,30,5,0 - - refId: B - relativeTimeRange: - from: 600 - to: 0 - datasourceUid: __expr__ - model: - conditions: - - evaluator: - params: - - 0 - - 0 - type: gt - operator: - type: and - query: - params: [] - reducer: - params: [] - type: avg - type: query - datasource: - name: Expression - type: __expr__ - uid: __expr__ - expression: A - hide: false - intervalMs: 1000 - maxDataPoints: 43200 - reducer: max - refId: B - settings: - mode: dropNN - type: reduce - - refId: C - relativeTimeRange: - from: 600 - to: 0 - datasourceUid: __expr__ - model: - conditions: - - evaluator: - params: - - 45 - - 0 - type: gt - operator: - type: and - query: - params: [] - reducer: - params: [] - type: avg - type: query - datasource: - name: Expression - type: __expr__ - uid: __expr__ - expression: B - hide: false - intervalMs: 1000 - maxDataPoints: 43200 - refId: C - type: threshold - noDataState: NoData - execErrState: Error - for: 5m - annotations: {} - labels: {} - isPaused: false ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaDashboard -metadata: - name: testdata -spec: - folderRef: testdata - resyncPeriod: 3s - instanceSelector: - matchLabels: - test: "($test.metadata.name)" - json: > - { - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "grafana", - "uid": "-- Grafana --" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } - ] - }, - "editable": true, - "fiscalYearStartMonth": 0, - "graphTooltip": 0, - "links": [], - "panels": [ - { - "datasource": { - "type": "grafana-testdata-datasource", - "uid": "grafana-testdata" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "align": "auto", - "cellOptions": { - "type": "auto" - }, - "inspect": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "id" - }, - "properties": [ - { - "id": "custom.width", - "value": 72 - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 2, - "options": { - "cellHeight": "sm", - "footer": { - "countRows": false, - "fields": "", - "reducer": [ - "sum" - ], - "show": false - }, - "showHeader": true, - "sortBy": [] - }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": { - "type": "grafana-testdata-datasource", - "uid": "grafana-testdata" - }, - "refId": "A", - "scenarioId": "grafana_api", - "stringInput": "datasources" - } - ], - "title": "Panel Title", - "type": "table" - }, - { - "datasource": { - "type": "grafana-testdata-datasource", - "uid": "grafana-testdata" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "align": "auto", - "cellOptions": { - "type": "auto" - }, - "inspect": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 24, - "x": 0, - "y": 8 - }, - "id": 1, - "options": { - "cellHeight": "sm", - "footer": { - "countRows": false, - "fields": "", - "reducer": [ - "sum" - ], - "show": false - }, - "showHeader": true - }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": { - "type": "grafana-testdata-datasource", - "uid": "grafana-testdata" - }, - "hide": false, - "refId": "A", - "scenarioId": "grafana_api", - "stringInput": "search" - } - ], - "title": "Panel Title", - "type": "table" - } - ], - "schemaVersion": 39, - "tags": [], - "templating": { - "list": [] - }, - "time": { - "from": "now-6h", - "to": "now" - }, - "timepicker": {}, - "timezone": "browser", - "title": "New dashboard", - "version": 0, - "weekStart": "" - } ---- -# Last to be cleaned up first -apiVersion: grafana.integreatly.org/v1beta1 -kind: Grafana -metadata: - name: testdata - labels: - test: ($test.metadata.name) -spec: - config: - log: - mode: "console" - auth: - disable_login_form: "false" - security: - admin_user: ($USER) - admin_password: ($PASS)