From aa4865aeb75439e6372cfbfb8f2b271ec177ac1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Thu, 27 Nov 2025 15:06:22 +0100 Subject: [PATCH 1/4] feat(tests): Add tests for gitops-must-gather (#958) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(tests): Add tests for gitops-must-gather Signed-off-by: Oliver Gondža * feat(tests): validate_running_must_gather.go: permit image override Signed-off-by: Oliver Gondža * fix(tests): 1-120_validate_running_must_gather.go: Do not read file to memory + please gosec Signed-off-by: Oliver Gondža * chore(test): Static analysis fixes Signed-off-by: Oliver Gondža * fix(tests): Suppress checking files not present in older ocp versions Signed-off-by: Oliver Gondža --------- Signed-off-by: Oliver Gondža Signed-off-by: akhil nittala --- go.mod | 2 +- .../1-120_validate_running_must_gather.go | 197 ++++++++++++++++++ 2 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 test/openshift/e2e/ginkgo/parallel/1-120_validate_running_must_gather.go diff --git a/go.mod b/go.mod index 695e81886..c9bdad753 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/stretchr/testify v1.11.1 go.uber.org/zap v1.27.0 golang.org/x/mod v0.29.0 + gopkg.in/yaml.v3 v3.0.1 gotest.tools v2.2.0+incompatible k8s.io/api v0.33.2 k8s.io/apiextensions-apiserver v0.33.1 @@ -158,7 +159,6 @@ require ( gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apiserver v0.33.2 // indirect k8s.io/cli-runtime v0.33.2 // indirect k8s.io/component-base v0.33.2 // indirect diff --git a/test/openshift/e2e/ginkgo/parallel/1-120_validate_running_must_gather.go b/test/openshift/e2e/ginkgo/parallel/1-120_validate_running_must_gather.go new file mode 100644 index 000000000..095da5132 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-120_validate_running_must_gather.go @@ -0,0 +1,197 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parallel + +import ( + "context" + "fmt" + "os" + "path" + "path/filepath" + "strings" + + osFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/os" + "gopkg.in/yaml.v3" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/types" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// default used when E2E_MUST_GATHER_IMAGE is not set. +// CI images: +// - quay.io/redhat-user-workloads/rh-openshift-gitops-tenant/gitops-must-gather:on-pr- +// - quay.io/redhat-user-workloads/rh-openshift-gitops-tenant/gitops-must-gather: +// - quay.io/redhat-user-workloads/rh-openshift-gitops-tenant/gitops-must-gather:latest # For main branch. +const defaultMustGatherImage = "quay.io/redhat-user-workloads/rh-openshift-gitops-tenant/gitops-must-gather:latest" + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-120_validate_running_must_gather", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verified the files collected for must gather are valid", func() { + By("creating namespace-scoped Argo CD instance") + ns, nsCleanup := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer nsCleanup() + + nsf, nsfCleanup := fixture.CreateManagedNamespaceWithCleanupFunc(ns.Name+"-follower", ns.Name) + defer nsfCleanup() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "left-argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{}, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CRs to be reconciled and the instances to be ready in " + ns.Name) + Eventually(argoCD, "5m", "5s").Should(argocdFixture.BeAvailable()) + + // TODO https://github.com/redhat-developer/gitops-must-gather/blob/135850b74b56b6fda9fc68ed4165a88b5c7dbeaf/gather_gitops.sh#L40 + // TODO https://github.com/redhat-developer/gitops-must-gather/blob/135850b74b56b6fda9fc68ed4165a88b5c7dbeaf/gather_gitops.sh#L61 + // TODO https://github.com/redhat-developer/gitops-must-gather/blob/135850b74b56b6fda9fc68ed4165a88b5c7dbeaf/gather_gitops.sh#L79 + + destDir := gather() + defer os.RemoveAll(destDir) + + // TODO: Not before 4.16: https://github.com/openshift/oc/commit/7d23cbb68dfed274b2821d91038f45c8ce12a249 + // Expect(path.Join(destDir, "must-gather.logs")).To(BeARegularFile()) + + Expect(path.Join(destDir, "event-filter.html")).To(BeARegularFile()) + Expect(path.Join(destDir, "timestamp")).To(BeARegularFile()) + + resources := resourcesDir(destDir) + // TODO: Not before 4.16: https://github.com/openshift/oc/commit/6348e4a0484fce9b4151dbf39ca17bdd8a450053 + // Expect(path.Join(resources, "gather.logs")).To(BeARegularFile()) + csr := path.Join(resources, "cluster-scoped-resources") + Expect(csr).To(BeADirectory()) + Expect(path.Join(csr, "apiextensions.k8s.io/customresourcedefinitions/applications.argoproj.io.yaml")).To(BeValidResourceFile()) + Expect(path.Join(csr, "argoproj.io/clusteranalysistemplates.yaml")).To(BeValidResourceFile()) + Expect(path.Join(csr, "config.openshift.io/clusterversions/version.yaml")).To(BeValidResourceFile()) + + n := path.Join(resources, "namespaces") + Expect(n).To(BeADirectory()) + Expect(path.Join(n, "openshift-gitops/openshift-gitops.yaml")).To(BeValidResourceFile()) + Expect(path.Join(n, "openshift-gitops/route.openshift.io/routes.yaml")).To(BeValidResourceFile()) + Expect(path.Join(n, "openshift-gitops/argoproj.io/appprojects.yaml")).To(BeValidResourceFile()) + logs := path.Join(n, "openshift-gitops/pods/openshift-gitops-application-controller-0/argocd-application-controller/argocd-application-controller/logs/") + Expect(path.Join(logs, "current.log")).To(BeARegularFile()) + Expect(path.Join(logs, "previous.log")).To(BeARegularFile()) + + Expect(path.Join(n, nsf.Name, "core/pods.yaml")).To(BeValidResourceFile()) + }) + }) +}) + +func gather() string { + destDir, err := os.MkdirTemp("", "gitops-operator-e2e-must-gather-test-1-120_*") + Expect(err).ToNot(HaveOccurred()) + + stdout, err := osFixture.ExecCommandWithOutputParam( + true, + "oc", "adm", "must-gather", "--image", mustGatherImage(), "--dest-dir", destDir, + ) + Expect(err).ToNot(HaveOccurred()) + + errorLines := make([]string, 0) + for _, line := range strings.Split(stdout, "\n") { + if strings.Contains(line, "error:") { + errorLines = append(errorLines, line) + } + } + Expect(errorLines).To(BeEmpty(), "Errors found in must gather output") + return destDir +} + +func resourcesDir(destDir string) string { + // Find the only subdirectory which contains must-gather data + entries, err := os.ReadDir(destDir) + Expect(err).ToNot(HaveOccurred()) + + var subdirs []string + for _, entry := range entries { + if entry.IsDir() { + subdirs = append(subdirs, entry.Name()) + } + } + + Expect(subdirs).To(HaveLen(1), "Expected exactly one subdirectory, found: %v", subdirs) + return path.Join(destDir, subdirs[0]) +} + +func mustGatherImage() string { + injected := os.Getenv("E2E_MUST_GATHER_IMAGE") + if injected == "" { + return defaultMustGatherImage + } + return injected +} + +// BeValidResourceFile checks if the file exists and if it is a valid YAML file. +func BeValidResourceFile() types.GomegaMatcher { + return &validResourceFile{} +} + +type validResourceFile struct{} + +func (matcher *validResourceFile) Match(actual any) (success bool, err error) { + filePath, ok := actual.(string) + if !ok { + return false, fmt.Errorf("BeValidResourceFile matcher expects a string (file path)") + } + + filePath = filepath.Clean(filePath) + f, err := os.Open(filePath) + if err != nil { + return false, fmt.Errorf("failed to read file: %v", err) + } + defer f.Close() + + decoder := yaml.NewDecoder(f) + var data map[string]any + if err := decoder.Decode(&data); err != nil { + return false, fmt.Errorf("failed parsing supposed YAML file: %v", err) + } + + _, exists := data["kind"] + return exists, nil +} + +func (matcher *validResourceFile) FailureMessage(actual any) string { + return fmt.Sprintf("Expected\n\t%v\nto be a valid YAML resource file", actual) +} + +func (matcher *validResourceFile) NegatedFailureMessage(actual any) string { + return fmt.Sprintf("Expected\n\t%v\nnot to be a valid YAML resource file", actual) +} From 617d58f36c16a31f8ce47e474163b575727827d6 Mon Sep 17 00:00:00 2001 From: akhil nittala Date: Thu, 4 Dec 2025 14:28:53 +0530 Subject: [PATCH 2/4] updated naming convention Signed-off-by: akhil nittala --- ...penshift-gitops-operator-metrics-bearer-token_v1_secret.yaml | 2 +- ...metrics-monitor_monitoring.coreos.com_v1_servicemonitor.yaml | 2 +- config/prometheus/monitor.yaml | 2 +- .../e2e/ginkgo/parallel/1-104_validate_prometheus_alert_test.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bundle/manifests/openshift-gitops-operator-metrics-bearer-token_v1_secret.yaml b/bundle/manifests/openshift-gitops-operator-metrics-bearer-token_v1_secret.yaml index a5ac5fdc9..ab422c66c 100644 --- a/bundle/manifests/openshift-gitops-operator-metrics-bearer-token_v1_secret.yaml +++ b/bundle/manifests/openshift-gitops-operator-metrics-bearer-token_v1_secret.yaml @@ -3,5 +3,5 @@ kind: Secret metadata: annotations: kubernetes.io/service-account.name: openshift-gitops-operator-controller-manager - name: openshift-gitops-operator-metrics-bearer-token + name: openshift-gitops-operator-metrics-monitor-bearer-token type: kubernetes.io/service-account-token diff --git a/bundle/manifests/openshift-gitops-operator-metrics-monitor_monitoring.coreos.com_v1_servicemonitor.yaml b/bundle/manifests/openshift-gitops-operator-metrics-monitor_monitoring.coreos.com_v1_servicemonitor.yaml index 042ed3f0b..3b4e719bc 100644 --- a/bundle/manifests/openshift-gitops-operator-metrics-monitor_monitoring.coreos.com_v1_servicemonitor.yaml +++ b/bundle/manifests/openshift-gitops-operator-metrics-monitor_monitoring.coreos.com_v1_servicemonitor.yaml @@ -8,7 +8,7 @@ spec: endpoints: - bearerTokenSecret: key: token - name: openshift-gitops-operator-metrics-bearer-token + name: openshift-gitops-operator-metrics-monitor-bearer-token interval: 30s path: /metrics port: metrics diff --git a/config/prometheus/monitor.yaml b/config/prometheus/monitor.yaml index 8a951845f..4107a2bd8 100644 --- a/config/prometheus/monitor.yaml +++ b/config/prometheus/monitor.yaml @@ -32,7 +32,7 @@ spec: control-plane: gitops-operator endpoints: - bearerTokenSecret: - name: openshift-gitops-operator-metrics-bearer-token + name: openshift-gitops-operator-metrics-monitor-bearer-token key: token interval: 30s path: /metrics diff --git a/test/openshift/e2e/ginkgo/parallel/1-104_validate_prometheus_alert_test.go b/test/openshift/e2e/ginkgo/parallel/1-104_validate_prometheus_alert_test.go index 147e52348..85162b73d 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-104_validate_prometheus_alert_test.go +++ b/test/openshift/e2e/ginkgo/parallel/1-104_validate_prometheus_alert_test.go @@ -39,7 +39,7 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { Expect(sm.Spec.Endpoints).To(Equal([]monitoringv1.Endpoint{{ BearerTokenSecret: &corev1.SecretKeySelector{ LocalObjectReference: corev1.LocalObjectReference{ - Name: "openshift-gitops-operator-metrics-bearer-token", + Name: "openshift-gitops-operator-metrics-monitor-bearer-token", }, Key: "token", }, From 980d4cfedb590af943f86cdc3ebb1ee67fd7c8a3 Mon Sep 17 00:00:00 2001 From: akhil nittala Date: Thu, 4 Dec 2025 14:44:44 +0530 Subject: [PATCH 3/4] updated naming convention Signed-off-by: akhil nittala --- .../manifests/gitops-operator.clusterserviceversion.yaml | 2 +- ...ps-operator-metrics-monitor-bearer-token_v1_secret.yaml | 7 +++++++ config/prometheus/monitor.yaml | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 bundle/manifests/openshift-gitops-operator-metrics-monitor-bearer-token_v1_secret.yaml diff --git a/bundle/manifests/gitops-operator.clusterserviceversion.yaml b/bundle/manifests/gitops-operator.clusterserviceversion.yaml index 5923e5127..188d7ec30 100644 --- a/bundle/manifests/gitops-operator.clusterserviceversion.yaml +++ b/bundle/manifests/gitops-operator.clusterserviceversion.yaml @@ -180,7 +180,7 @@ metadata: capabilities: Deep Insights console.openshift.io/plugins: '["gitops-plugin"]' containerImage: quay.io/redhat-developer/gitops-operator - createdAt: "2025-11-19T17:07:40Z" + createdAt: "2025-12-04T09:14:27Z" description: Enables teams to adopt GitOps principles for managing cluster configurations and application delivery across hybrid multi-cluster Kubernetes environments. features.operators.openshift.io/disconnected: "true" diff --git a/bundle/manifests/openshift-gitops-operator-metrics-monitor-bearer-token_v1_secret.yaml b/bundle/manifests/openshift-gitops-operator-metrics-monitor-bearer-token_v1_secret.yaml new file mode 100644 index 000000000..ab422c66c --- /dev/null +++ b/bundle/manifests/openshift-gitops-operator-metrics-monitor-bearer-token_v1_secret.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Secret +metadata: + annotations: + kubernetes.io/service-account.name: openshift-gitops-operator-controller-manager + name: openshift-gitops-operator-metrics-monitor-bearer-token +type: kubernetes.io/service-account-token diff --git a/config/prometheus/monitor.yaml b/config/prometheus/monitor.yaml index 4107a2bd8..c601f41a4 100644 --- a/config/prometheus/monitor.yaml +++ b/config/prometheus/monitor.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: Secret metadata: - name: metrics-bearer-token + name: metrics-monitor-bearer-token namespace: openshift-gitops-operator annotations: kubernetes.io/service-account.name: openshift-gitops-operator-controller-manager From 870e9824c9bb1e4c8bbf5e86b2be1e891c2bba76 Mon Sep 17 00:00:00 2001 From: akhil nittala Date: Thu, 4 Dec 2025 14:46:57 +0530 Subject: [PATCH 4/4] updated naming convention Signed-off-by: akhil nittala --- ...ift-gitops-operator-metrics-bearer-token_v1_secret.yaml | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 bundle/manifests/openshift-gitops-operator-metrics-bearer-token_v1_secret.yaml diff --git a/bundle/manifests/openshift-gitops-operator-metrics-bearer-token_v1_secret.yaml b/bundle/manifests/openshift-gitops-operator-metrics-bearer-token_v1_secret.yaml deleted file mode 100644 index ab422c66c..000000000 --- a/bundle/manifests/openshift-gitops-operator-metrics-bearer-token_v1_secret.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/service-account.name: openshift-gitops-operator-controller-manager - name: openshift-gitops-operator-metrics-monitor-bearer-token -type: kubernetes.io/service-account-token