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