From 0e105018f947ff52e87dd652cead4098f0058230 Mon Sep 17 00:00:00 2001 From: wai-wong-edb <119956756+wai-wong-edb@users.noreply.github.com> Date: Wed, 14 Aug 2024 11:01:42 +0100 Subject: [PATCH 1/2] feat: tag delete (#521) * feat: resource tag create * fix: lint errors * fix: lint errors * refactor: refactor tag client * feat: tag update * refactor: refactor tag client * feat: changed tag description * feat: tag import * feat: lint error * feat: tag delete --- pkg/api/tag_client.go | 11 +++++++++++ pkg/provider/resource_tag.go | 14 ++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/pkg/api/tag_client.go b/pkg/api/tag_client.go index 0264be45..0d5cadd4 100644 --- a/pkg/api/tag_client.go +++ b/pkg/api/tag_client.go @@ -101,3 +101,14 @@ func (tc TagClient) List(ctx context.Context) ([]api.TagResponse, error) { return response.Data, err } + +func (tc TagClient) Delete(ctx context.Context, tagId string) error { + url := fmt.Sprintf("tags/%s", tagId) + + _, err := tc.doRequest(ctx, http.MethodDelete, url, nil) + if err != nil { + return err + } + + return nil +} diff --git a/pkg/provider/resource_tag.go b/pkg/provider/resource_tag.go index 34e1b048..aafc454d 100644 --- a/pkg/provider/resource_tag.go +++ b/pkg/provider/resource_tag.go @@ -168,6 +168,20 @@ func (tr *tagResource) Update(ctx context.Context, req resource.UpdateRequest, r } func (tr *tagResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state TagResourceModel + diags := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + err := tr.client.Delete(ctx, state.TagId.ValueString()) + if err != nil { + if !appendDiagFromBAErr(err, &resp.Diagnostics) { + resp.Diagnostics.AddError("Error deleting tag", err.Error()) + } + return + } } func (tr *tagResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { From d74f2ce4f0170c1860927af0d4019f8e92b51a2c Mon Sep 17 00:00:00 2001 From: wai-wong-edb <119956756+wai-wong-edb@users.noreply.github.com> Date: Fri, 16 Aug 2024 10:53:51 +0100 Subject: [PATCH 2/2] feat: tags assign to cluster resources single/ha/faraway-replica (#526) * feat: resource tag create * fix: lint errors * fix: lint errors * refactor: refactor tag client * feat: tag update * refactor: refactor tag client * feat: changed tag description * feat: tag import * feat: lint error * feat: assign tags to resources * fix: faraway replica assign tag * feat: tag in cluster examples * fix: lint fixes * feat: faraway-replica tag fix * fix: faraway-replica data source --- .../biganimal_cluster/ha/resource.tf | 10 ++++ .../single_node/aws/resource.tf | 10 ++++ .../single_node/azure/resource.tf | 10 ++++ .../single_node/gcp/resource.tf | 10 ++++ .../biganimal_faraway_replica/aws/resource.tf | 13 +++- .../azure/resource.tf | 12 +++- .../cluster_and_faraway_replica/resource.tf | 13 +++- .../biganimal_faraway_replica/gcp/resource.tf | 13 +++- .../biganimal_faraway_replica/import.sh | 2 + pkg/models/cluster.go | 11 ++++ pkg/models/common/api/tag.go | 8 +++ pkg/provider/data_source_fareplica.go | 17 ++++++ pkg/provider/resource_cluster.go | 50 ++++++++++++++++ pkg/provider/resource_fareplica.go | 59 ++++++++++++++++++- 14 files changed, 230 insertions(+), 8 deletions(-) create mode 100644 examples/resources/biganimal_faraway_replica/import.sh create mode 100644 pkg/models/common/api/tag.go diff --git a/examples/resources/biganimal_cluster/ha/resource.tf b/examples/resources/biganimal_cluster/ha/resource.tf index 360fb33f..2cc74b02 100644 --- a/examples/resources/biganimal_cluster/ha/resource.tf +++ b/examples/resources/biganimal_cluster/ha/resource.tf @@ -101,6 +101,16 @@ resource "biganimal_cluster" "ha_cluster" { # ] } + #tags = [ + # { + # tag_name = "test-tag-1" + # color = "blue" + # }, + # { + # tag_name = "test-tag-2" + # }, + #] + # transparent_data_encryption = { # key_id = # } diff --git a/examples/resources/biganimal_cluster/single_node/aws/resource.tf b/examples/resources/biganimal_cluster/single_node/aws/resource.tf index 472e686a..9f879026 100644 --- a/examples/resources/biganimal_cluster/single_node/aws/resource.tf +++ b/examples/resources/biganimal_cluster/single_node/aws/resource.tf @@ -102,6 +102,16 @@ resource "biganimal_cluster" "single_node_cluster" { # ] } + #tags = [ + # { + # tag_name = "test-tag-1" + # color = "blue" + # }, + # { + # tag_name = "test-tag-2" + # }, + #] + # pe_allowed_principal_ids = [ # # ex: 123456789012 # ] diff --git a/examples/resources/biganimal_cluster/single_node/azure/resource.tf b/examples/resources/biganimal_cluster/single_node/azure/resource.tf index 0290122a..aeac78d8 100644 --- a/examples/resources/biganimal_cluster/single_node/azure/resource.tf +++ b/examples/resources/biganimal_cluster/single_node/azure/resource.tf @@ -103,6 +103,16 @@ resource "biganimal_cluster" "single_node_cluster" { # ] } + #tags = [ + # { + # tag_name = "test-tag-1" + # color = "blue" + # }, + # { + # tag_name = "test-tag-2" + # }, + #] + # pe_allowed_principal_ids = [ # # ex: "9334e5e6-7f47-aE61-5A4F-ee067daeEf4A" # ] diff --git a/examples/resources/biganimal_cluster/single_node/gcp/resource.tf b/examples/resources/biganimal_cluster/single_node/gcp/resource.tf index 093e117c..25949974 100644 --- a/examples/resources/biganimal_cluster/single_node/gcp/resource.tf +++ b/examples/resources/biganimal_cluster/single_node/gcp/resource.tf @@ -103,6 +103,16 @@ resource "biganimal_cluster" "single_node_cluster" { # ] } + #tags = [ + # { + # tag_name = "test-tag-1" + # color = "blue" + # }, + # { + # tag_name = "test-tag-2" + # }, + #] + # pe_allowed_principal_ids = [ # # ex: "development-data-123456" # ] diff --git a/examples/resources/biganimal_faraway_replica/aws/resource.tf b/examples/resources/biganimal_faraway_replica/aws/resource.tf index 5ce8dc4e..fdf0ff2b 100644 --- a/examples/resources/biganimal_faraway_replica/aws/resource.tf +++ b/examples/resources/biganimal_faraway_replica/aws/resource.tf @@ -67,7 +67,18 @@ resource "biganimal_faraway_replica" "faraway_replica" { size = "4 Gi" } private_networking = false - region = "eu-west-2" + region = "ap-south-1" + + #tags = [ + # { + # tag_name = "test-tag-1" + # color = "blue" + # }, + # { + # tag_name = "test-tag-2" + # }, + #] + # pe_allowed_principal_ids = [ # # ex: 123456789012 # ] diff --git a/examples/resources/biganimal_faraway_replica/azure/resource.tf b/examples/resources/biganimal_faraway_replica/azure/resource.tf index 2e7bcbba..2e89affa 100644 --- a/examples/resources/biganimal_faraway_replica/azure/resource.tf +++ b/examples/resources/biganimal_faraway_replica/azure/resource.tf @@ -66,9 +66,19 @@ resource "biganimal_faraway_replica" "faraway_replica" { volume_properties = "P1" size = "4 Gi" } - private_networking = false region = "australiaeast" + + #tags = [ + # { + # tag_name = "test-tag-1" + # color = "blue" + # }, + # { + # tag_name = "test-tag-2" + # }, + #] + # pe_allowed_principal_ids = [ # # ex: "9334e5e6-7f47-aE61-5A4F-ee067daeEf4A" # ] diff --git a/examples/resources/biganimal_faraway_replica/cluster_and_faraway_replica/resource.tf b/examples/resources/biganimal_faraway_replica/cluster_and_faraway_replica/resource.tf index daac0ec0..00124bf2 100644 --- a/examples/resources/biganimal_faraway_replica/cluster_and_faraway_replica/resource.tf +++ b/examples/resources/biganimal_faraway_replica/cluster_and_faraway_replica/resource.tf @@ -80,7 +80,7 @@ resource "biganimal_faraway_replica" "faraway_replica" { backup_retention_period = "8d" csp_auth = false - instance_type = "aws:c6i.large" + instance_type = "azure:Standard_D2s_v3" // only following pg_config parameters are configurable for faraway replica // max_connections, max_locks_per_transaction, max_prepared_transactions, max_wal_senders, max_worker_processes. @@ -102,10 +102,19 @@ resource "biganimal_faraway_replica" "faraway_replica" { volume_properties = "P1" size = "4 Gi" } - private_networking = false region = "centralindia" + #tags = [ + # { + # tag_name = "test-tag-1" + # color = "blue" + # }, + # { + # tag_name = "test-tag-2" + # }, + #] + # transparent_data_encryption = { # key_id = # } diff --git a/examples/resources/biganimal_faraway_replica/gcp/resource.tf b/examples/resources/biganimal_faraway_replica/gcp/resource.tf index e6be2a9f..f74b1c79 100644 --- a/examples/resources/biganimal_faraway_replica/gcp/resource.tf +++ b/examples/resources/biganimal_faraway_replica/gcp/resource.tf @@ -64,10 +64,21 @@ resource "biganimal_faraway_replica" "faraway_replica" { storage = { volume_type = "pd-ssd" volume_properties = "pd-ssd" - size = "10 Gi" + size = "4 Gi" } private_networking = false region = "us-east1" + + #tags = [ + # { + # tag_name = "test-tag-1" + # color = "blue" + # }, + # { + # tag_name = "test-tag-2" + # }, + #] + # pe_allowed_principal_ids = [ # # ex: "development-data-123456" # ] diff --git a/examples/resources/biganimal_faraway_replica/import.sh b/examples/resources/biganimal_faraway_replica/import.sh new file mode 100644 index 00000000..f7a48516 --- /dev/null +++ b/examples/resources/biganimal_faraway_replica/import.sh @@ -0,0 +1,2 @@ +# terraform import biganimal_faraway_replica. / +terraform import biganimal_faraway_replica.faraway_replica prj_deadbeef01234567/p-abcd123456 diff --git a/pkg/models/cluster.go b/pkg/models/cluster.go index ff22648e..2684159c 100644 --- a/pkg/models/cluster.go +++ b/pkg/models/cluster.go @@ -58,6 +58,15 @@ func NewCluster(d *schema.ResourceData) (*Cluster, error) { return nil, err } + tagKey := d.Get("tags") + tags := []commonApi.Tag{} + if tagKey != nil { + tags, err = utils.StructFromProps[[]commonApi.Tag](tagKey.(*schema.Set).List()) + if err != nil { + return nil, err + } + } + cluster := &Cluster{ ReplicaSourceClusterId: SourceId, ClusterType: ClusterType, @@ -96,6 +105,7 @@ func NewCluster(d *schema.ResourceData) (*Cluster, error) { }, ReadOnlyConnections: clusterRoConn, Storage: &storage, + Tags: tags, } return cluster, nil @@ -171,6 +181,7 @@ type Cluster struct { SuperuserAccess *bool `json:"superuserAccess,omitempty"` Extensions *[]ClusterExtension `json:"extensions,omitempty"` PgBouncer *PgBouncer `json:"pgBouncer,omitempty"` + Tags []commonApi.Tag `json:"tags,omitempty"` VolumeSnapshot *bool `json:"volumeSnapshotBackup,omitempty"` EncryptionKeyIdReq *string `json:"keyId,omitempty"` EncryptionKeyResp *EncryptionKey `json:"encryptionKey,omitempty"` diff --git a/pkg/models/common/api/tag.go b/pkg/models/common/api/tag.go new file mode 100644 index 00000000..e87777fe --- /dev/null +++ b/pkg/models/common/api/tag.go @@ -0,0 +1,8 @@ +package api + +// mapstructure annotations are used by faraway away replica only and should be removed once we migrate faraway replica resouce to terraform plugin framework +type Tag struct { + Color *string `json:"color,omitempty" mapstructure:"color"` + TagId string `json:"tagId" mapstructure:"tag_id"` + TagName string `json:"tagName" mapstructure:"tag_name"` +} diff --git a/pkg/provider/data_source_fareplica.go b/pkg/provider/data_source_fareplica.go index 35edff44..662d7426 100644 --- a/pkg/provider/data_source_fareplica.go +++ b/pkg/provider/data_source_fareplica.go @@ -254,6 +254,23 @@ func (c *FAReplicaData) Schema(ctx context.Context, req datasource.SchemaRequest MarkdownDescription: "Transparent data encryption action.", Computed: true, }, + "tags": schema.SetNestedAttribute{ + Description: "Assign existing tags or create tags to assign to this resource", + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "tag_id": schema.StringAttribute{ + Computed: true, + }, + "tag_name": schema.StringAttribute{ + Required: true, + }, + "color": schema.StringAttribute{ + Computed: true, + }, + }, + }, + }, }, } } diff --git a/pkg/provider/resource_cluster.go b/pkg/provider/resource_cluster.go index a2bba884..d7689ddd 100644 --- a/pkg/provider/resource_cluster.go +++ b/pkg/provider/resource_cluster.go @@ -80,6 +80,7 @@ type ClusterResourceModel struct { PgIdentity types.String `tfsdk:"pg_identity"` TransparentDataEncryptionAction types.String `tfsdk:"transparent_data_encryption_action"` VolumeSnapshot types.Bool `tfsdk:"volume_snapshot_backup"` + Tags []commonTerraform.Tag `tfsdk:"tags"` Timeouts timeouts.Value `tfsdk:"timeouts"` } @@ -502,6 +503,36 @@ func (c *clusterResource) Schema(ctx context.Context, req resource.SchemaRequest Optional: true, PlanModifiers: []planmodifier.Bool{boolplanmodifier.UseStateForUnknown()}, }, + "tags": schema.SetNestedAttribute{ + Description: "Assign existing tags or create tags to assign to this resource", + Optional: true, + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "tag_id": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "tag_name": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "color": schema.StringAttribute{ + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + }, + }, + PlanModifiers: []planmodifier.Set{ + setplanmodifier.UseStateForUnknown(), + }, + }, "transparent_data_encryption": schema.SingleNestedAttribute{ MarkdownDescription: "Transparent Data Encryption (TDE) key", Optional: true, @@ -932,6 +963,15 @@ func readCluster(ctx context.Context, client *api.ClusterClient, tfClusterResour } } + tfClusterResource.Tags = []commonTerraform.Tag{} + for _, v := range responseCluster.Tags { + tfClusterResource.Tags = append(tfClusterResource.Tags, commonTerraform.Tag{ + TagId: types.StringValue(v.TagId), + TagName: types.StringValue(v.TagName), + Color: basetypes.NewStringPointerValue(v.Color), + }) + } + if responseCluster.EncryptionKeyResp != nil { tfClusterResource.TransparentDataEncryption = &TransparentDataEncryptionModel{} tfClusterResource.TransparentDataEncryption.KeyId = types.StringValue(responseCluster.EncryptionKeyResp.KeyId) @@ -1120,6 +1160,16 @@ func (c *clusterResource) generateGenericClusterModel(ctx context.Context, clust } } + tags := []commonApi.Tag{} + for _, tag := range clusterResource.Tags { + tags = append(tags, commonApi.Tag{ + Color: tag.Color.ValueStringPointer(), + TagId: tag.TagId.ValueString(), + TagName: tag.TagName.ValueString(), + }) + } + cluster.Tags = tags + svAccIds, principalIds, err := c.buildRequestBah(ctx, clusterResource) if err != nil { return models.Cluster{}, err diff --git a/pkg/provider/resource_fareplica.go b/pkg/provider/resource_fareplica.go index c416b42d..bd777d57 100644 --- a/pkg/provider/resource_fareplica.go +++ b/pkg/provider/resource_fareplica.go @@ -9,6 +9,8 @@ import ( "github.com/EnterpriseDB/terraform-provider-biganimal/pkg/api" "github.com/EnterpriseDB/terraform-provider-biganimal/pkg/constants" "github.com/EnterpriseDB/terraform-provider-biganimal/pkg/models" + commonApi "github.com/EnterpriseDB/terraform-provider-biganimal/pkg/models/common/api" + commonTerraform "github.com/EnterpriseDB/terraform-provider-biganimal/pkg/models/common/terraform" "github.com/EnterpriseDB/terraform-provider-biganimal/pkg/plan_modifier" "github.com/EnterpriseDB/terraform-provider-biganimal/pkg/utils" "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" @@ -62,6 +64,7 @@ type FAReplicaResourceModel struct { PgIdentity types.String `tfsdk:"pg_identity"` TransparentDataEncryptionAction types.String `tfsdk:"transparent_data_encryption_action"` VolumeSnapshot types.Bool `tfsdk:"volume_snapshot_backup"` + Tags []commonTerraform.Tag `tfsdk:"tags"` Timeouts timeouts.Value `tfsdk:"timeouts"` } @@ -318,8 +321,8 @@ func (r *FAReplicaResource) Schema(ctx context.Context, req resource.SchemaReque Computed: true, Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ - Description: "Cluster architecture ID. For example, \"single\" or \"ha\".For Extreme High Availability clusters, please use the [biganimal_pgd](https://registry.terraform.io/providers/EnterpriseDB/biganimal/latest/docs/resources/pgd) resource.", - Computed: true, + Description: "Cluster architecture ID.", + Required: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, }, "name": schema.StringAttribute{ @@ -329,10 +332,11 @@ func (r *FAReplicaResource) Schema(ctx context.Context, req resource.SchemaReque }, "nodes": schema.Float64Attribute{ Description: "Node count.", - Computed: true, + Required: true, PlanModifiers: []planmodifier.Float64{float64planmodifier.UseStateForUnknown()}, }, }, + PlanModifiers: []planmodifier.Object{objectplanmodifier.UseStateForUnknown()}, }, "pg_version": schema.StringAttribute{ MarkdownDescription: "Postgres version. See [Supported Postgres types and versions](https://www.enterprisedb.com/docs/biganimal/latest/overview/05_database_version_policy/#supported-postgres-types-and-versions) for supported Postgres types and versions.", @@ -387,6 +391,36 @@ func (r *FAReplicaResource) Schema(ctx context.Context, req resource.SchemaReque Optional: true, PlanModifiers: []planmodifier.Bool{boolplanmodifier.UseStateForUnknown()}, }, + "tags": schema.SetNestedAttribute{ + Description: "Assign existing tags or create tags to assign to this resource", + Optional: true, + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "tag_id": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "tag_name": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "color": schema.StringAttribute{ + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + }, + }, + PlanModifiers: []planmodifier.Set{ + setplanmodifier.UseStateForUnknown(), + }, + }, }, } } @@ -657,6 +691,15 @@ func readFAReplica(ctx context.Context, client *api.ClusterClient, fAReplicaReso fAReplicaResourceModel.TransparentDataEncryption.Status = types.StringValue(responseCluster.EncryptionKeyResp.Status) } + fAReplicaResourceModel.Tags = []commonTerraform.Tag{} + for _, v := range responseCluster.Tags { + fAReplicaResourceModel.Tags = append(fAReplicaResourceModel.Tags, commonTerraform.Tag{ + TagId: types.StringValue(v.TagId), + TagName: types.StringValue(v.TagName), + Color: basetypes.NewStringPointerValue(v.Color), + }) + } + return nil } @@ -758,6 +801,16 @@ func (r *FAReplicaResource) generateGenericFAReplicaModel(ctx context.Context, f } } + tags := []commonApi.Tag{} + for _, tag := range fAReplicaResourceModel.Tags { + tags = append(tags, commonApi.Tag{ + Color: tag.Color.ValueStringPointer(), + TagId: tag.TagId.ValueString(), + TagName: tag.TagName.ValueString(), + }) + } + cluster.Tags = tags + return cluster, nil }