Skip to content

Commit d818ac6

Browse files
authored
Fix argocd_project orphaned_resources v0 to v1 migration and permadiff (argoproj-labs#61)
1 parent c968929 commit d818ac6

File tree

7 files changed

+350
-141
lines changed

7 files changed

+350
-141
lines changed

argocd/resource_argocd_project.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,20 @@ func resourceArgoCDProject() *schema.Resource {
2323
},
2424
Schema: map[string]*schema.Schema{
2525
"metadata": metadataSchema("appprojects.argoproj.io"),
26-
"spec": projectSpecSchemaV1(),
26+
"spec": projectSpecSchemaV2(),
2727
},
28-
SchemaVersion: 1,
28+
SchemaVersion: 2,
2929
StateUpgraders: []schema.StateUpgrader{
3030
{
3131
Type: resourceArgoCDProjectV0().CoreConfigSchema().ImpliedType(),
3232
Upgrade: resourceArgoCDProjectStateUpgradeV0,
3333
Version: 0,
3434
},
35+
{
36+
Type: resourceArgoCDProjectV1().CoreConfigSchema().ImpliedType(),
37+
Upgrade: resourceArgoCDProjectStateUpgradeV1,
38+
Version: 1,
39+
},
3540
},
3641
}
3742
}

argocd/resource_argocd_project_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,12 @@ func TestAccArgoCDProject(t *testing.T) {
6868
}
6969

7070
func TestAccArgoCDProject_tokensCoexistence(t *testing.T) {
71-
7271
resource.ParallelTest(t, resource.TestCase{
7372
PreCheck: func() { testAccPreCheck(t) },
7473
Providers: testAccProviders,
7574
Steps: []resource.TestStep{
7675
{
76+
ExpectNonEmptyPlan: true,
7777
Config: testAccArgoCDProjectCoexistenceWithTokenResource(
7878
"test-acc-"+acctest.RandString(10),
7979
4,

argocd/schema_project.go

Lines changed: 215 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package argocd
33
import (
44
"fmt"
55
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
6+
"reflect"
67
)
78

89
func projectSpecSchemaV0() *schema.Schema {
@@ -341,26 +342,78 @@ func projectSpecSchemaV1() *schema.Schema {
341342
}
342343
}
343344

344-
func resourceArgoCDProjectV0() *schema.Resource {
345-
return &schema.Resource{
346-
Schema: map[string]*schema.Schema{
347-
"metadata": metadataSchema("appprojects.argoproj.io"),
348-
"spec": projectSpecSchemaV0(),
349-
},
350-
}
351-
}
352-
353-
func resourceArgoCDProjectStateUpgradeV0(rawState map[string]interface{}, _ interface{}) (map[string]interface{}, error) {
354-
spec := rawState["spec"].([]map[string]interface{})
355-
if len(spec) > 0 {
356-
if orphanedResources, ok := spec[0]["orphaned_resources"]; ok {
357-
switch orphanedResources.(type) {
358-
359-
// <= v0.4.8
360-
case map[string]bool:
361-
warn := orphanedResources.(map[string]bool)["warn"]
362-
newOrphanedResources := schema.NewSet(
363-
schema.HashResource(&schema.Resource{
345+
func projectSpecSchemaV2() *schema.Schema {
346+
return &schema.Schema{
347+
Type: schema.TypeList,
348+
MinItems: 1,
349+
MaxItems: 1,
350+
Description: "ArgoCD App project resource specs. Required attributes: destination, source_repos.",
351+
Required: true,
352+
Elem: &schema.Resource{
353+
Schema: map[string]*schema.Schema{
354+
"cluster_resource_whitelist": {
355+
Type: schema.TypeSet,
356+
Optional: true,
357+
Elem: &schema.Resource{
358+
Schema: map[string]*schema.Schema{
359+
"group": {
360+
Type: schema.TypeString,
361+
ValidateFunc: validateGroupName,
362+
Optional: true,
363+
},
364+
"kind": {
365+
Type: schema.TypeString,
366+
Optional: true,
367+
},
368+
},
369+
},
370+
},
371+
"description": {
372+
Type: schema.TypeString,
373+
Optional: true,
374+
},
375+
"destination": {
376+
Type: schema.TypeSet,
377+
Required: true,
378+
Elem: &schema.Resource{
379+
Schema: map[string]*schema.Schema{
380+
"server": {
381+
Type: schema.TypeString,
382+
Optional: true,
383+
},
384+
"namespace": {
385+
Type: schema.TypeString,
386+
Required: true,
387+
},
388+
"name": {
389+
Type: schema.TypeString,
390+
Optional: true,
391+
Description: "Name of the destination cluster which can be used instead of server.",
392+
},
393+
},
394+
},
395+
},
396+
"namespace_resource_blacklist": {
397+
Type: schema.TypeSet,
398+
Optional: true,
399+
Elem: &schema.Resource{
400+
Schema: map[string]*schema.Schema{
401+
"group": {
402+
Type: schema.TypeString,
403+
Optional: true,
404+
},
405+
"kind": {
406+
Type: schema.TypeString,
407+
Optional: true,
408+
},
409+
},
410+
},
411+
},
412+
"orphaned_resources": {
413+
Type: schema.TypeList,
414+
Optional: true,
415+
MaxItems: 1,
416+
Elem: &schema.Resource{
364417
Schema: map[string]*schema.Schema{
365418
"warn": {
366419
Type: schema.TypeBool,
@@ -388,15 +441,151 @@ func resourceArgoCDProjectStateUpgradeV0(rawState map[string]interface{}, _ inte
388441
},
389442
},
390443
},
391-
}),
392-
[]interface{}{map[string]interface{}{"warn": warn}},
393-
)
394-
rawState["spec"].([]map[string]interface{})[0]["orphaned_resources"] = newOrphanedResources
444+
},
445+
},
446+
"role": {
447+
Type: schema.TypeList,
448+
Optional: true,
449+
Elem: &schema.Resource{
450+
Schema: map[string]*schema.Schema{
451+
"description": {
452+
Type: schema.TypeString,
453+
Optional: true,
454+
},
455+
"groups": {
456+
Type: schema.TypeList,
457+
Optional: true,
458+
Elem: &schema.Schema{Type: schema.TypeString},
459+
},
460+
"name": {
461+
Type: schema.TypeString,
462+
ValidateFunc: validateRoleName,
463+
Required: true,
464+
},
465+
"policies": {
466+
Type: schema.TypeList,
467+
Required: true,
468+
Elem: &schema.Schema{Type: schema.TypeString},
469+
},
470+
},
471+
},
472+
},
473+
"source_repos": {
474+
Type: schema.TypeList,
475+
Required: true,
476+
Elem: &schema.Schema{Type: schema.TypeString},
477+
},
478+
"signature_keys": {
479+
Type: schema.TypeList,
480+
Optional: true,
481+
Elem: &schema.Schema{Type: schema.TypeString},
482+
},
483+
"sync_window": {
484+
Type: schema.TypeList,
485+
Optional: true,
486+
Elem: &schema.Resource{
487+
Schema: map[string]*schema.Schema{
488+
"applications": {
489+
Type: schema.TypeList,
490+
Optional: true,
491+
Elem: &schema.Schema{Type: schema.TypeString},
492+
},
493+
"clusters": {
494+
Type: schema.TypeList,
495+
Optional: true,
496+
Elem: &schema.Schema{Type: schema.TypeString},
497+
},
498+
"duration": {
499+
Type: schema.TypeString,
500+
ValidateFunc: validateSyncWindowDuration,
501+
Optional: true,
502+
},
503+
"kind": {
504+
Type: schema.TypeString,
505+
ValidateFunc: validateSyncWindowKind,
506+
Optional: true,
507+
},
508+
"manual_sync": {
509+
Type: schema.TypeBool,
510+
Optional: true,
511+
},
512+
"namespaces": {
513+
Type: schema.TypeList,
514+
Optional: true,
515+
Elem: &schema.Schema{Type: schema.TypeString},
516+
},
517+
"schedule": {
518+
Type: schema.TypeString,
519+
ValidateFunc: validateSyncWindowSchedule,
520+
Optional: true,
521+
},
522+
},
523+
},
524+
},
525+
},
526+
},
527+
}
528+
}
529+
530+
func resourceArgoCDProjectV0() *schema.Resource {
531+
return &schema.Resource{
532+
Schema: map[string]*schema.Schema{
533+
"metadata": metadataSchema("appprojects.argoproj.io"),
534+
"spec": projectSpecSchemaV0(),
535+
},
536+
}
537+
}
538+
539+
func resourceArgoCDProjectV1() *schema.Resource {
540+
return &schema.Resource{
541+
Schema: map[string]*schema.Schema{
542+
"metadata": metadataSchema("appprojects.argoproj.io"),
543+
"spec": projectSpecSchemaV1(),
544+
},
545+
}
546+
}
547+
548+
func resourceArgoCDProjectStateUpgradeV0(rawState map[string]interface{}, _ interface{}) (map[string]interface{}, error) {
549+
_spec := rawState["spec"]
550+
if len(_spec.([]interface{})) > 0 {
551+
spec := _spec.([]interface{})[0]
552+
if orphanedResources, ok := spec.(map[string]interface{})["orphaned_resources"]; ok {
553+
switch orphanedResources.(type) {
554+
// <= v0.4.8 with nil orphaned_resources map
555+
case map[string]interface{}:
556+
warn := orphanedResources.(map[string]interface{})["warn"]
557+
newOrphanedResources := []interface{}{map[string]interface{}{"warn": warn}}
558+
rawState["spec"].([]interface{})[0].(map[string]interface{})["orphaned_resources"] = newOrphanedResources
395559

396-
// >= v0.5.0 <= v1.1.0
560+
// <= v0.4.8 with non-nil orphaned_resources map
561+
case map[string]bool:
562+
warn := orphanedResources.(map[string]bool)["warn"]
563+
newOrphanedResources := []interface{}{map[string]bool{"warn": warn}}
564+
rawState["spec"].([]interface{})[0].(map[string]interface{})["orphaned_resources"] = newOrphanedResources
565+
566+
// >= v0.5.0 <= v1.1.2 (should not happen)
567+
case *schema.Set:
568+
return nil, fmt.Errorf("error during state migration v0 to v1, unsupported type for 'orphaned_resources': %s", reflect.TypeOf(orphanedResources))
569+
default:
570+
return nil, fmt.Errorf("error during state migration v0 to v1, unsupported type for 'orphaned_resources': %s", reflect.TypeOf(orphanedResources))
571+
}
572+
}
573+
}
574+
return rawState, nil
575+
}
576+
577+
func resourceArgoCDProjectStateUpgradeV1(rawState map[string]interface{}, _ interface{}) (map[string]interface{}, error) {
578+
_spec := rawState["spec"]
579+
if len(_spec.([]interface{})) > 0 {
580+
spec := _spec.([]interface{})[0]
581+
if orphanedResources, ok := spec.(map[string]interface{})["orphaned_resources"]; ok {
582+
switch orphanedResources.(type) {
583+
case []interface{}:
584+
// >= v0.5.0 <= v1.1.2
397585
case *schema.Set:
586+
rawState["spec"].([]interface{})[0].(map[string]interface{})["orphaned_resources"] = orphanedResources.(*schema.Set).List()
398587
default:
399-
return nil, fmt.Errorf("error during state migration v0 to v1, unsupported type for 'orphaned_resources': %s", orphanedResources)
588+
return nil, fmt.Errorf("error during state migration v1 to v2, unsupported type for 'orphaned_resources': %s", reflect.TypeOf(orphanedResources))
400589
}
401590
}
402591
}

0 commit comments

Comments
 (0)