@@ -91,7 +91,6 @@ g, admin, role:admin`
9191 MountPath : "/etc/pki/tls/certs" ,
9292 },
9393 }
94-
9594 initContainers := []v1.Container {
9695 {
9796 Name : "fetch-ca" ,
@@ -117,6 +116,114 @@ g, admin, role:admin`
117116 },
118117 },
119118 }
119+ resourceHealthChecks := []argooperator.ResourceHealthCheck {
120+ {
121+ // We can drop this custom Subscription healthcheck once https://www.github.com/argoproj/argo-cd/issues/25921 is fixed
122+ Group : "operators.coreos.com" ,
123+ Kind : "Subscription" ,
124+ Check : `local health_status = {}
125+ if obj.status ~= nil then
126+ if obj.status.conditions ~= nil then
127+ local numDegraded = 0
128+ local numPending = 0
129+ local msg = ""
130+
131+ -- Check if this is a manual approval scenario where InstallPlanPending is expected
132+ -- and the operator is already installed (upgrade pending, not initial install)
133+ local isManualApprovalPending = false
134+ if obj.spec ~= nil and obj.spec.installPlanApproval == "Manual" then
135+ for _, condition in pairs(obj.status.conditions) do
136+ if condition.type == "InstallPlanPending" and condition.status == "True" and condition.reason == "RequiresApproval" then
137+ -- Only treat as expected healthy state if the operator is already installed
138+ -- (installedCSV is present), meaning this is an upgrade pending approval
139+ if obj.status.installedCSV ~= nil then
140+ isManualApprovalPending = true
141+ end
142+ break
143+ end
144+ end
145+ end
146+
147+ for i, condition in pairs(obj.status.conditions) do
148+ -- Skip InstallPlanPending condition when manual approval is pending (expected behavior)
149+ if isManualApprovalPending and condition.type == "InstallPlanPending" then
150+ -- Do not include in message or count as pending
151+ else
152+ msg = msg .. i .. ": " .. condition.type .. " | " .. condition.status .. "\n"
153+ if condition.type == "InstallPlanPending" and condition.status == "True" then
154+ numPending = numPending + 1
155+ elseif (condition.type == "InstallPlanMissing" and condition.reason ~= "ReferencedInstallPlanNotFound") then
156+ numDegraded = numDegraded + 1
157+ elseif (condition.type == "CatalogSourcesUnhealthy" or condition.type == "InstallPlanFailed" or condition.type == "ResolutionFailed") and condition.status == "True" then
158+ numDegraded = numDegraded + 1
159+ end
160+ end
161+ end
162+
163+ -- Available states: undef/nil, UpgradeAvailable, UpgradePending, UpgradeFailed, AtLatestKnown
164+ -- Source: https://github.com/openshift/operator-framework-olm/blob/5e2c73b7663d0122c9dc3e59ea39e515a31e2719/staging/api/pkg/operators/v1alpha1/subscription_types.go#L17-L23
165+ if obj.status.state == nil then
166+ numPending = numPending + 1
167+ msg = msg .. ".status.state not yet known\n"
168+ elseif obj.status.state == "" or obj.status.state == "UpgradeAvailable" then
169+ numPending = numPending + 1
170+ msg = msg .. ".status.state is '" .. obj.status.state .. "'\n"
171+ elseif obj.status.state == "UpgradePending" then
172+ -- UpgradePending with manual approval is expected behavior, treat as healthy
173+ if isManualApprovalPending then
174+ msg = msg .. ".status.state is 'AtLatestKnown'\n"
175+ else
176+ numPending = numPending + 1
177+ msg = msg .. ".status.state is '" .. obj.status.state .. "'\n"
178+ end
179+ elseif obj.status.state == "UpgradeFailed" then
180+ numDegraded = numDegraded + 1
181+ msg = msg .. ".status.state is '" .. obj.status.state .. "'\n"
182+ else
183+ -- Last possiblity of .status.state: AtLatestKnown
184+ msg = msg .. ".status.state is '" .. obj.status.state .. "'\n"
185+ end
186+
187+ if numDegraded == 0 and numPending == 0 then
188+ health_status.status = "Healthy"
189+ health_status.message = msg
190+ return health_status
191+ elseif numPending > 0 and numDegraded == 0 then
192+ health_status.status = "Progressing"
193+ health_status.message = msg
194+ return health_status
195+ else
196+ health_status.status = "Degraded"
197+ health_status.message = msg
198+ return health_status
199+ end
200+ end
201+ end
202+ health_status.status = "Progressing"
203+ health_status.message = "An install plan for a subscription is pending installation"
204+ return health_status` ,
205+ },
206+ }
207+ if strings .EqualFold (PatternsOperatorConfig .getValueWithDefault ("gitops.applicationHealthCheckEnabled" ), "true" ) {
208+ // As of ArgoCD 1.8 the Application health check was dropped (see https://github.com/argoproj/argo-cd/issues/3781),
209+ // but in app-of-apps pattern this is needed in order to implement children apps dependencies via sync-waves
210+ resourceHealthChecks = append (resourceHealthChecks , argooperator.ResourceHealthCheck {
211+ Group : "argoproj.io" ,
212+ Kind : "Application" ,
213+ Check : `local health_status = {}
214+ health_status.status = "Progressing"
215+ health_status.message = ""
216+ if obj.status ~= nil then
217+ if obj.status.health ~= nil then
218+ health_status.status = obj.status.health.status
219+ if obj.status.health.message ~= nil then
220+ health_status.message = obj.status.health.message
221+ end
222+ end
223+ end
224+ return health_status` ,
225+ })
226+ }
120227
121228 s := argooperator.ArgoCD {
122229 TypeMeta : metav1.TypeMeta {
@@ -247,94 +354,7 @@ g, admin, role:admin`
247354 kinds:
248355 - TaskRun
249356 - PipelineRun` ,
250- // We can drop this custom Subscription healthcheck once https://www.github.com/argoproj/argo-cd/issues/25921 is fixed
251- ResourceHealthChecks : []argooperator.ResourceHealthCheck {
252- {
253- Group : "operators.coreos.com" ,
254- Kind : "Subscription" ,
255- Check : `local health_status = {}
256- if obj.status ~= nil then
257- if obj.status.conditions ~= nil then
258- local numDegraded = 0
259- local numPending = 0
260- local msg = ""
261-
262- -- Check if this is a manual approval scenario where InstallPlanPending is expected
263- -- and the operator is already installed (upgrade pending, not initial install)
264- local isManualApprovalPending = false
265- if obj.spec ~= nil and obj.spec.installPlanApproval == "Manual" then
266- for _, condition in pairs(obj.status.conditions) do
267- if condition.type == "InstallPlanPending" and condition.status == "True" and condition.reason == "RequiresApproval" then
268- -- Only treat as expected healthy state if the operator is already installed
269- -- (installedCSV is present), meaning this is an upgrade pending approval
270- if obj.status.installedCSV ~= nil then
271- isManualApprovalPending = true
272- end
273- break
274- end
275- end
276- end
277-
278- for i, condition in pairs(obj.status.conditions) do
279- -- Skip InstallPlanPending condition when manual approval is pending (expected behavior)
280- if isManualApprovalPending and condition.type == "InstallPlanPending" then
281- -- Do not include in message or count as pending
282- else
283- msg = msg .. i .. ": " .. condition.type .. " | " .. condition.status .. "\n"
284- if condition.type == "InstallPlanPending" and condition.status == "True" then
285- numPending = numPending + 1
286- elseif (condition.type == "InstallPlanMissing" and condition.reason ~= "ReferencedInstallPlanNotFound") then
287- numDegraded = numDegraded + 1
288- elseif (condition.type == "CatalogSourcesUnhealthy" or condition.type == "InstallPlanFailed" or condition.type == "ResolutionFailed") and condition.status == "True" then
289- numDegraded = numDegraded + 1
290- end
291- end
292- end
293-
294- -- Available states: undef/nil, UpgradeAvailable, UpgradePending, UpgradeFailed, AtLatestKnown
295- -- Source: https://github.com/openshift/operator-framework-olm/blob/5e2c73b7663d0122c9dc3e59ea39e515a31e2719/staging/api/pkg/operators/v1alpha1/subscription_types.go#L17-L23
296- if obj.status.state == nil then
297- numPending = numPending + 1
298- msg = msg .. ".status.state not yet known\n"
299- elseif obj.status.state == "" or obj.status.state == "UpgradeAvailable" then
300- numPending = numPending + 1
301- msg = msg .. ".status.state is '" .. obj.status.state .. "'\n"
302- elseif obj.status.state == "UpgradePending" then
303- -- UpgradePending with manual approval is expected behavior, treat as healthy
304- if isManualApprovalPending then
305- msg = msg .. ".status.state is 'AtLatestKnown'\n"
306- else
307- numPending = numPending + 1
308- msg = msg .. ".status.state is '" .. obj.status.state .. "'\n"
309- end
310- elseif obj.status.state == "UpgradeFailed" then
311- numDegraded = numDegraded + 1
312- msg = msg .. ".status.state is '" .. obj.status.state .. "'\n"
313- else
314- -- Last possiblity of .status.state: AtLatestKnown
315- msg = msg .. ".status.state is '" .. obj.status.state .. "'\n"
316- end
317-
318- if numDegraded == 0 and numPending == 0 then
319- health_status.status = "Healthy"
320- health_status.message = msg
321- return health_status
322- elseif numPending > 0 and numDegraded == 0 then
323- health_status.status = "Progressing"
324- health_status.message = msg
325- return health_status
326- else
327- health_status.status = "Degraded"
328- health_status.message = msg
329- return health_status
330- end
331- end
332- end
333- health_status.status = "Progressing"
334- health_status.message = "An install plan for a subscription is pending installation"
335- return health_status` ,
336- },
337- },
357+ ResourceHealthChecks : resourceHealthChecks ,
338358 ResourceTrackingMethod : "annotation" ,
339359 Server : argooperator.ArgoCDServerSpec {
340360 Autoscale : argooperator.ArgoCDServerAutoscaleSpec {
0 commit comments