Skip to content

Commit 878c3e6

Browse files
authored
Merge branch 'master' into usr/akhil/GITOPS-9256
2 parents 7a32cc8 + ddee831 commit 878c3e6

3 files changed

Lines changed: 218 additions & 2 deletions

File tree

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ e2e-tests-ginkgo: e2e-tests-sequential-ginkgo e2e-tests-parallel-ginkgo ## Runs
157157
.PHONY: e2e-tests-sequential-ginkgo
158158
e2e-tests-sequential-ginkgo: ginkgo ## Runs kuttl e2e sequential tests
159159
@echo "Running GitOps Operator sequential Ginkgo E2E tests..."
160-
$(GINKGO_CLI) -v --trace --timeout 180m -r ./test/openshift/e2e/ginkgo/sequential
160+
$(GINKGO_CLI) -v --trace --timeout 240m -r ./test/openshift/e2e/ginkgo/sequential
161161

162162
.PHONY: e2e-tests-parallel-ginkgo ## Runs kuttl e2e parallel tests, (Defaults to 5 runs at a time)
163163
e2e-tests-parallel-ginkgo: ginkgo

bundle/manifests/gitops-operator.clusterserviceversion.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ metadata:
190190
capabilities: Deep Insights
191191
console.openshift.io/plugins: '["gitops-plugin"]'
192192
containerImage: quay.io/redhat-developer/gitops-operator
193-
createdAt: "2026-04-09T09:03:42Z"
193+
createdAt: "2026-04-09T19:32:55Z"
194194
description: Enables teams to adopt GitOps principles for managing cluster configurations
195195
and application delivery across hybrid multi-cluster Kubernetes environments.
196196
features.operators.openshift.io/disconnected: "true"
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
package sequential
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"os/exec"
7+
8+
argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1"
9+
. "github.com/onsi/ginkgo/v2"
10+
. "github.com/onsi/gomega"
11+
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
12+
"github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture"
13+
argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd"
14+
k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s"
15+
fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils"
16+
appsv1 "k8s.io/api/apps/v1"
17+
corev1 "k8s.io/api/core/v1"
18+
"k8s.io/apimachinery/pkg/api/errors"
19+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
20+
"sigs.k8s.io/controller-runtime/pkg/client"
21+
)
22+
23+
var _ = Describe("GitOps Operator Sequential E2E Tests", func() {
24+
25+
Context("1-092_validate_workload_status_monitoring_alert", func() {
26+
var (
27+
k8sClient client.Client
28+
ctx context.Context
29+
nsCluster *corev1.Namespace
30+
nsNamespaced *corev1.Namespace
31+
cleanupFunc func()
32+
)
33+
34+
BeforeEach(func() {
35+
fixture.EnsureSequentialCleanSlate()
36+
k8sClient, _ = fixtureUtils.GetE2ETestKubeClient()
37+
ctx = context.Background()
38+
39+
nsCluster = &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops"}}
40+
nsNamespaced, cleanupFunc = fixture.CreateRandomE2ETestNamespaceWithCleanupFunc()
41+
})
42+
43+
AfterEach(func() {
44+
defer cleanupFunc()
45+
fixture.OutputDebugOnFail(nsNamespaced)
46+
})
47+
48+
It("validates monitoring setup, alert rule creation, and teardown", func() {
49+
const (
50+
// picking image that exists to avoid ImagePullBackOff but should fail to run as an ApplicationSet controller
51+
invalidImage = "quay.io/libpod/alpine:latest"
52+
prometheusRuleName = "argocd-component-status-alert"
53+
clusterInstanceName = "openshift-gitops"
54+
)
55+
56+
ruleCluster := &monitoringv1.PrometheusRule{
57+
ObjectMeta: metav1.ObjectMeta{Name: prometheusRuleName, Namespace: nsCluster.Name},
58+
}
59+
ruleNamespaced := &monitoringv1.PrometheusRule{
60+
ObjectMeta: metav1.ObjectMeta{Name: prometheusRuleName, Namespace: nsNamespaced.Name},
61+
}
62+
appSetDeplCluster := &appsv1.Deployment{
63+
ObjectMeta: metav1.ObjectMeta{Name: clusterInstanceName + "-applicationset-controller", Namespace: nsCluster.Name},
64+
}
65+
appSetDeplNamespaced := &appsv1.Deployment{
66+
ObjectMeta: metav1.ObjectMeta{Name: "argocd-applicationset-controller", Namespace: nsNamespaced.Name},
67+
}
68+
uwmConfigMap := &corev1.ConfigMap{
69+
ObjectMeta: metav1.ObjectMeta{Name: "cluster-monitoring-config", Namespace: "openshift-monitoring"},
70+
Data: map[string]string{"config.yaml": "enableUserWorkload: true\n"},
71+
}
72+
73+
By("labeling the namespace for monitoring")
74+
// prometheus will only scrape user workload namespaces that have this label
75+
err := k8sClient.Get(ctx, client.ObjectKeyFromObject(nsNamespaced), nsNamespaced)
76+
Expect(err).NotTo(HaveOccurred())
77+
78+
if nsNamespaced.Labels == nil {
79+
nsNamespaced.Labels = make(map[string]string)
80+
}
81+
nsNamespaced.Labels["openshift.io/cluster-monitoring"] = "true"
82+
err = k8sClient.Update(ctx, nsNamespaced)
83+
Expect(err).NotTo(HaveOccurred())
84+
85+
By("enabling user workload monitoring in the cluster monitoring config map")
86+
existingCM := &corev1.ConfigMap{}
87+
err = k8sClient.Get(ctx, client.ObjectKeyFromObject(uwmConfigMap), existingCM)
88+
89+
cmExisted := (err == nil)
90+
var originalData map[string]string
91+
92+
if cmExisted {
93+
originalData = existingCM.Data
94+
existingCM.Data = uwmConfigMap.Data
95+
Expect(k8sClient.Update(ctx, existingCM)).To(Succeed(), "Failed to update existing UWM ConfigMap")
96+
} else if errors.IsNotFound(err) {
97+
Expect(k8sClient.Create(ctx, uwmConfigMap)).To(Succeed(), "Failed to create UWM ConfigMap")
98+
} else {
99+
Expect(err).NotTo(HaveOccurred(), "Failed to fetch UWM ConfigMap")
100+
}
101+
102+
DeferCleanup(func() {
103+
By("restoring or deleting cluster monitoring config")
104+
if cmExisted {
105+
revertCM := &corev1.ConfigMap{}
106+
Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(uwmConfigMap), revertCM)).To(Succeed())
107+
revertCM.Data = originalData
108+
Expect(k8sClient.Update(ctx, revertCM)).To(Succeed())
109+
} else {
110+
_ = k8sClient.Delete(ctx, uwmConfigMap)
111+
}
112+
})
113+
114+
By("modifying both ArgoCD instances to enable monitoring and break the AppSet image")
115+
argoCDCluster := &argov1beta1api.ArgoCD{
116+
ObjectMeta: metav1.ObjectMeta{Name: clusterInstanceName, Namespace: nsCluster.Name},
117+
}
118+
Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(argoCDCluster), argoCDCluster)).To(Succeed())
119+
120+
// restore even if the test fails halfway
121+
DeferCleanup(func() {
122+
By("restoring the default image and disabling monitoring on cluster Argo CD instance (Cleanup)")
123+
_ = k8sClient.Get(ctx, client.ObjectKeyFromObject(argoCDCluster), argoCDCluster)
124+
argocdFixture.Update(argoCDCluster, func(ac *argov1beta1api.ArgoCD) {
125+
ac.Spec.ApplicationSet.Image = ""
126+
ac.Spec.Monitoring.Enabled = false
127+
})
128+
})
129+
130+
argocdFixture.Update(argoCDCluster, func(ac *argov1beta1api.ArgoCD) {
131+
ac.Spec.ApplicationSet = &argov1beta1api.ArgoCDApplicationSet{Image: invalidImage}
132+
ac.Spec.Monitoring = argov1beta1api.ArgoCDMonitoringSpec{Enabled: true}
133+
})
134+
135+
argoCDNamespaced := &argov1beta1api.ArgoCD{
136+
ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: nsNamespaced.Name},
137+
Spec: argov1beta1api.ArgoCDSpec{
138+
ApplicationSet: &argov1beta1api.ArgoCDApplicationSet{Image: invalidImage},
139+
Monitoring: argov1beta1api.ArgoCDMonitoringSpec{Enabled: true},
140+
},
141+
}
142+
Expect(k8sClient.Create(ctx, argoCDNamespaced)).To(Succeed())
143+
144+
By("waiting for the Argo CD instances to become available")
145+
Eventually(argoCDCluster, "5m").Should(argocdFixture.BeAvailable())
146+
Eventually(argoCDNamespaced, "5m").Should(argocdFixture.BeAvailable())
147+
148+
By("verifying PrometheusRules are created with the correct alerts")
149+
Eventually(ruleCluster, "3m", "5s").Should(k8sFixture.ExistByName(), "PrometheusRule should be created in cluster namespace")
150+
Eventually(ruleNamespaced, "3m", "5s").Should(k8sFixture.ExistByName(), "PrometheusRule should be created in test namespace")
151+
152+
By("verifying the ApplicationSet deployments are present")
153+
Eventually(appSetDeplCluster).Should(k8sFixture.ExistByName())
154+
Eventually(appSetDeplNamespaced).Should(k8sFixture.ExistByName())
155+
156+
By("verifying the workload degradation alerts are actively firing in Prometheus")
157+
Eventually(func() bool {
158+
cmd := exec.Command("oc", "exec", "-n", "openshift-monitoring", "prometheus-k8s-0", "-c", "prometheus", "--", "curl", "-s", "http://localhost:9090/api/v1/alerts")
159+
outBytes, err := cmd.Output()
160+
if err != nil {
161+
GinkgoWriter.Printf("Failed to query Prometheus: %v\n", err)
162+
return false
163+
}
164+
165+
// parse the json response
166+
type promResponse struct {
167+
Data struct {
168+
Alerts []struct {
169+
Labels map[string]string `json:"labels"`
170+
State string `json:"state"`
171+
} `json:"alerts"`
172+
} `json:"data"`
173+
}
174+
175+
var resp promResponse
176+
if err := json.Unmarshal(outBytes, &resp); err != nil {
177+
GinkgoWriter.Printf("Failed to unmarshal JSON: %v\n", err)
178+
return false
179+
}
180+
181+
hasDefaultAlert := false
182+
hasCustomAlert := false
183+
184+
for _, alert := range resp.Data.Alerts {
185+
if alert.Labels["alertname"] == "ApplicationSetControllerNotReady" && alert.State == "firing" {
186+
if alert.Labels["namespace"] == "openshift-gitops" {
187+
hasDefaultAlert = true
188+
}
189+
if alert.Labels["namespace"] == nsNamespaced.Name {
190+
hasCustomAlert = true
191+
}
192+
}
193+
}
194+
195+
return hasDefaultAlert && hasCustomAlert
196+
}, "15m", "30s").Should(BeTrue(), "Expected ApplicationSetControllerNotReady alerts to reach 'firing' state for both instances")
197+
198+
By("disabling monitoring and restoring the default images")
199+
Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(argoCDCluster), argoCDCluster)).To(Succeed())
200+
argocdFixture.Update(argoCDCluster, func(ac *argov1beta1api.ArgoCD) {
201+
ac.Spec.ApplicationSet.Image = ""
202+
ac.Spec.Monitoring.Enabled = false
203+
})
204+
205+
Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(argoCDNamespaced), argoCDNamespaced)).To(Succeed())
206+
argocdFixture.Update(argoCDNamespaced, func(ac *argov1beta1api.ArgoCD) {
207+
ac.Spec.ApplicationSet.Image = ""
208+
ac.Spec.Monitoring.Enabled = false
209+
})
210+
211+
By("verifying PrometheusRules are deleted")
212+
Eventually(ruleCluster, "5m").Should(k8sFixture.NotExistByName(), "Cluster PrometheusRule should be deleted")
213+
Eventually(ruleNamespaced, "5m").Should(k8sFixture.NotExistByName(), "Namespaced PrometheusRule should be deleted")
214+
})
215+
})
216+
})

0 commit comments

Comments
 (0)