Skip to content

Commit ce561fa

Browse files
authored
feat(argocd_application): add support for managed namespace metadata (#299)
1 parent a6b8f70 commit ce561fa

File tree

7 files changed

+653
-40
lines changed

7 files changed

+653
-40
lines changed

argocd/resource_argocd_application.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ func resourceArgoCDApplicationCreate(ctx context.Context, d *schema.ResourceData
126126
return featureNotSupported(features.MultipleApplicationSources)
127127
}
128128

129+
if spec.SyncPolicy != nil && spec.SyncPolicy.ManagedNamespaceMetadata != nil && !si.isFeatureSupported(features.ManagedNamespaceMetadata) {
130+
return featureNotSupported(features.ManagedNamespaceMetadata)
131+
}
132+
129133
app, err := si.ApplicationClient.Create(ctx, &applicationClient.ApplicationCreateRequest{
130134
Application: &application.Application{
131135
ObjectMeta: objectMeta,
@@ -259,6 +263,10 @@ func resourceArgoCDApplicationUpdate(ctx context.Context, d *schema.ResourceData
259263
return featureNotSupported(features.MultipleApplicationSources)
260264
}
261265

266+
if spec.SyncPolicy != nil && spec.SyncPolicy.ManagedNamespaceMetadata != nil && !si.isFeatureSupported(features.ManagedNamespaceMetadata) {
267+
return featureNotSupported(features.ManagedNamespaceMetadata)
268+
}
269+
262270
apps, err := si.ApplicationClient.List(ctx, appQuery)
263271
if err != nil {
264272
return []diag.Diagnostic{

argocd/resource_argocd_application_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,6 +1015,29 @@ func TestAccArgoCDApplication_HelmValuesFromExternalGitRepo(t *testing.T) {
10151015
})
10161016
}
10171017

1018+
func TestAccArgoCDApplication_ManagedNamespaceMetadata(t *testing.T) {
1019+
resource.ParallelTest(t, resource.TestCase{
1020+
PreCheck: func() { testAccPreCheck(t); testAccPreCheckFeatureSupported(t, features.ManagedNamespaceMetadata) },
1021+
ProviderFactories: testAccProviders,
1022+
Steps: []resource.TestStep{
1023+
{
1024+
Config: testAccArgoCDApplication_ManagedNamespaceMetadata(),
1025+
Check: resource.ComposeTestCheckFunc(
1026+
resource.TestCheckResourceAttrSet("argocd_application.namespace_metadata", "metadata.0.uid"),
1027+
resource.TestCheckResourceAttrSet("argocd_application.namespace_metadata", "spec.0.sync_policy.0.managed_namespace_metadata.0.annotations.%"),
1028+
resource.TestCheckResourceAttrSet("argocd_application.namespace_metadata", "spec.0.sync_policy.0.managed_namespace_metadata.0.labels.%"),
1029+
),
1030+
},
1031+
{
1032+
ResourceName: "argocd_application.namespace_metadata",
1033+
ImportState: true,
1034+
ImportStateVerify: true,
1035+
ImportStateVerifyIgnore: []string{"wait", "cascade", "metadata.0.generation", "metadata.0.resource_version"},
1036+
},
1037+
},
1038+
})
1039+
}
1040+
10181041
func TestAccArgoCDApplication_Wait(t *testing.T) {
10191042
chartRevision := "9.4.1"
10201043
name := acctest.RandomWithPrefix("test-acc")
@@ -2075,6 +2098,43 @@ resource "argocd_application" "multiple_sources" {
20752098
}`
20762099
}
20772100

2101+
func testAccArgoCDApplication_ManagedNamespaceMetadata() string {
2102+
return `
2103+
resource "argocd_application" "namespace_metadata" {
2104+
metadata {
2105+
name = "namespace-metadata"
2106+
namespace = "argocd"
2107+
}
2108+
2109+
spec {
2110+
project = "default"
2111+
2112+
source {
2113+
repo_url = "https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami"
2114+
chart = "apache"
2115+
target_revision = "9.4.1"
2116+
}
2117+
2118+
destination {
2119+
server = "https://kubernetes.default.svc"
2120+
namespace = "managed-namespace"
2121+
}
2122+
2123+
sync_policy {
2124+
managed_namespace_metadata {
2125+
annotations = {
2126+
"this.is.a.really.long.nested.key" = "yes, really!"
2127+
}
2128+
labels = {
2129+
foo = "bar"
2130+
}
2131+
}
2132+
sync_options = ["CreateNamespace=true"]
2133+
}
2134+
}
2135+
}`
2136+
}
2137+
20782138
func testAccArgoCDApplicationHelmValuesFromExternalGitRepo() string {
20792139
return `
20802140
resource "argocd_application" "helm_values_external" {

argocd/schema_application.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,6 +1674,30 @@ func applicationSpecSchemaV4(allOptional bool) *schema.Schema {
16741674
},
16751675
},
16761676
},
1677+
"managed_namespace_metadata": {
1678+
Type: schema.TypeList,
1679+
MaxItems: 1,
1680+
Description: "Controls metadata in the given namespace (if `CreateNamespace=true`).",
1681+
Optional: true,
1682+
Elem: &schema.Resource{
1683+
Schema: map[string]*schema.Schema{
1684+
"annotations": {
1685+
Type: schema.TypeMap,
1686+
Description: "Annotations to apply to the namespace.",
1687+
Optional: true,
1688+
Elem: &schema.Schema{Type: schema.TypeString},
1689+
ValidateFunc: validateMetadataAnnotations,
1690+
},
1691+
"labels": {
1692+
Type: schema.TypeMap,
1693+
Description: "Labels to apply to the namespace.",
1694+
Optional: true,
1695+
Elem: &schema.Schema{Type: schema.TypeString},
1696+
ValidateFunc: validateMetadataLabels,
1697+
},
1698+
},
1699+
},
1700+
},
16771701
},
16781702
},
16791703
},

argocd/structure_application.go

Lines changed: 59 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -315,13 +315,15 @@ func expandApplicationSourceHelm(in []interface{}) *application.ApplicationSourc
315315
}
316316

317317
func expandApplicationSyncPolicy(sp interface{}) (*application.SyncPolicy, error) {
318+
var syncPolicy = &application.SyncPolicy{}
319+
318320
if sp == nil {
319-
return &application.SyncPolicy{}, nil
321+
return syncPolicy, nil
320322
}
321323

322-
var syncPolicy = &application.SyncPolicy{}
324+
p := sp.(map[string]interface{})
323325

324-
if _a, ok := sp.(map[string]interface{})["automated"].(*schema.Set); ok {
326+
if _a, ok := p["automated"].(*schema.Set); ok {
325327
var automated = &application.SyncPolicyAutomated{}
326328

327329
list := _a.List()
@@ -344,61 +346,69 @@ func expandApplicationSyncPolicy(sp interface{}) (*application.SyncPolicy, error
344346
}
345347
}
346348

347-
if v, ok := sp.(map[string]interface{})["sync_options"]; ok {
349+
if _sOpts, ok := p["sync_options"].([]interface{}); ok && len(_sOpts) > 0 {
348350
var syncOptions application.SyncOptions
349351

350-
sOpts := v.([]interface{})
351-
if len(sOpts) > 0 {
352-
for _, sOpt := range sOpts {
353-
syncOptions = append(syncOptions, sOpt.(string))
354-
}
355-
356-
syncPolicy.SyncOptions = syncOptions
352+
for _, so := range _sOpts {
353+
syncOptions = append(syncOptions, so.(string))
357354
}
355+
356+
syncPolicy.SyncOptions = syncOptions
358357
}
359358

360-
if _retry, ok := sp.(map[string]interface{})["retry"].([]interface{}); ok {
361-
if len(_retry) > 0 {
362-
var retry = &application.RetryStrategy{}
359+
if _retry, ok := p["retry"].([]interface{}); ok && len(_retry) > 0 {
360+
var retry = &application.RetryStrategy{}
363361

364-
r := (_retry[0]).(map[string]interface{})
362+
r := (_retry[0]).(map[string]interface{})
365363

366-
if v, ok := r["limit"]; ok {
367-
var err error
364+
if v, ok := r["limit"]; ok {
365+
var err error
368366

369-
retry.Limit, err = convertStringToInt64(v.(string))
370-
if err != nil {
371-
return nil, fmt.Errorf("failed to convert retry limit to integer: %w", err)
372-
}
367+
retry.Limit, err = convertStringToInt64(v.(string))
368+
if err != nil {
369+
return nil, fmt.Errorf("failed to convert retry limit to integer: %w", err)
373370
}
371+
}
374372

375-
if _b, ok := r["backoff"].(*schema.Set); ok {
376-
retry.Backoff = &application.Backoff{}
377-
378-
list := _b.List()
379-
if len(list) > 0 {
380-
b := list[0].(map[string]interface{})
373+
if _b, ok := r["backoff"].(*schema.Set); ok {
374+
retry.Backoff = &application.Backoff{}
381375

382-
if v, ok := b["duration"]; ok {
383-
retry.Backoff.Duration = v.(string)
384-
}
376+
list := _b.List()
377+
if len(list) > 0 {
378+
b := list[0].(map[string]interface{})
385379

386-
if v, ok := b["max_duration"]; ok {
387-
retry.Backoff.MaxDuration = v.(string)
388-
}
380+
if v, ok := b["duration"]; ok {
381+
retry.Backoff.Duration = v.(string)
382+
}
389383

390-
if v, ok := b["factor"]; ok {
391-
factor, err := convertStringToInt64Pointer(v.(string))
392-
if err != nil {
393-
return nil, fmt.Errorf("failed to convert backoff factor to integer: %w", err)
394-
}
384+
if v, ok := b["max_duration"]; ok {
385+
retry.Backoff.MaxDuration = v.(string)
386+
}
395387

396-
retry.Backoff.Factor = factor
388+
if v, ok := b["factor"]; ok {
389+
factor, err := convertStringToInt64Pointer(v.(string))
390+
if err != nil {
391+
return nil, fmt.Errorf("failed to convert backoff factor to integer: %w", err)
397392
}
393+
394+
retry.Backoff.Factor = factor
398395
}
399396
}
397+
}
398+
399+
syncPolicy.Retry = retry
400+
}
401+
402+
if _mnm, ok := p["managed_namespace_metadata"].([]interface{}); ok && len(_mnm) > 0 {
403+
mnm := _mnm[0].(map[string]interface{})
404+
syncPolicy.ManagedNamespaceMetadata = &application.ManagedNamespaceMetadata{}
405+
406+
if a, ok := mnm["annotations"]; ok {
407+
syncPolicy.ManagedNamespaceMetadata.Annotations = expandStringMap(a.(map[string]interface{}))
408+
}
400409

401-
syncPolicy.Retry = retry
410+
if l, ok := mnm["labels"]; ok {
411+
syncPolicy.ManagedNamespaceMetadata.Labels = expandStringMap(l.(map[string]interface{}))
402412
}
403413
}
404414

@@ -571,6 +581,15 @@ func flattenApplicationSyncPolicy(sp *application.SyncPolicy) []map[string]inter
571581
}
572582
}
573583

584+
if sp.ManagedNamespaceMetadata != nil {
585+
result["managed_namespace_metadata"] = []map[string]interface{}{
586+
{
587+
"annotations": sp.ManagedNamespaceMetadata.Annotations,
588+
"labels": sp.ManagedNamespaceMetadata.Labels,
589+
},
590+
}
591+
}
592+
574593
result["sync_options"] = []string(sp.SyncOptions)
575594

576595
if sp.Retry != nil {

docs/resources/application.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ Optional:
379379
Optional:
380380

381381
- `automated` (Block Set, Max: 1) Whether to automatically keep an application synced to the target revision. (see [below for nested schema](#nestedblock--spec--sync_policy--automated))
382+
- `managed_namespace_metadata` (Block List, Max: 1) Controls metadata in the given namespace (if `CreateNamespace=true`). (see [below for nested schema](#nestedblock--spec--sync_policy--managed_namespace_metadata))
382383
- `retry` (Block List, Max: 1) Controls failed sync retry behavior. (see [below for nested schema](#nestedblock--spec--sync_policy--retry))
383384
- `sync_options` (List of String) List of sync options. More info: https://argo-cd.readthedocs.io/en/stable/user-guide/sync-options/.
384385

@@ -392,6 +393,15 @@ Optional:
392393
- `self_heal` (Boolean) Whether to revert resources back to their desired state upon modification in the cluster.
393394

394395

396+
<a id="nestedblock--spec--sync_policy--managed_namespace_metadata"></a>
397+
### Nested Schema for `spec.sync_policy.managed_namespace_metadata`
398+
399+
Optional:
400+
401+
- `annotations` (Map of String) Annotations to apply to the namespace.
402+
- `labels` (Map of String) Labels to apply to the namespace.
403+
404+
395405
<a id="nestedblock--spec--sync_policy--retry"></a>
396406
### Nested Schema for `spec.sync_policy.retry`
397407

0 commit comments

Comments
 (0)