From 1f5717cd492ecd62e02e980e841bbf364273ce9c Mon Sep 17 00:00:00 2001 From: wai-wong-edb <119956756+wai-wong-edb@users.noreply.github.com> Date: Tue, 8 Oct 2024 15:39:59 +0100 Subject: [PATCH] feat: tag analytical cluster (#583) * 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: plan modifier for cluster to merge plan with state so it can deal with existing tags when planning * fix: cluster assign tags fix * feat: pgd assign tags * fix: lint fix * fix: examples * feat: project tags assign * fix: planmodifier to use state so it can assign and remove correctly * fix: custom plan modifier * feat: tag analytics cluster * feat: examples and datasource * fix: change example tag name * fix: data source description changes for analytics and faraway replica cluster * fix: example naming --- .../aws/resource.tf | 10 ++ pkg/api/beacon_analytics_client.go | 21 ---- pkg/provider/data_source_analytics_cluster.go | 19 +++- pkg/provider/data_source_fareplica.go | 2 +- pkg/provider/resource_analytics_cluster.go | 99 +++++++++++++------ 5 files changed, 96 insertions(+), 55 deletions(-) delete mode 100644 pkg/api/beacon_analytics_client.go diff --git a/examples/resources/biganimal_analytics_cluster/aws/resource.tf b/examples/resources/biganimal_analytics_cluster/aws/resource.tf index f8b5e123..3fc59d8e 100644 --- a/examples/resources/biganimal_analytics_cluster/aws/resource.tf +++ b/examples/resources/biganimal_analytics_cluster/aws/resource.tf @@ -32,6 +32,16 @@ resource "biganimal_analytics_cluster" "analytics_cluster" { project_id = var.project_id pause = false + #tags = [ + # { + # tag_name = "ex-tag-name" + # color = "blue" + # }, + # { + # tag_name = "ex-tag-name" + # }, + #] + allowed_ip_ranges = [ { cidr_block = "127.0.0.1/32" diff --git a/pkg/api/beacon_analytics_client.go b/pkg/api/beacon_analytics_client.go deleted file mode 100644 index 48768613..00000000 --- a/pkg/api/beacon_analytics_client.go +++ /dev/null @@ -1,21 +0,0 @@ -package api - -import ( - "net/http" - "time" -) - -type BeaconAnalyticsClient struct { - API -} - -func NewBeaconAnalyticsClient(api API) *BeaconAnalyticsClient { - httpClient := http.Client{ - Timeout: clientTimeoutSeconds * time.Second, - } - - api.HTTPClient = httpClient - c := BeaconAnalyticsClient{API: api} - - return &c -} diff --git a/pkg/provider/data_source_analytics_cluster.go b/pkg/provider/data_source_analytics_cluster.go index 317a71d1..f26057b8 100644 --- a/pkg/provider/data_source_analytics_cluster.go +++ b/pkg/provider/data_source_analytics_cluster.go @@ -193,6 +193,23 @@ func (r *analyticsClusterDataSource) Schema(ctx context.Context, req datasource. "Pausing a high availability cluster shuts down all cluster nodes", Optional: true, }, + "tags": schema.SetNestedAttribute{ + Description: "show tags associated with this resource", + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "tag_id": schema.StringAttribute{ + Computed: true, + }, + "tag_name": schema.StringAttribute{ + Computed: true, + }, + "color": schema.StringAttribute{ + Computed: true, + }, + }, + }, + }, }, } } @@ -205,7 +222,7 @@ func (r *analyticsClusterDataSource) Read(ctx context.Context, req datasource.Re return } - if err := read(ctx, r.client, &data.analyticsClusterResourceModel); err != nil { + if err := readAnalyticsCluster(ctx, r.client, &data.analyticsClusterResourceModel); err != nil { if !appendDiagFromBAErr(err, &resp.Diagnostics) { resp.Diagnostics.AddError("Error reading cluster", err.Error()) } diff --git a/pkg/provider/data_source_fareplica.go b/pkg/provider/data_source_fareplica.go index e6c6c864..d3ca9d21 100644 --- a/pkg/provider/data_source_fareplica.go +++ b/pkg/provider/data_source_fareplica.go @@ -255,7 +255,7 @@ func (c *FAReplicaData) Schema(ctx context.Context, req datasource.SchemaRequest Computed: true, }, "tags": schema.SetNestedAttribute{ - Description: "Assign existing tags or create tags to assign to this resource", + Description: "show tags associated with this resource", Computed: true, NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ diff --git a/pkg/provider/resource_analytics_cluster.go b/pkg/provider/resource_analytics_cluster.go index 404af2a5..51ec7a29 100644 --- a/pkg/provider/resource_analytics_cluster.go +++ b/pkg/provider/resource_analytics_cluster.go @@ -59,6 +59,7 @@ type analyticsClusterResourceModel struct { ServiceAccountIds types.Set `tfsdk:"service_account_ids"` PeAllowedPrincipalIds types.Set `tfsdk:"pe_allowed_principal_ids"` Pause types.Bool `tfsdk:"pause"` + Tags []commonTerraform.Tag `tfsdk:"tags"` Timeouts timeouts.Value `tfsdk:"timeouts"` } @@ -270,6 +271,36 @@ func (r *analyticsClusterResource) Schema(ctx context.Context, req resource.Sche 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{ + plan_modifier.CustomAssignTags(), + }, + }, }, } } @@ -335,7 +366,7 @@ func (r *analyticsClusterResource) Create(ctx context.Context, req resource.Crea } // after cluster is in the correct state (healthy/paused) then get the cluster and save into state - if err := read(ctx, r.client, &config); err != nil { + if err := readAnalyticsCluster(ctx, r.client, &config); err != nil { if !appendDiagFromBAErr(err, &resp.Diagnostics) { resp.Diagnostics.AddError("Error reading cluster", err.Error()) } @@ -445,11 +476,13 @@ func generateAnalyticsClusterModelCreate(ctx context.Context, client *api.Cluste } } + cluster.Tags = buildAPIReqAssignTags(clusterResource.Tags) + return cluster, nil } -func read(ctx context.Context, client *api.ClusterClient, tfClusterResource *analyticsClusterResourceModel) error { - apiCluster, err := client.Read(ctx, tfClusterResource.ProjectId, *tfClusterResource.ClusterId) +func readAnalyticsCluster(ctx context.Context, client *api.ClusterClient, tfClusterResource *analyticsClusterResourceModel) error { + responseCluster, err := client.Read(ctx, tfClusterResource.ProjectId, *tfClusterResource.ClusterId) if err != nil { return err } @@ -460,29 +493,29 @@ func read(ctx context.Context, client *api.ClusterClient, tfClusterResource *ana } tfClusterResource.ID = types.StringValue(fmt.Sprintf("%s/%s", tfClusterResource.ProjectId, *tfClusterResource.ClusterId)) - tfClusterResource.ClusterId = apiCluster.ClusterId - tfClusterResource.ClusterName = types.StringPointerValue(apiCluster.ClusterName) - tfClusterResource.Phase = apiCluster.Phase - tfClusterResource.CloudProvider = types.StringValue(apiCluster.Provider.CloudProviderId) - tfClusterResource.Region = types.StringValue(apiCluster.Region.Id) - tfClusterResource.InstanceType = types.StringValue(apiCluster.InstanceType.InstanceTypeId) - tfClusterResource.ResizingPvc = StringSliceToList(apiCluster.ResizingPvc) + tfClusterResource.ClusterId = responseCluster.ClusterId + tfClusterResource.ClusterName = types.StringPointerValue(responseCluster.ClusterName) + tfClusterResource.Phase = responseCluster.Phase + tfClusterResource.CloudProvider = types.StringValue(responseCluster.Provider.CloudProviderId) + tfClusterResource.Region = types.StringValue(responseCluster.Region.Id) + tfClusterResource.InstanceType = types.StringValue(responseCluster.InstanceType.InstanceTypeId) + tfClusterResource.ResizingPvc = StringSliceToList(responseCluster.ResizingPvc) tfClusterResource.ConnectionUri = types.StringPointerValue(&connection.PgUri) - tfClusterResource.CspAuth = types.BoolPointerValue(apiCluster.CSPAuth) - tfClusterResource.LogsUrl = apiCluster.LogsUrl - tfClusterResource.MetricsUrl = apiCluster.MetricsUrl - tfClusterResource.BackupRetentionPeriod = types.StringPointerValue(apiCluster.BackupRetentionPeriod) - tfClusterResource.PgVersion = types.StringValue(apiCluster.PgVersion.PgVersionId) - tfClusterResource.PgType = types.StringValue(apiCluster.PgType.PgTypeId) - tfClusterResource.PrivateNetworking = types.BoolPointerValue(apiCluster.PrivateNetworking) - - if apiCluster.FirstRecoverabilityPointAt != nil { - firstPointAt := apiCluster.FirstRecoverabilityPointAt.String() + tfClusterResource.CspAuth = types.BoolPointerValue(responseCluster.CSPAuth) + tfClusterResource.LogsUrl = responseCluster.LogsUrl + tfClusterResource.MetricsUrl = responseCluster.MetricsUrl + tfClusterResource.BackupRetentionPeriod = types.StringPointerValue(responseCluster.BackupRetentionPeriod) + tfClusterResource.PgVersion = types.StringValue(responseCluster.PgVersion.PgVersionId) + tfClusterResource.PgType = types.StringValue(responseCluster.PgType.PgTypeId) + tfClusterResource.PrivateNetworking = types.BoolPointerValue(responseCluster.PrivateNetworking) + + if responseCluster.FirstRecoverabilityPointAt != nil { + firstPointAt := responseCluster.FirstRecoverabilityPointAt.String() tfClusterResource.FirstRecoverabilityPointAt = &firstPointAt } tfClusterResource.AllowedIpRanges = []AllowedIpRangesResourceModel{} - if allowedIpRanges := apiCluster.AllowedIpRanges; allowedIpRanges != nil { + if allowedIpRanges := responseCluster.AllowedIpRanges; allowedIpRanges != nil { for _, ipRange := range *allowedIpRanges { tfClusterResource.AllowedIpRanges = append(tfClusterResource.AllowedIpRanges, AllowedIpRangesResourceModel{ CidrBlock: ipRange.CidrBlock, @@ -491,26 +524,28 @@ func read(ctx context.Context, client *api.ClusterClient, tfClusterResource *ana } } - if pt := apiCluster.CreatedAt; pt != nil { + if pt := responseCluster.CreatedAt; pt != nil { tfClusterResource.CreatedAt = types.StringValue(pt.String()) } - if apiCluster.MaintenanceWindow != nil { + if responseCluster.MaintenanceWindow != nil { tfClusterResource.MaintenanceWindow = &commonTerraform.MaintenanceWindow{ - IsEnabled: apiCluster.MaintenanceWindow.IsEnabled, - StartDay: types.Int64PointerValue(utils.ToPointer(int64(*apiCluster.MaintenanceWindow.StartDay))), - StartTime: types.StringPointerValue(apiCluster.MaintenanceWindow.StartTime), + IsEnabled: responseCluster.MaintenanceWindow.IsEnabled, + StartDay: types.Int64PointerValue(utils.ToPointer(int64(*responseCluster.MaintenanceWindow.StartDay))), + StartTime: types.StringPointerValue(responseCluster.MaintenanceWindow.StartTime), } } - if apiCluster.PeAllowedPrincipalIds != nil { - tfClusterResource.PeAllowedPrincipalIds = StringSliceToSet(utils.ToValue(&apiCluster.PeAllowedPrincipalIds)) + if responseCluster.PeAllowedPrincipalIds != nil { + tfClusterResource.PeAllowedPrincipalIds = StringSliceToSet(utils.ToValue(&responseCluster.PeAllowedPrincipalIds)) } - if apiCluster.ServiceAccountIds != nil { - tfClusterResource.ServiceAccountIds = StringSliceToSet(utils.ToValue(&apiCluster.ServiceAccountIds)) + if responseCluster.ServiceAccountIds != nil { + tfClusterResource.ServiceAccountIds = StringSliceToSet(utils.ToValue(&responseCluster.ServiceAccountIds)) } + buildTFRsrcAssignTagsAs(&tfClusterResource.Tags, responseCluster.Tags) + return nil } @@ -522,7 +557,7 @@ func (r *analyticsClusterResource) Read(ctx context.Context, req resource.ReadRe return } - if err := read(ctx, r.client, &state); err != nil { + if err := readAnalyticsCluster(ctx, r.client, &state); err != nil { if !appendDiagFromBAErr(err, &resp.Diagnostics) { resp.Diagnostics.AddError("Error reading cluster", err.Error()) } @@ -628,7 +663,7 @@ func (r *analyticsClusterResource) Update(ctx context.Context, req resource.Upda } } - if err := read(ctx, r.client, &plan); err != nil { + if err := readAnalyticsCluster(ctx, r.client, &plan); err != nil { if !appendDiagFromBAErr(err, &resp.Diagnostics) { resp.Diagnostics.AddError("Error reading cluster", err.Error()) }