From 96ec7d1b6282764b65935d3978af536a4e5de61f Mon Sep 17 00:00:00 2001 From: ClaudioGisch Date: Mon, 4 Mar 2024 16:06:57 -0300 Subject: [PATCH] Feat/allow label annotation deletion (#55) * feature: support labels/annotation deletions * test: labels/annotation deletions * refactor: review suggestions --- GNUmakefile | 2 +- internal/provider/resource_tsuru_app.go | 18 ++- internal/provider/resource_tsuru_app_test.go | 136 +++++++++++++++++++ internal/provider/utils.go | 16 +++ internal/provider/utils_test.go | 108 +++++++++++++++ 5 files changed, 275 insertions(+), 5 deletions(-) create mode 100644 internal/provider/utils_test.go diff --git a/GNUmakefile b/GNUmakefile index ab165bd..68cce89 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -2,7 +2,7 @@ HOSTNAME=registry.terraform.io NAMESPACE=tsuru NAME=tsuru BINARY=terraform-provider-${NAME} -VERSION=2.9.0 +VERSION=2.9.2 UNAME_S := $(shell uname -s) UNAME_P := $(shell uname -p) diff --git a/internal/provider/resource_tsuru_app.go b/internal/provider/resource_tsuru_app.go index be3703e..0902261 100644 --- a/internal/provider/resource_tsuru_app.go +++ b/internal/provider/resource_tsuru_app.go @@ -279,10 +279,20 @@ func resourceTsuruApplicationUpdate(ctx context.Context, d *schema.ResourceData, Tags: tags, } - if m, ok := d.GetOk("metadata"); ok { - metadata := metadataFromResourceData(m) - if metadata != nil { - app.Metadata = *metadata + if d.HasChange("metadata") { + old, new := d.GetChange("metadata") + oldMetadata := metadataFromResourceData(old) + if oldMetadata == nil { + oldMetadata = &tsuru_client.Metadata{} + } + newMetadata := metadataFromResourceData(new) + if newMetadata == nil { + newMetadata = &tsuru_client.Metadata{} + } + + app.Metadata = tsuru_client.Metadata{ + Annotations: markRemovedMetadataItemAsDeleted(oldMetadata.Annotations, newMetadata.Annotations), + Labels: markRemovedMetadataItemAsDeleted(oldMetadata.Labels, newMetadata.Labels), } } diff --git a/internal/provider/resource_tsuru_app_test.go b/internal/provider/resource_tsuru_app_test.go index a19fa79..bb54924 100644 --- a/internal/provider/resource_tsuru_app_test.go +++ b/internal/provider/resource_tsuru_app_test.go @@ -130,10 +130,87 @@ func TestAccResourceTsuruApp(t *testing.T) { return c.JSON(http.StatusOK, app) } + if iterationCount == 2 { + app := &tsuru.App{ + Name: name, + Description: "my app description", + TeamOwner: "my-team", + Platform: "python", + Plan: tsuru.Plan{Name: "c2m4"}, + Cluster: "my-cluster-01", + Pool: "prod", + Provisioner: "kubernetes", + Tags: []string{"tagA", "tagB"}, + Metadata: tsuru.Metadata{ + Labels: []tsuru.MetadataItem{{Name: "label1", Value: "value1"}, {Name: "label3", Value: "value3"}}, + }, + Deploys: 2, + Units: []tsuru.Unit{ + {Processname: "web"}, + }, + InternalAddresses: []tsuru.AppInternalAddresses{ + { + Version: "10", + Port: 8888, + Process: "web", + Domain: "app01.namespace.svc.cluster.local", + Protocol: "TCP", + }, + }, + Routers: []tsuru.AppRouters{ + { + Name: "default-router", + Addresses: []string{ + "my-app.router.io", + }, + }, + }, + Processes: []tsuru.AppProcess{ + { + Name: "web", + Plan: "c2m2", + Metadata: tsuru.Metadata{ + Labels: []tsuru.MetadataItem{ + { + Name: "weblabel", + Value: "value", + }, + }, + Annotations: []tsuru.MetadataItem{ + { + Name: "webannotation", + Value: "nice", + }, + }, + }, + }, + { + Name: "worker", + Metadata: tsuru.Metadata{ + Labels: []tsuru.MetadataItem{ + { + Name: "workerlabel", + Value: "value", + }, + }, + Annotations: []tsuru.MetadataItem{ + { + Name: "workerannotation", + Value: "nice", + }, + }, + }, + }, + }, + } + return c.JSON(http.StatusOK, app) + } + return c.JSON(http.StatusNotFound, nil) }) fakeServer.PUT("/1.0/apps/:name", func(c echo.Context) error { + iterationCount++ return c.JSON(http.StatusOK, nil) }) @@ -171,6 +248,19 @@ func TestAccResourceTsuruApp(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "internal_address.0.domain", "app01.namespace.svc.cluster.local"), ), }, + { + Config: testAccResourceTsuruApp_metadataAfterUpdate(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccResourceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "name", "app01"), + resource.TestCheckResourceAttr(resourceName, "description", "my app description"), + resource.TestCheckResourceAttr(resourceName, "platform", "python"), + resource.TestCheckResourceAttr(resourceName, "plan", "c2m4"), + resource.TestCheckResourceAttr(resourceName, "team_owner", "my-team"), + resource.TestCheckResourceAttr(resourceName, "pool", "prod"), + resource.TestCheckResourceAttr(resourceName, "tags.0", "tagA"), + ), + }, }, }) } @@ -222,3 +312,49 @@ func testAccResourceTsuruApp_basic() string { } ` } + +func testAccResourceTsuruApp_metadataAfterUpdate() string { + return ` + resource "tsuru_app" "app" { + name = "app01" + description = "my app description" + platform = "python" + plan = "c2m4" + team_owner = "my-team" + pool = "prod" + tags = ["tagA", "tagB"] + metadata { + labels = { + "label1" = "value1" + "label3" = "value3" + } + } + + process { + name = "web" + plan = "c2m2" + metadata { + labels = { + "weblabel" = "value" + } + annotations = { + "webannotation": "nice" + } + } + } + + process { + name = "worker" + + metadata { + labels = { + "workerlabel" = "value" + } + annotations = { + "workerannotation": "nice" + } + } + } + } +` +} diff --git a/internal/provider/utils.go b/internal/provider/utils.go index 4605ece..0615096 100644 --- a/internal/provider/utils.go +++ b/internal/provider/utils.go @@ -66,3 +66,19 @@ func IDtoParts(input string, minLength int) ([]string, error) { } return output, nil } + +func markRemovedMetadataItemAsDeleted(oldMetadataItems []tsuru_client.MetadataItem, newMetadataItems []tsuru_client.MetadataItem) []tsuru_client.MetadataItem { + newMap := map[string]bool{} + for _, newMetadataItem := range newMetadataItems { + newMap[newMetadataItem.Name] = true + } + + newMetadataItemsList := newMetadataItems + for _, oldMetadataItem := range oldMetadataItems { + if _, found := newMap[oldMetadataItem.Name]; !found { + oldMetadataItem.Delete = true + newMetadataItemsList = append(newMetadataItemsList, oldMetadataItem) + } + } + return newMetadataItemsList +} diff --git a/internal/provider/utils_test.go b/internal/provider/utils_test.go new file mode 100644 index 0000000..76c5fab --- /dev/null +++ b/internal/provider/utils_test.go @@ -0,0 +1,108 @@ +package provider + +import ( + "testing" + + "github.com/stretchr/testify/assert" + tsuru_client "github.com/tsuru/go-tsuruclient/pkg/tsuru" +) + +func TestMarkRemovedMetadataItemWhenOldIsEmpty(t *testing.T) { + oldMetadataItemsList := []tsuru_client.MetadataItem{} + newMetadataItemsList := []tsuru_client.MetadataItem{{ + Name: "label_name", + Value: "label_value", + }} + + resultMetadataItemList := markRemovedMetadataItemAsDeleted(oldMetadataItemsList, newMetadataItemsList) + + expectedList := []tsuru_client.MetadataItem{{ + Name: "label_name", + Value: "label_value", + }} + assert.Equal(t, expectedList, resultMetadataItemList) +} + +func TestMarkRemovedMetadataItemWhenNewIsEmpty(t *testing.T) { + oldMetadataItemsList := []tsuru_client.MetadataItem{{ + Name: "label_name", + Value: "label_value", + }} + newMetadataItemsList := []tsuru_client.MetadataItem{} + + resultMetadataItemList := markRemovedMetadataItemAsDeleted(oldMetadataItemsList, newMetadataItemsList) + + expectedList := []tsuru_client.MetadataItem{{ + Name: "label_name", + Value: "label_value", + Delete: true, + }} + assert.Equal(t, expectedList, resultMetadataItemList) +} + +func TestMarkRemovedMetadataItemWhenOldIsReplaced(t *testing.T) { + oldMetadataItemsList := []tsuru_client.MetadataItem{{ + Name: "label_name", + Value: "label_value", + }} + newMetadataItemsList := []tsuru_client.MetadataItem{{ + Name: "label_name", + Value: "new_label_value", + }} + + resultMetadataItemList := markRemovedMetadataItemAsDeleted(oldMetadataItemsList, newMetadataItemsList) + + expectedList := []tsuru_client.MetadataItem{{ + Name: "label_name", + Value: "new_label_value", + }} + assert.Equal(t, expectedList, resultMetadataItemList) +} + +func TestMarkRemovedMetadataItemWhenOldIsRemovedNewIsAdded(t *testing.T) { + oldMetadataItemsList := []tsuru_client.MetadataItem{{ + Name: "label_name", + Value: "label_value", + }} + newMetadataItemsList := []tsuru_client.MetadataItem{{ + Name: "new_label_name", + Value: "new_label_value", + }} + + resultMetadataItemList := markRemovedMetadataItemAsDeleted(oldMetadataItemsList, newMetadataItemsList) + + expectedList := []tsuru_client.MetadataItem{{ + Name: "new_label_name", + Value: "new_label_value", + }, { + Name: "label_name", + Value: "label_value", + Delete: true, + }} + assert.Equal(t, expectedList, resultMetadataItemList) +} + +func TestMarkRemovedMetadataItemWhenOldShouldNotChange(t *testing.T) { + oldMetadataItemsList := []tsuru_client.MetadataItem{{ + Name: "label_name", + Value: "label_value", + }} + newMetadataItemsList := []tsuru_client.MetadataItem{{ + Name: "label_name", + Value: "label_value", + }, { + Name: "new_label_name", + Value: "new_label_value", + }} + + resultMetadataItemList := markRemovedMetadataItemAsDeleted(oldMetadataItemsList, newMetadataItemsList) + + expectedList := []tsuru_client.MetadataItem{{ + Name: "label_name", + Value: "label_value", + }, { + Name: "new_label_name", + Value: "new_label_value", + }} + assert.Equal(t, expectedList, resultMetadataItemList) +}