Skip to content

Commit 603dc2c

Browse files
authored
argocd_application: introduce wait parameter (#54)
1 parent 9503821 commit 603dc2c

File tree

7 files changed

+120
-3
lines changed

7 files changed

+120
-3
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ For example if you use Docker as your local container runtime:
341341
docker pull argoproj/argocd:v1.8.3
342342
docker pull ghcr.io/dexidp/dex:v2.27.0
343343
docker pull redis:5.0.10-alpine
344+
docker pull banzaicloud/vault-operator:1.3.3
344345
```
345346

346347
#### Troubleshooting during local development

argocd/resource_argocd_application.go

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"fmt"
66
applicationClient "github.com/argoproj/argo-cd/pkg/apiclient/application"
77
application "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
8+
"github.com/argoproj/gitops-engine/pkg/health"
9+
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
810
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
911
"strings"
1012
"time"
@@ -23,6 +25,17 @@ func resourceArgoCDApplication() *schema.Resource {
2325
Schema: map[string]*schema.Schema{
2426
"metadata": metadataSchema("applications.argoproj.io"),
2527
"spec": applicationSpecSchema(),
28+
"wait": {
29+
Type: schema.TypeBool,
30+
Description: "Upon application creation or update, wait for application health/sync status to be healthy/Synced, upon application deletion, wait for application to be removed, when set to true.",
31+
Optional: true,
32+
Default: false,
33+
},
34+
},
35+
Timeouts: &schema.ResourceTimeout{
36+
Create: schema.DefaultTimeout(5 * time.Minute),
37+
Update: schema.DefaultTimeout(5 * time.Minute),
38+
Delete: schema.DefaultTimeout(5 * time.Minute),
2639
},
2740
}
2841
}
@@ -78,6 +91,23 @@ func resourceArgoCDApplicationCreate(d *schema.ResourceData, meta interface{}) e
7891
return fmt.Errorf("something went wrong during application creation")
7992
}
8093
d.SetId(app.Name)
94+
if wait, ok := d.GetOk("wait"); ok && wait.(bool) {
95+
return resource.Retry(d.Timeout(schema.TimeoutCreate), func() *resource.RetryError {
96+
a, err := c.Get(context.Background(), &applicationClient.ApplicationQuery{
97+
Name: &app.Name,
98+
})
99+
if err != nil {
100+
return resource.NonRetryableError(fmt.Errorf("error while waiting for application %s to be synced and healthy: %s", app.Name, err))
101+
}
102+
if a.Status.Health.Status != health.HealthStatusHealthy {
103+
return resource.RetryableError(fmt.Errorf("expected application health status to be healthy but was %s", a.Status.Health.Status))
104+
}
105+
if a.Status.Sync.Status != application.SyncStatusCodeSynced {
106+
return resource.RetryableError(fmt.Errorf("expected application sync status to be synced but was %s", a.Status.Sync.Status))
107+
}
108+
return resource.NonRetryableError(resourceArgoCDApplicationRead(d, meta))
109+
})
110+
}
81111
return resourceArgoCDApplicationRead(d, meta)
82112
}
83113

@@ -87,8 +117,7 @@ func resourceArgoCDApplicationRead(d *schema.ResourceData, meta interface{}) err
87117
appName := d.Id()
88118
app, err := c.Get(context.Background(), &applicationClient.ApplicationQuery{
89119
Name: &appName,
90-
},
91-
)
120+
})
92121
if err != nil {
93122
switch strings.Contains(err.Error(), "NotFound") {
94123
case true:
@@ -141,6 +170,23 @@ func resourceArgoCDApplicationUpdate(d *schema.ResourceData, meta interface{}) e
141170
if err != nil {
142171
return err
143172
}
173+
if wait, _ok := d.GetOk("wait"); _ok && wait.(bool) {
174+
return resource.Retry(d.Timeout(schema.TimeoutUpdate), func() *resource.RetryError {
175+
a, err := c.Get(context.Background(), &applicationClient.ApplicationQuery{
176+
Name: &app.Name,
177+
})
178+
if err != nil {
179+
return resource.NonRetryableError(fmt.Errorf("error while waiting for application %s to be synced and healthy: %s", app.Name, err))
180+
}
181+
if a.Status.Health.Status != health.HealthStatusHealthy {
182+
return resource.RetryableError(fmt.Errorf("expected application health status to be healthy but was %s", a.Status.Health.Status))
183+
}
184+
if a.Status.Sync.Status != application.SyncStatusCodeSynced {
185+
return resource.RetryableError(fmt.Errorf("expected application sync status to be synced but was %s", a.Status.Sync.Status))
186+
}
187+
return resource.NonRetryableError(resourceArgoCDApplicationRead(d, meta))
188+
})
189+
}
144190
}
145191
return resourceArgoCDApplicationRead(d, meta)
146192
}
@@ -153,6 +199,21 @@ func resourceArgoCDApplicationDelete(d *schema.ResourceData, meta interface{}) e
153199
if err != nil && !strings.Contains(err.Error(), "NotFound") {
154200
return err
155201
}
202+
if wait, ok := d.GetOk("wait"); ok && wait.(bool) {
203+
return resource.Retry(d.Timeout(schema.TimeoutDelete), func() *resource.RetryError {
204+
_, err = c.Get(context.Background(), &applicationClient.ApplicationQuery{
205+
Name: &appName,
206+
})
207+
if err == nil {
208+
return resource.RetryableError(fmt.Errorf("application %s is still present", appName))
209+
}
210+
if !strings.Contains(err.Error(), "NotFound") {
211+
return resource.NonRetryableError(err)
212+
}
213+
d.SetId("")
214+
return nil
215+
})
216+
}
156217
d.SetId("")
157218
return nil
158219
}

argocd/resource_argocd_application_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,15 @@ ingress:
5151
),
5252
),
5353
},
54+
{
55+
Config: testAccArgoCDApplicationSimpleWait(commonName),
56+
ExpectNonEmptyPlan: true,
57+
Check: resource.TestCheckResourceAttr(
58+
"argocd_application.simple",
59+
"wait",
60+
"true",
61+
),
62+
},
5463
{
5564
Config: testAccArgoCDApplicationHelm(
5665
acctest.RandomWithPrefix("test-acc"),
@@ -221,6 +230,48 @@ resource "argocd_application" "simple" {
221230
`, name)
222231
}
223232

233+
func testAccArgoCDApplicationSimpleWait(name string) string {
234+
return fmt.Sprintf(`
235+
resource "argocd_application" "simple" {
236+
metadata {
237+
name = "%s"
238+
namespace = "argocd"
239+
labels = {
240+
acceptance = "true"
241+
}
242+
annotations = {
243+
"this.is.a.really.long.nested.key" = "yes, really!"
244+
}
245+
}
246+
spec {
247+
source {
248+
repo_url = "https://kubernetes-charts.banzaicloud.com"
249+
chart = "vault-operator"
250+
target_revision = "1.3.3"
251+
helm {
252+
parameter {
253+
name = "image.tag"
254+
value = "1.3.3"
255+
}
256+
release_name = "testing"
257+
}
258+
}
259+
sync_policy {
260+
automated = {
261+
prune = true
262+
self_heal = true
263+
}
264+
}
265+
destination {
266+
server = "https://kubernetes.default.svc"
267+
namespace = "default"
268+
}
269+
}
270+
wait = true
271+
}
272+
`, name)
273+
}
274+
224275
func testAccArgoCDApplicationHelm(name, helmValues string) string {
225276
return fmt.Sprintf(`
226277
resource "argocd_application" "helm" {

argocd/schema_application.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,6 @@ func applicationSpecSchema() *schema.Schema {
313313
},
314314
"retry": {
315315
Type: schema.TypeList,
316-
MinItems: 1,
317316
MaxItems: 1,
318317
Optional: true,
319318
Elem: &schema.Resource{

docs/resources/application.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ resource "argocd_application" "helm" {
8282
}
8383
}
8484
85+
wait = true
86+
8587
spec {
8688
source {
8789
repo_url = "https://some.chart.repo.io"
@@ -120,6 +122,7 @@ EOT
120122

121123
* `metadata` - (Required) Standard Kubernetes API service's metadata. For more info see the [Kubernetes reference](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#metadata).
122124
* `spec` - (Required) The application specification, the nested attributes are documented below.
125+
* `wait` - (Optional) boolean, wait for application to be synced and healthy upon creation and updates, also waits for Kubernetes resources to be truly deleted upon deletion. Wait timeouts are controlled by Terraform Create, Update and Delete resource timeouts (all default to 5 minutes). Default is `false`.
123126

124127
The `metadata` block can have the following attributes:
125128

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.15
55
require (
66
github.com/Masterminds/semver v1.5.0
77
github.com/argoproj/argo-cd v1.8.3
8+
github.com/argoproj/gitops-engine v0.2.1
89
github.com/argoproj/pkg v0.2.0
910
github.com/cristalhq/jwt/v3 v3.0.8
1011
github.com/golang/protobuf v1.4.3

scripts/testacc_prepare_env.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ kubectl get services --all-namespaces -o wide
1717
echo '--- Load already available container images from local registry into Kind (local development only)'
1818
kind load docker-image redis:5.0.10-alpine --name argocd
1919
kind load docker-image ghcr.io/dexidp/dex:v2.27.0 --name argocd
20+
kind load docker-image banzaicloud/vault-operator:1.3.3 --name argocd
2021
kind load docker-image argoproj/argocd:${ARGOCD_VERSION:-v1.8.3} --name argocd
2122

2223
echo '--- Install ArgoCD ${ARGOCD_VERSION:-v1.8.3}\n\n'

0 commit comments

Comments
 (0)