Skip to content

Commit 46eca8d

Browse files
authored
feat(argo-helm): add status wait support (#15)
1 parent 9814d71 commit 46eca8d

File tree

5 files changed

+194
-31
lines changed

5 files changed

+194
-31
lines changed

Diff for: README.md

+8
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,12 @@ No modules.
104104
| [helm_release.default_cluster_issuer](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource |
105105
| [helm_release.default_cluster_issuer_argo_application](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource |
106106
| [helm_release.this](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource |
107+
| [kubernetes_job.helm_argo_application_wait](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/job) | resource |
107108
| [kubernetes_manifest.default_cluster_issuer_argo_application](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource |
108109
| [kubernetes_manifest.this](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource |
110+
| [kubernetes_role.helm_argo_application_wait](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/role) | resource |
111+
| [kubernetes_role_binding.helm_argo_application_wait](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/role_binding) | resource |
112+
| [kubernetes_service_account.helm_argo_application_wait](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/service_account) | resource |
109113
| [aws_iam_policy_document.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
110114
| [aws_iam_policy_document.this_irsa](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
111115
| [utils_deep_merge_yaml.argo_helm_values](https://registry.terraform.io/providers/cloudposse/utils/latest/docs/data-sources/deep_merge_yaml) | data source |
@@ -123,6 +127,10 @@ No modules.
123127
| <a name="input_argo_enabled"></a> [argo\_enabled](#input\_argo\_enabled) | If set to true, the module will be deployed as ArgoCD application, otherwise it will be deployed as a Helm release | `bool` | `false` | no |
124128
| <a name="input_argo_helm_enabled"></a> [argo\_helm\_enabled](#input\_argo\_helm\_enabled) | If set to true, the ArgoCD Application manifest will be deployed using Kubernetes provider as a Helm release. Otherwise it'll be deployed as a Kubernetes manifest. See Readme for more info | `bool` | `false` | no |
125129
| <a name="input_argo_helm_values"></a> [argo\_helm\_values](#input\_argo\_helm\_values) | Value overrides to use when deploying argo application object with helm | `string` | `""` | no |
130+
| <a name="input_argo_helm_wait_backoff_limit"></a> [argo\_helm\_wait\_backoff\_limit](#input\_argo\_helm\_wait\_backoff\_limit) | Backoff limit for ArgoCD Application Helm release wait job | `number` | `6` | no |
131+
| <a name="input_argo_helm_wait_node_selector"></a> [argo\_helm\_wait\_node\_selector](#input\_argo\_helm\_wait\_node\_selector) | Node selector for ArgoCD Application Helm release wait job | `map(string)` | `{}` | no |
132+
| <a name="input_argo_helm_wait_timeout"></a> [argo\_helm\_wait\_timeout](#input\_argo\_helm\_wait\_timeout) | Timeout for ArgoCD Application Helm release wait job | `string` | `"10m"` | no |
133+
| <a name="input_argo_helm_wait_tolerations"></a> [argo\_helm\_wait\_tolerations](#input\_argo\_helm\_wait\_tolerations) | Tolerations for ArgoCD Application Helm release wait job | `list(any)` | `[]` | no |
126134
| <a name="input_argo_info"></a> [argo\_info](#input\_argo\_info) | ArgoCD info manifest parameter | <pre>list(object({<br> name = string<br> value = string<br> }))</pre> | <pre>[<br> {<br> "name": "terraform",<br> "value": "true"<br> }<br>]</pre> | no |
127135
| <a name="input_argo_kubernetes_manifest_computed_fields"></a> [argo\_kubernetes\_manifest\_computed\_fields](#input\_argo\_kubernetes\_manifest\_computed\_fields) | List of paths of fields to be handled as "computed". The user-configured value for the field will be overridden by any different value returned by the API after apply. | `list(string)` | <pre>[<br> "metadata.labels",<br> "metadata.annotations"<br>]</pre> | no |
128136
| <a name="input_argo_kubernetes_manifest_field_manager_force_conflicts"></a> [argo\_kubernetes\_manifest\_field\_manager\_force\_conflicts](#input\_argo\_kubernetes\_manifest\_field\_manager\_force\_conflicts) | Forcibly override any field manager conflicts when applying the kubernetes manifest resource | `bool` | `false` | no |

Diff for: argo-helm.tf

+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
locals {
2+
helm_argo_application_enabled = var.enabled && var.argo_enabled && var.argo_helm_enabled
3+
helm_argo_application_wait_enabled = local.helm_argo_application_enabled && length(keys(var.argo_kubernetes_manifest_wait_fields)) > 0
4+
helm_argo_application_values = [
5+
one(data.utils_deep_merge_yaml.argo_helm_values[*].output),
6+
var.argo_helm_values
7+
]
8+
}
9+
10+
data "utils_deep_merge_yaml" "argo_helm_values" {
11+
count = local.helm_argo_application_enabled ? 1 : 0
12+
13+
input = compact([
14+
yamlencode({
15+
"apiVersion" : var.argo_apiversion
16+
}),
17+
yamlencode({
18+
"spec" : local.argo_application_values
19+
}),
20+
yamlencode({
21+
"spec" : var.argo_spec
22+
}),
23+
yamlencode(
24+
local.argo_application_metadata
25+
)
26+
])
27+
}
28+
29+
resource "helm_release" "argo_application" {
30+
count = local.helm_argo_application_enabled ? 1 : 0
31+
32+
chart = "${path.module}/helm/argocd-application"
33+
name = var.helm_release_name
34+
namespace = var.argo_namespace
35+
36+
values = local.helm_argo_application_values
37+
}
38+
39+
resource "kubernetes_role" "helm_argo_application_wait" {
40+
count = local.helm_argo_application_wait_enabled ? 1 : 0
41+
42+
metadata {
43+
name = "${var.helm_release_name}-argo-application-wait"
44+
namespace = var.argo_namespace
45+
labels = local.argo_application_metadata.labels
46+
annotations = local.argo_application_metadata.annotations
47+
}
48+
49+
rule {
50+
api_groups = ["argoproj.io"]
51+
resources = ["applications"]
52+
verbs = ["get", "list", "watch"]
53+
}
54+
}
55+
56+
resource "kubernetes_role_binding" "helm_argo_application_wait" {
57+
count = local.helm_argo_application_wait_enabled ? 1 : 0
58+
59+
metadata {
60+
name = "${var.helm_release_name}-argo-application-wait"
61+
namespace = var.argo_namespace
62+
labels = local.argo_application_metadata.labels
63+
annotations = local.argo_application_metadata.annotations
64+
}
65+
66+
role_ref {
67+
api_group = "rbac.authorization.k8s.io"
68+
kind = "Role"
69+
name = one(kubernetes_role.helm_argo_application_wait[*].metadata[0].name)
70+
}
71+
72+
subject {
73+
kind = "ServiceAccount"
74+
name = one(kubernetes_service_account.helm_argo_application_wait[*].metadata[0].name)
75+
namespace = one(kubernetes_service_account.helm_argo_application_wait[*].metadata[0].namespace)
76+
}
77+
}
78+
79+
resource "kubernetes_service_account" "helm_argo_application_wait" {
80+
count = local.helm_argo_application_wait_enabled ? 1 : 0
81+
82+
metadata {
83+
name = "${var.helm_release_name}-argo-application-wait"
84+
namespace = var.argo_namespace
85+
labels = local.argo_application_metadata.labels
86+
annotations = local.argo_application_metadata.annotations
87+
}
88+
}
89+
90+
resource "kubernetes_job" "helm_argo_application_wait" {
91+
count = local.helm_argo_application_wait_enabled ? 1 : 0
92+
93+
metadata {
94+
generate_name = "${var.helm_release_name}-argo-application-wait-"
95+
namespace = var.argo_namespace
96+
labels = local.argo_application_metadata.labels
97+
annotations = local.argo_application_metadata.annotations
98+
}
99+
100+
spec {
101+
template {
102+
metadata {
103+
labels = local.argo_application_metadata.labels
104+
annotations = local.argo_application_metadata.annotations
105+
}
106+
107+
spec {
108+
service_account_name = one(kubernetes_service_account.helm_argo_application_wait[*].metadata[0].name)
109+
110+
dynamic "container" {
111+
for_each = var.argo_kubernetes_manifest_wait_fields
112+
113+
content {
114+
name = "${lower(replace(container.key, ".", "-"))}-${md5(jsonencode(local.helm_argo_application_values))}" # md5 suffix is a workaround for https://github.com/hashicorp/terraform-provider-kubernetes/issues/1325
115+
image = "bitnami/kubectl:latest"
116+
command = ["/bin/bash", "-ecx"]
117+
# Waits for ArgoCD Application to be "Healthy", see https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#wait
118+
# i.e. kubectl wait --for=jsonpath='{.status.sync.status}'=Healthy application.argoproj.io <$addon-name>
119+
args = [
120+
<<-EOT
121+
kubectl wait \
122+
--namespace ${var.argo_namespace} \
123+
--for=jsonpath='{.${container.key}}'=${container.value} \
124+
--timeout=${var.argo_helm_wait_timeout} \
125+
application.argoproj.io ${var.helm_release_name}
126+
EOT
127+
]
128+
}
129+
}
130+
131+
node_selector = var.argo_helm_wait_node_selector
132+
133+
dynamic "toleration" {
134+
for_each = var.argo_helm_wait_tolerations
135+
136+
content {
137+
key = try(toleration.value.key, null)
138+
operator = try(toleration.value.operator, null)
139+
value = try(toleration.value.value, null)
140+
effect = try(toleration.value.effect, null)
141+
}
142+
}
143+
144+
# ArgoCD Application status fields might not be available immediately after creation
145+
restart_policy = "OnFailure"
146+
}
147+
}
148+
149+
backoff_limit = var.argo_helm_wait_backoff_limit
150+
}
151+
152+
wait_for_completion = true
153+
154+
timeouts {
155+
create = var.argo_helm_wait_timeout
156+
update = var.argo_helm_wait_timeout
157+
}
158+
159+
depends_on = [
160+
helm_release.argo_application
161+
]
162+
}

Diff for: argo.tf

-31
Original file line numberDiff line numberDiff line change
@@ -25,37 +25,6 @@ locals {
2525
}
2626
}
2727

28-
data "utils_deep_merge_yaml" "argo_helm_values" {
29-
count = var.enabled && var.argo_enabled && var.argo_helm_enabled ? 1 : 0
30-
input = compact([
31-
yamlencode({
32-
"apiVersion" : var.argo_apiversion
33-
}),
34-
yamlencode({
35-
"spec" : local.argo_application_values
36-
}),
37-
yamlencode({
38-
"spec" : var.argo_spec
39-
}),
40-
yamlencode(
41-
local.argo_application_metadata
42-
)
43-
])
44-
}
45-
46-
resource "helm_release" "argo_application" {
47-
count = var.enabled && var.argo_enabled && var.argo_helm_enabled ? 1 : 0
48-
49-
chart = "${path.module}/helm/argocd-application"
50-
name = var.helm_release_name
51-
namespace = var.argo_namespace
52-
53-
values = [
54-
data.utils_deep_merge_yaml.argo_helm_values[0].output,
55-
var.argo_helm_values
56-
]
57-
}
58-
5928
resource "kubernetes_manifest" "this" {
6029
count = var.enabled && var.argo_enabled && !var.argo_helm_enabled ? 1 : 0
6130
manifest = {
File renamed without changes.

Diff for: variables.tf

+24
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,30 @@ variable "argo_helm_enabled" {
164164
description = "If set to true, the ArgoCD Application manifest will be deployed using Kubernetes provider as a Helm release. Otherwise it'll be deployed as a Kubernetes manifest. See Readme for more info"
165165
}
166166

167+
variable "argo_helm_wait_timeout" {
168+
type = string
169+
default = "10m"
170+
description = "Timeout for ArgoCD Application Helm release wait job"
171+
}
172+
173+
variable "argo_helm_wait_node_selector" {
174+
type = map(string)
175+
default = {}
176+
description = "Node selector for ArgoCD Application Helm release wait job"
177+
}
178+
179+
variable "argo_helm_wait_tolerations" {
180+
type = list(any)
181+
default = []
182+
description = "Tolerations for ArgoCD Application Helm release wait job"
183+
}
184+
185+
variable "argo_helm_wait_backoff_limit" {
186+
type = number
187+
default = 6
188+
description = "Backoff limit for ArgoCD Application Helm release wait job"
189+
}
190+
167191
variable "argo_destination_server" {
168192
type = string
169193
default = "https://kubernetes.default.svc"

0 commit comments

Comments
 (0)