Skip to content

Commit 36f1a59

Browse files
authored
feat(health): add health checks for GitOps Promoter (#23663)
Signed-off-by: Michael Crenshaw <[email protected]>
1 parent d5383de commit 36f1a59

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1138
-1
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
local hs = {}
2+
hs.status = "Progressing"
3+
hs.message = "Initializing Argo CD commit status"
4+
5+
-- Check for deletion timestamp
6+
if obj.metadata.deletionTimestamp then
7+
hs.status = "Progressing"
8+
hs.message = "Argo CD commit status is being deleted"
9+
return hs
10+
end
11+
12+
-- Check if status exists
13+
if not obj.status then
14+
return hs
15+
end
16+
17+
-- Check for reconciliation conditions
18+
local hasReadyCondition = false
19+
if obj.status.conditions then
20+
for _, condition in ipairs(obj.status.conditions) do
21+
if condition.type == "Ready" then
22+
hasReadyCondition = true
23+
if condition.observedGeneration and obj.metadata.generation and condition.observedGeneration ~= obj.metadata.generation then
24+
hs.status = "Progressing"
25+
hs.message = "Waiting for Argo CD commit status spec update to be observed"
26+
return hs
27+
end
28+
if condition.status == "False" and condition.reason == "ReconciliationError" then
29+
hs.status = "Degraded"
30+
hs.message = "Argo CD commit status reconciliation failed: " .. (condition.message or "Unknown error")
31+
return hs
32+
end
33+
end
34+
end
35+
end
36+
if not hasReadyCondition then
37+
hs.status = "Progressing"
38+
hs.message = "Argo CD commit status is not ready yet"
39+
return hs
40+
end
41+
42+
if not obj.status.applicationsSelected or #obj.status.applicationsSelected == 0 then
43+
hs.status = "Degraded"
44+
hs.message = "Argo CD commit status has no applications configured"
45+
return hs
46+
end
47+
48+
hs.status = "Healthy"
49+
hs.message = "Argo CD commit status is healthy and is tracking " .. #obj.status.applicationsSelected .. " applications"
50+
return hs
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
tests:
2+
- healthStatus:
3+
status: Progressing
4+
message: Initializing Argo CD commit status
5+
inputPath: testdata/no-status.yaml
6+
- healthStatus:
7+
status: Progressing
8+
message: Argo CD commit status is being deleted
9+
inputPath: testdata/deleting.yaml
10+
- healthStatus:
11+
status: Progressing
12+
message: Waiting for Argo CD commit status spec update to be observed
13+
inputPath: testdata/observed-generation-outdated.yaml
14+
- healthStatus:
15+
status: Degraded
16+
message: "Argo CD commit status reconciliation failed: Something went wrong"
17+
inputPath: testdata/reconcile-error.yaml
18+
- healthStatus:
19+
status: Progressing
20+
message: Argo CD commit status is not ready yet
21+
inputPath: testdata/no-ready-condition.yaml
22+
- healthStatus:
23+
status: Degraded
24+
message: Argo CD commit status has no applications configured
25+
inputPath: testdata/no-applications.yaml
26+
- healthStatus:
27+
status: Healthy
28+
message: Argo CD commit status is healthy and is tracking 2 applications
29+
inputPath: testdata/all-healthy.yaml
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
apiVersion: promoter.argoproj.io/v1alpha1
2+
kind: ArgoCDCommitStatus
3+
metadata:
4+
name: test
5+
generation: 2
6+
status:
7+
conditions:
8+
- type: Ready
9+
status: True
10+
observedGeneration: 2
11+
applicationsSelected:
12+
- name: app1
13+
namespace: default
14+
phase: success
15+
sha: abc1234
16+
- name: app2
17+
namespace: default
18+
phase: success
19+
sha: def5678
20+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
apiVersion: promoter.argoproj.io/v1alpha1
2+
kind: ArgoCDCommitStatus
3+
metadata:
4+
name: test
5+
deletionTimestamp: "2025-07-04T12:00:00Z"
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
apiVersion: promoter.argoproj.io/v1alpha1
2+
kind: ArgoCDCommitStatus
3+
metadata:
4+
name: test
5+
generation: 2
6+
status:
7+
conditions:
8+
- type: Ready
9+
status: True
10+
observedGeneration: 2
11+
applicationsSelected: []
12+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
apiVersion: promoter.argoproj.io/v1alpha1
2+
kind: ArgoCDCommitStatus
3+
metadata:
4+
name: test
5+
generation: 2
6+
status:
7+
conditions:
8+
- type: SomeOtherCondition
9+
status: True
10+
observedGeneration: 2
11+
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
apiVersion: promoter.argoproj.io/v1alpha1
2+
kind: ArgoCDCommitStatus
3+
metadata:
4+
name: test
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
apiVersion: promoter.argoproj.io/v1alpha1
2+
kind: ArgoCDCommitStatus
3+
metadata:
4+
name: test
5+
generation: 2
6+
status:
7+
conditions:
8+
- type: Ready
9+
status: True
10+
observedGeneration: 1
11+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
apiVersion: promoter.argoproj.io/v1alpha1
2+
kind: ArgoCDCommitStatus
3+
metadata:
4+
name: test
5+
generation: 2
6+
status:
7+
conditions:
8+
- type: Ready
9+
status: "False"
10+
reason: ReconciliationError
11+
message: Something went wrong
12+
observedGeneration: 2
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
local hs = {}
2+
hs.status = "Progressing"
3+
hs.message = "Initializing change transfer policy"
4+
5+
-- Check for deletion timestamp
6+
if obj.metadata.deletionTimestamp then
7+
hs.status = "Progressing"
8+
hs.message = "Change transfer policy is being deleted"
9+
return hs
10+
end
11+
12+
-- Check if status exists
13+
if not obj.status then
14+
return hs
15+
end
16+
17+
-- Check for reconciliation conditions
18+
local hasReadyCondition = false
19+
if obj.status.conditions then
20+
for _, condition in ipairs(obj.status.conditions) do
21+
if condition.type == "Ready" then
22+
hasReadyCondition = true
23+
-- Check observedGeneration vs metadata.generation within the reconciliation condition
24+
if condition.observedGeneration and obj.metadata.generation and condition.observedGeneration ~= obj.metadata.generation then
25+
hs.status = "Progressing"
26+
hs.message = "Waiting for change transfer policy spec update to be observed"
27+
return hs
28+
end
29+
if condition.status == "False" and condition.reason == "ReconciliationError" then
30+
hs.status = "Degraded"
31+
hs.message = "Change transfer policy reconciliation failed: " .. (condition.message or "Unknown error")
32+
return hs
33+
end
34+
end
35+
end
36+
end
37+
if not hasReadyCondition then
38+
hs.status = "Progressing"
39+
hs.message = "Change transfer policy is not ready yet"
40+
return hs
41+
end
42+
43+
if not obj.status.active or not obj.status.active.dry or not obj.status.active.dry.sha or obj.status.active.dry.sha == "" then
44+
hs.status = "Progressing"
45+
hs.message = "The active commit DRY SHA is missing or empty."
46+
return hs
47+
end
48+
if not obj.status.proposed or not obj.status.proposed.dry or not obj.status.proposed.dry.sha or obj.status.proposed.dry.sha == "" then
49+
hs.status = "Progressing"
50+
hs.message = "The proposed commit DRY SHA is missing or empty."
51+
return hs
52+
end
53+
54+
-- Helper function to get short SHA
55+
local function getShortSha(sha)
56+
if not sha or sha == "" then
57+
return ""
58+
end
59+
if string.len(sha) > 7 then
60+
return string.sub(sha, 1, 7)
61+
end
62+
return sha
63+
end
64+
65+
if obj.status.proposed.dry.sha ~= obj.status.active.dry.sha then
66+
local pendingCount = 0
67+
local successCount = 0
68+
local failureCount = 0
69+
local pendingKeys = {}
70+
local failedKeys = {}
71+
72+
for _, status in ipairs(obj.status.proposed.commitStatuses or {}) do
73+
if status.phase == "pending" then
74+
pendingCount = pendingCount + 1
75+
table.insert(pendingKeys, status.key)
76+
elseif status.phase == "success" then
77+
successCount = successCount + 1
78+
elseif status.phase == "failure" then
79+
failureCount = failureCount + 1
80+
table.insert(failedKeys, status.key)
81+
end
82+
end
83+
84+
hs.status = "Progressing"
85+
hs.message =
86+
"Promotion in progress from '" .. getShortSha(obj.status.active.dry.sha) ..
87+
"' to '" .. getShortSha(obj.status.proposed.dry.sha) .. "': " ..
88+
pendingCount .. " pending, " .. successCount .. " successful, " .. failureCount .. " failed. "
89+
90+
if pendingCount > 0 then
91+
hs.message = hs.message .. "Pending commit statuses: " .. table.concat(pendingKeys, ", ") .. ". "
92+
end
93+
if failureCount > 0 then
94+
hs.message = hs.message .. "Failed commit statuses: " .. table.concat(failedKeys, ", ") .. ". "
95+
end
96+
return hs
97+
end
98+
99+
local pendingCount = 0
100+
local failureCount = 0
101+
for _, status in ipairs(obj.status.active.commitStatuses or {}) do
102+
if status.phase == "pending" then
103+
pendingCount = pendingCount + 1
104+
elseif status.phase == "failure" then
105+
failureCount = failureCount + 1
106+
end
107+
end
108+
if pendingCount > 0 or failureCount > 0 then
109+
local envMessages = {}
110+
for branch, counts in pairs(nonSuccessfulEnvironments) do
111+
local msg = branch .. " (" .. counts.failure .. " failed, " .. counts.pending .. " pending)"
112+
table.insert(envMessages, msg)
113+
end
114+
hs.status = "Healthy"
115+
hs.message = "Environment is up-to-date, but there are non-successful commit statuses: " .. table.concat(envMessages, ", ") .. "."
116+
return hs
117+
end
118+
119+
hs.status = "Healthy"
120+
hs.message = "Environment is up-to-date on commit " .. getShortSha(obj.status.active.dry.sha) .. "."
121+
return hs

0 commit comments

Comments
 (0)