Skip to content

Commit cb8528d

Browse files
authored
Prevent duplicate clusters ending up in Terraform state (#264)
1 parent 50f550a commit cb8528d

File tree

2 files changed

+27
-102
lines changed

2 files changed

+27
-102
lines changed

argocd/resource_argocd_cluster.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,17 +90,20 @@ func resourceArgoCDClusterCreate(ctx context.Context, d *schema.ResourceData, me
9090

9191
client := *server.ClusterClient
9292

93+
// Need a full lock here to avoid race conditions between List existing clusters and creating a new one
94+
tokenMutexClusters.Lock()
95+
9396
// Cluster are unique by "server address" so we should check there is no existing cluster with this address before
94-
tokenMutexClusters.RLock()
9597
existingClusters, err := client.List(ctx, &clusterClient.ClusterQuery{
9698
Id: &clusterClient.ClusterID{
9799
Type: "server",
98100
Value: cluster.Server, // TODO: not used by backend, upstream bug ?
99101
},
100102
})
101-
tokenMutexClusters.RUnlock()
102103

103104
if err != nil {
105+
tokenMutexClusters.Unlock()
106+
104107
return []diag.Diagnostic{
105108
{
106109
Severity: diag.Error,
@@ -115,6 +118,8 @@ func resourceArgoCDClusterCreate(ctx context.Context, d *schema.ResourceData, me
115118
if len(existingClusters.Items) > 0 {
116119
for _, existingCluster := range existingClusters.Items {
117120
if rtrimmedServer == strings.TrimRight(existingCluster.Server, "/") {
121+
tokenMutexClusters.Unlock()
122+
118123
return []diag.Diagnostic{
119124
{
120125
Severity: diag.Error,
@@ -125,9 +130,8 @@ func resourceArgoCDClusterCreate(ctx context.Context, d *schema.ResourceData, me
125130
}
126131
}
127132

128-
tokenMutexClusters.Lock()
129133
c, err := client.Create(ctx, &clusterClient.ClusterCreateRequest{
130-
Cluster: cluster, Upsert: true})
134+
Cluster: cluster, Upsert: false})
131135
tokenMutexClusters.Unlock()
132136

133137
if err != nil {

argocd/resource_argocd_cluster_test.go

Lines changed: 19 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -273,99 +273,22 @@ func TestAccArgoCDCluster_metadata(t *testing.T) {
273273
})
274274
}
275275

276-
func TestAccArgoCDCluster_uniqueByServerEvenWithDifferentNames(t *testing.T) {
277-
name := acctest.RandString(10)
278-
276+
func TestAccArgoCDCluster_invalidSameServer(t *testing.T) {
279277
resource.Test(t, resource.TestCase{
280278
PreCheck: func() { testAccPreCheck(t); testAccPreCheckFeatureSupported(t, featureProjectScopedClusters) },
281279
ProviderFactories: testAccProviders,
282280
Steps: []resource.TestStep{
283281
{
284-
Config: testAccArgoCDClusterTwiceWithSameServer(name, name+"d"),
282+
Config: testAccArgoCDClusterTwiceWithSameServer(),
285283
ExpectError: regexp.MustCompile("cluster with server address .* already exists"),
286-
Check: resource.ComposeTestCheckFunc(
287-
resource.TestCheckResourceAttr(
288-
"argocd_cluster.cluster_one",
289-
"info.0.connection_state.0.status",
290-
"Successful",
291-
),
292-
resource.TestCheckResourceAttr(
293-
"argocd_cluster.cluster_one",
294-
"config.0.tls_client_config.0.insecure",
295-
"true",
296-
),
297-
resource.TestCheckResourceAttr(
298-
"argocd_cluster.cluster_one",
299-
"name",
300-
name,
301-
),
302-
),
303284
},
304-
},
305-
})
306-
}
307-
308-
func TestAccArgoCDCluster_uniqueByServer(t *testing.T) {
309-
name := acctest.RandString(10)
310-
311-
resource.Test(t, resource.TestCase{
312-
PreCheck: func() { testAccPreCheck(t); testAccPreCheckFeatureSupported(t, featureProjectScopedClusters) },
313-
ProviderFactories: testAccProviders,
314-
Steps: []resource.TestStep{
315285
{
316286
Config: testAccArgoCDClusterTwiceWithSameServerNoNames(),
317287
ExpectError: regexp.MustCompile("cluster with server address .* already exists"),
318-
Check: resource.ComposeTestCheckFunc(
319-
resource.TestCheckResourceAttr(
320-
"argocd_cluster.cluster_one",
321-
"info.0.connection_state.0.status",
322-
"Successful",
323-
),
324-
resource.TestCheckResourceAttr(
325-
"argocd_cluster.cluster_one",
326-
"config.0.tls_client_config.0.insecure",
327-
"true",
328-
),
329-
resource.TestCheckResourceAttr(
330-
"argocd_cluster.cluster_one",
331-
"name",
332-
name,
333-
),
334-
),
335288
},
336-
},
337-
})
338-
}
339-
340-
func TestAccArgoCDCluster_uniqueByServerTrimmed(t *testing.T) {
341-
name := acctest.RandString(10)
342-
343-
resource.Test(t, resource.TestCase{
344-
PreCheck: func() { testAccPreCheck(t); testAccPreCheckFeatureSupported(t, featureProjectScopedClusters) },
345-
ProviderFactories: testAccProviders,
346-
Steps: []resource.TestStep{
347289
{
348-
Config: testAccArgoCDClusterTwiceWithSameServerNoNamesTrimmed(
349-
"https://kubernetes.default.svc.cluster.local",
350-
"https://kubernetes.default.svc.cluster.local/"),
290+
Config: testAccArgoCDClusterTwiceWithSameLogicalServer(),
351291
ExpectError: regexp.MustCompile("cluster with server address .* already exists"),
352-
Check: resource.ComposeTestCheckFunc(
353-
resource.TestCheckResourceAttr(
354-
"argocd_cluster.cluster_one",
355-
"info.0.connection_state.0.status",
356-
"Successful",
357-
),
358-
resource.TestCheckResourceAttr(
359-
"argocd_cluster.cluster_one",
360-
"config.0.tls_client_config.0.insecure",
361-
"true",
362-
),
363-
resource.TestCheckResourceAttr(
364-
"argocd_cluster.cluster_one",
365-
"name",
366-
name,
367-
),
368-
),
369292
},
370293
},
371294
})
@@ -486,11 +409,11 @@ resource "argocd_cluster" "cluster_metadata" {
486409
`
487410
}
488411

489-
func testAccArgoCDClusterTwiceWithSameServer(clusterName, clusterName2 string) string {
490-
return fmt.Sprintf(`
491-
resource "argocd_cluster" "cluster_one" {
412+
func testAccArgoCDClusterTwiceWithSameServer() string {
413+
return `
414+
resource "argocd_cluster" "cluster_one_same_server" {
492415
server = "https://kubernetes.default.svc.cluster.local"
493-
name = "%s"
416+
name = "foo"
494417
config {
495418
# Uses Kind's bootstrap token whose ttl is 24 hours after cluster bootstrap.
496419
bearer_token = "abcdef.0123456789abcdef"
@@ -499,23 +422,22 @@ resource "argocd_cluster" "cluster_one" {
499422
}
500423
}
501424
}
502-
resource "argocd_cluster" "cluster_two" {
425+
resource "argocd_cluster" "cluster_two_same_server" {
503426
server = "https://kubernetes.default.svc.cluster.local"
504-
name = "%s"
427+
name = "bar"
505428
config {
506429
# Uses Kind's bootstrap token whose ttl is 24 hours after cluster bootstrap.
507430
bearer_token = "abcdef.0123456789abcdef"
508431
tls_client_config {
509432
insecure = true
510433
}
511434
}
512-
}
513-
`, clusterName, clusterName2)
435+
}`
514436
}
515437

516438
func testAccArgoCDClusterTwiceWithSameServerNoNames() string {
517439
return `
518-
resource "argocd_cluster" "cluster_one" {
440+
resource "argocd_cluster" "cluster_one_no_name" {
519441
server = "https://kubernetes.default.svc.cluster.local"
520442
config {
521443
# Uses Kind's bootstrap token whose ttl is 24 hours after cluster bootstrap.
@@ -525,7 +447,7 @@ resource "argocd_cluster" "cluster_one" {
525447
}
526448
}
527449
}
528-
resource "argocd_cluster" "cluster_two" {
450+
resource "argocd_cluster" "cluster_two_no_name" {
529451
server = "https://kubernetes.default.svc.cluster.local"
530452
config {
531453
# Uses Kind's bootstrap token whose ttl is 24 hours after cluster bootstrap.
@@ -538,11 +460,11 @@ resource "argocd_cluster" "cluster_two" {
538460
`
539461
}
540462

541-
func testAccArgoCDClusterTwiceWithSameServerNoNamesTrimmed(server, server2 string) string {
542-
return fmt.Sprintf(`
543-
resource "argocd_cluster" "cluster_one" {
463+
func testAccArgoCDClusterTwiceWithSameLogicalServer() string {
464+
return `
465+
resource "argocd_cluster" "cluster_with_trailing_slash" {
544466
name = "server"
545-
server = "%s"
467+
server = "https://kubernetes.default.svc.cluster.local/"
546468
config {
547469
# Uses Kind's bootstrap token whose ttl is 24 hours after cluster bootstrap.
548470
bearer_token = "abcdef.0123456789abcdef"
@@ -551,18 +473,17 @@ resource "argocd_cluster" "cluster_one" {
551473
}
552474
}
553475
}
554-
resource "argocd_cluster" "cluster_two" {
476+
resource "argocd_cluster" "cluster_with_no_trailing_slash" {
555477
name = "server"
556-
server = "%s"
478+
server = "https://kubernetes.default.svc.cluster.local"
557479
config {
558480
# Uses Kind's bootstrap token whose ttl is 24 hours after cluster bootstrap.
559481
bearer_token = "abcdef.0123456789abcdef"
560482
tls_client_config {
561483
insecure = true
562484
}
563485
}
564-
}
565-
`, server, server2)
486+
}`
566487
}
567488

568489
func testAccArgoCDClusterMetadata_addLabels(clusterName string) string {

0 commit comments

Comments
 (0)