From cc4a760054385be566044b958a2cb5ce3ddf77f2 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Tue, 13 Aug 2024 15:55:21 +0100 Subject: [PATCH 1/5] add singular data source schema --- go.mod | 2 +- go.sum | 4 +- .../data_source.go | 48 +++++++++++++++++ .../data_source_schema.go | 54 +++++++++++++++++++ .../tfplugingen/generator_config.yml | 11 +++- 5 files changed, 115 insertions(+), 4 deletions(-) create mode 100644 internal/service/encryptionatrestprivateendpoint/data_source.go create mode 100644 internal/service/encryptionatrestprivateendpoint/data_source_schema.go diff --git a/go.mod b/go.mod index 11e45eaffb..e7f9b831f1 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/zclconf/go-cty v1.15.0 go.mongodb.org/atlas v0.36.0 go.mongodb.org/atlas-sdk/v20240530005 v20240530005.0.0 - go.mongodb.org/atlas-sdk/v20240805001 v20240805001.0.1-0.20240809201355-5fc86d455f4c + go.mongodb.org/atlas-sdk/v20240805001 v20240805001.0.1-0.20240813143344-1cfe40386cbc go.mongodb.org/realm v0.1.0 ) diff --git a/go.sum b/go.sum index 6e55e5623c..ed0d3c50fe 100644 --- a/go.sum +++ b/go.sum @@ -782,8 +782,8 @@ go.mongodb.org/atlas v0.36.0 h1:m05S3AO7zkl+bcG1qaNsEKBnAqnKx2FDwLooHpIG3j4= go.mongodb.org/atlas v0.36.0/go.mod h1:nfPldE9dSama6G2IbIzmEza02Ly7yFZjMMVscaM0uEc= go.mongodb.org/atlas-sdk/v20240530005 v20240530005.0.0 h1:d/gbYJ+obR0EM/3DZf7+ZMi2QWISegm3mid7Or708cc= go.mongodb.org/atlas-sdk/v20240530005 v20240530005.0.0/go.mod h1:O47ZrMMfcWb31wznNIq2PQkkdoFoK0ea2GlmRqGJC2s= -go.mongodb.org/atlas-sdk/v20240805001 v20240805001.0.1-0.20240809201355-5fc86d455f4c h1:8mh2UocF0IYCc0tr4oWGrIEcuc7PqLg6GgHMFgN4fWU= -go.mongodb.org/atlas-sdk/v20240805001 v20240805001.0.1-0.20240809201355-5fc86d455f4c/go.mod h1:0aHEphVfsYbpg3CiEUcXeAU7OVoOFig1tltXdLjYiSQ= +go.mongodb.org/atlas-sdk/v20240805001 v20240805001.0.1-0.20240813143344-1cfe40386cbc h1:ZZOXzXjt9PMOx1tKz76aenAikF6n5f8qvitaarDWJ9Q= +go.mongodb.org/atlas-sdk/v20240805001 v20240805001.0.1-0.20240813143344-1cfe40386cbc/go.mod h1:0aHEphVfsYbpg3CiEUcXeAU7OVoOFig1tltXdLjYiSQ= go.mongodb.org/realm v0.1.0 h1:zJiXyLaZrznQ+Pz947ziSrDKUep39DO4SfA0Fzx8M4M= go.mongodb.org/realm v0.1.0/go.mod h1:4Vj6iy+Puo1TDERcoh4XZ+pjtwbOzPpzqy3Cwe8ZmDM= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= diff --git a/internal/service/encryptionatrestprivateendpoint/data_source.go b/internal/service/encryptionatrestprivateendpoint/data_source.go new file mode 100644 index 0000000000..5bccd2ebc2 --- /dev/null +++ b/internal/service/encryptionatrestprivateendpoint/data_source.go @@ -0,0 +1,48 @@ +//nolint:gocritic +package encryptionatrestprivateendpoint + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + + "github.com/mongodb/terraform-provider-mongodbatlas/internal/config" +) + +var _ datasource.DataSource = &encryptionAtRestPrivateEndpointDS{} +var _ datasource.DataSourceWithConfigure = &encryptionAtRestPrivateEndpointDS{} + +func DataSource() datasource.DataSource { + return &encryptionAtRestPrivateEndpointDS{ + DSCommon: config.DSCommon{ + DataSourceName: encryptionAtRestPrivateEndpointName, + }, + } +} + +type encryptionAtRestPrivateEndpointDS struct { + config.DSCommon +} + +func (d *encryptionAtRestPrivateEndpointDS) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = DataSourceSchema(ctx) +} + +func (d *encryptionAtRestPrivateEndpointDS) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var earPrivateEndpointConfig TFEarPrivateEndpointModel + resp.Diagnostics.Append(req.Config.Get(ctx, &earPrivateEndpointConfig)...) + if resp.Diagnostics.HasError() { + return + } + + // TODO: make get request to resource + + // connV2 := d.Client.AtlasV2 + // if err != nil { + // resp.Diagnostics.AddError("error fetching resource", err.Error()) + // return + //} + + // TODO: process response into new terraform state + // resp.Diagnostics.Append(resp.State.Set(ctx, NewTFEarPrivateEndpoint(apiResp))...) +} diff --git a/internal/service/encryptionatrestprivateendpoint/data_source_schema.go b/internal/service/encryptionatrestprivateendpoint/data_source_schema.go new file mode 100644 index 0000000000..08f0a5c66a --- /dev/null +++ b/internal/service/encryptionatrestprivateendpoint/data_source_schema.go @@ -0,0 +1,54 @@ +package encryptionatrestprivateendpoint + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" +) + +func DataSourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "cloud_provider": schema.StringAttribute{ + Required: true, + Description: "Human-readable label that identifies the cloud provider of the private endpoint.", + MarkdownDescription: "Human-readable label that identifies the cloud provider of the private endpoint.", + }, + "endpoint_id": schema.StringAttribute{ + Required: true, + Description: "Unique 24-hexadecimal digit string that identifies the private endpoint.", + MarkdownDescription: "Unique 24-hexadecimal digit string that identifies the private endpoint.", + }, + "error_message": schema.StringAttribute{ + Computed: true, + Description: "Error message for failures associated with the Encryption At Rest private endpoint.", + MarkdownDescription: "Error message for failures associated with the Encryption At Rest private endpoint.", + }, + "project_id": schema.StringAttribute{ + Required: true, + Description: "Unique 24-hexadecimal digit string that identifies your project. Use the [/groups](#tag/Projects/operation/listProjects) endpoint to retrieve all projects to which the authenticated user has access.\n\n**NOTE**: Groups and projects are synonymous terms. Your group id is the same as your project id. For existing groups, your group/project id remains the same. The resource and corresponding endpoints use the term groups.", + MarkdownDescription: "Unique 24-hexadecimal digit string that identifies your project. Use the [/groups](#tag/Projects/operation/listProjects) endpoint to retrieve all projects to which the authenticated user has access.\n\n**NOTE**: Groups and projects are synonymous terms. Your group id is the same as your project id. For existing groups, your group/project id remains the same. The resource and corresponding endpoints use the term groups.", + }, + "id": schema.StringAttribute{ + Computed: true, + Description: "Unique 24-hexadecimal digit string that identifies the Private Endpoint Service.", + MarkdownDescription: "Unique 24-hexadecimal digit string that identifies the Private Endpoint Service.", + }, + "private_endpoint_connection_name": schema.StringAttribute{ + Computed: true, + Description: "Connection name of the Azure Private Endpoint.", + MarkdownDescription: "Connection name of the Azure Private Endpoint.", + }, + "region_name": schema.StringAttribute{ + Computed: true, + Description: "Cloud provider region in which the Encryption At Rest private endpoint is located.", + MarkdownDescription: "Cloud provider region in which the Encryption At Rest private endpoint is located.", + }, + "status": schema.StringAttribute{ + Computed: true, + Description: "State of the Encryption At Rest private endpoint.", + MarkdownDescription: "State of the Encryption At Rest private endpoint.", + }, + }, + } +} diff --git a/internal/service/encryptionatrestprivateendpoint/tfplugingen/generator_config.yml b/internal/service/encryptionatrestprivateendpoint/tfplugingen/generator_config.yml index a873e539fd..58d292fc60 100644 --- a/internal/service/encryptionatrestprivateendpoint/tfplugingen/generator_config.yml +++ b/internal/service/encryptionatrestprivateendpoint/tfplugingen/generator_config.yml @@ -2,7 +2,7 @@ provider: name: mongodbatlas resources: - encryptionatrestprivateendpoint: + encryption_at_rest_private_endpoint: read: path: /api/atlas/v2/groups/{groupId}/encryptionAtRest/{cloudProvider}/privateEndpoints/{endpointId} method: GET @@ -13,3 +13,12 @@ resources: path: /api/atlas/v2/groups/{groupId}/encryptionAtRest/{cloudProvider}/privateEndpoints/{endpointId} method: DELETE +data_sources: + encryption_at_rest_private_endpoint: + read: + path: /api/atlas/v2/groups/{groupId}/encryptionAtRest/{cloudProvider}/privateEndpoints/{endpointId} + method: GET + # encryption_at_rest_private_endpoints: + # read: + # path: /api/atlas/v2/groups/{groupId}/encryptionAtRest/{cloudProvider}/privateEndpoints + # method: GET \ No newline at end of file From f950c48d609d33131a09aa0fe22df48144d77bd8 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Tue, 13 Aug 2024 17:23:47 +0100 Subject: [PATCH 2/5] update provider --- internal/provider/provider.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 8dd43e6014..dc16a595d5 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -435,7 +435,9 @@ func (p *MongodbtlasProvider) DataSources(context.Context) []func() datasource.D streamconnection.PluralDataSource, controlplaneipaddresses.DataSource, } - previewDataSources := []func() datasource.DataSource{} // Data sources not yet in GA + previewDataSources := []func() datasource.DataSource{ // Data sources not yet in GA + encryptionatrestprivateendpoint.DataSource, + } if providerEnablePreview { dataSources = append(dataSources, previewDataSources...) } From 851d723d5b14feb302ef2279d5e665575b47c8cc Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Tue, 13 Aug 2024 17:26:33 +0100 Subject: [PATCH 3/5] add initial schema --- internal/provider/provider.go | 1 + .../plural_data_source.go | 53 ++ .../pural_data_source_schema.go | 688 ++++++++++++++++++ 3 files changed, 742 insertions(+) create mode 100644 internal/service/encryptionatrestprivateendpoint/plural_data_source.go create mode 100644 internal/service/encryptionatrestprivateendpoint/pural_data_source_schema.go diff --git a/internal/provider/provider.go b/internal/provider/provider.go index dc16a595d5..73ed20a0c1 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -437,6 +437,7 @@ func (p *MongodbtlasProvider) DataSources(context.Context) []func() datasource.D } previewDataSources := []func() datasource.DataSource{ // Data sources not yet in GA encryptionatrestprivateendpoint.DataSource, + encryptionatrestprivateendpoint.PluralDataSource, } if providerEnablePreview { dataSources = append(dataSources, previewDataSources...) diff --git a/internal/service/encryptionatrestprivateendpoint/plural_data_source.go b/internal/service/encryptionatrestprivateendpoint/plural_data_source.go new file mode 100644 index 0000000000..0795ecc55e --- /dev/null +++ b/internal/service/encryptionatrestprivateendpoint/plural_data_source.go @@ -0,0 +1,53 @@ +package encryptionatrestprivateendpoint + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + + "github.com/mongodb/terraform-provider-mongodbatlas/internal/config" +) + +var _ datasource.DataSource = &encryptionAtRestPrivateEndpointsDS{} +var _ datasource.DataSourceWithConfigure = &encryptionAtRestPrivateEndpointsDS{} + +func PluralDataSource() datasource.DataSource { + return &encryptionAtRestPrivateEndpointsDS{ + DSCommon: config.DSCommon{ + DataSourceName: fmt.Sprintf("%ss", encryptionAtRestPrivateEndpointName), + }, + } +} + +type encryptionAtRestPrivateEndpointsDS struct { + config.DSCommon +} + +func (d *encryptionAtRestPrivateEndpointsDS) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = PluralDataSourceSchema(ctx) +} + +func (d *encryptionAtRestPrivateEndpointsDS) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var encryptionAtRestPrivateEndpointsConfig TFEncryptionAtRestPrivateEndpointsDSModel + resp.Diagnostics.Append(req.Config.Get(ctx, &encryptionAtRestPrivateEndpointsConfig)...) + if resp.Diagnostics.HasError() { + return + } + + // TODO: make get request to obtain list of results + + // connV2 := r.Client.AtlasV2 + // if err != nil { + // resp.Diagnostics.AddError("error fetching results", err.Error()) + // return + //} + + // TODO: process response into new terraform state + // newEncryptionAtRestPrivateEndpointsModel, diags := NewTFEncryptionAtRestPrivateEndpoints(ctx, apiResp) + // if diags.HasError() { + // resp.Diagnostics.Append(diags...) + // return + // } + // resp.Diagnostics.Append(resp.State.Set(ctx, newEncryptionAtRestPrivateEndpointsModel)...) +} diff --git a/internal/service/encryptionatrestprivateendpoint/pural_data_source_schema.go b/internal/service/encryptionatrestprivateendpoint/pural_data_source_schema.go new file mode 100644 index 0000000000..f829031f95 --- /dev/null +++ b/internal/service/encryptionatrestprivateendpoint/pural_data_source_schema.go @@ -0,0 +1,688 @@ +// Code generated by terraform-plugin-framework-generator DO NOT EDIT. + +package encryptionatrestprivateendpoint + +import ( + "context" + "strings" + "fmt" + + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" +) + +func PluralDataSourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "cloud_provider": schema.StringAttribute{ + Required: true, + Description: "Human-readable label that identifies the cloud provider for the private endpoints to return.", + MarkdownDescription: "Human-readable label that identifies the cloud provider for the private endpoints to return.", + }, + "group_id": schema.StringAttribute{ + Required: true, + Description: "Unique 24-hexadecimal digit string that identifies your project. Use the [/groups](#tag/Projects/operation/listProjects) endpoint to retrieve all projects to which the authenticated user has access.\n\n**NOTE**: Groups and projects are synonymous terms. Your group id is the same as your project id. For existing groups, your group/project id remains the same. The resource and corresponding endpoints use the term groups.", + MarkdownDescription: "Unique 24-hexadecimal digit string that identifies your project. Use the [/groups](#tag/Projects/operation/listProjects) endpoint to retrieve all projects to which the authenticated user has access.\n\n**NOTE**: Groups and projects are synonymous terms. Your group id is the same as your project id. For existing groups, your group/project id remains the same. The resource and corresponding endpoints use the term groups.", + }, + "results": schema.ListNestedAttribute{ + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "cloud_provider": schema.StringAttribute{ + Computed: true, + Description: "Human-readable label that identifies the cloud provider for the Encryption At Rest private endpoint.", + MarkdownDescription: "Human-readable label that identifies the cloud provider for the Encryption At Rest private endpoint.", + }, + "error_message": schema.StringAttribute{ + Computed: true, + Description: "Error message for failures associated with the Encryption At Rest private endpoint.", + MarkdownDescription: "Error message for failures associated with the Encryption At Rest private endpoint.", + }, + "id": schema.StringAttribute{ + Computed: true, + Description: "Unique 24-hexadecimal digit string that identifies the Private Endpoint Service.", + MarkdownDescription: "Unique 24-hexadecimal digit string that identifies the Private Endpoint Service.", + }, + "private_endpoint_connection_name": schema.StringAttribute{ + Computed: true, + Description: "Connection name of the Azure Private Endpoint.", + MarkdownDescription: "Connection name of the Azure Private Endpoint.", + }, + "region_name": schema.StringAttribute{ + Computed: true, + Description: "Cloud provider region in which the Encryption At Rest private endpoint is located.", + MarkdownDescription: "Cloud provider region in which the Encryption At Rest private endpoint is located.", + }, + "status": schema.StringAttribute{ + Computed: true, + Description: "State of the Encryption At Rest private endpoint.", + MarkdownDescription: "State of the Encryption At Rest private endpoint.", + }, + }, + CustomType: ResultsType{ + ObjectType: types.ObjectType{ + AttrTypes: ResultsValue{}.AttributeTypes(ctx), + }, + }, + }, + Computed: true, + Description: "List of returned documents that MongoDB Cloud providers when completing this request.", + MarkdownDescription: "List of returned documents that MongoDB Cloud providers when completing this request.", + }, + "total_count": schema.Int64Attribute{ + Computed: true, + Description: "Total number of documents available. MongoDB Cloud omits this value if `includeCount` is set to `false`.", + MarkdownDescription: "Total number of documents available. MongoDB Cloud omits this value if `includeCount` is set to `false`.", + }, + }, + } +} + +type TFEncryptionAtRestPrivateEndpointsDSModel struct { + CloudProvider types.String `tfsdk:"cloud_provider"` + GroupId types.String `tfsdk:"group_id"` + Results types.List `tfsdk:"results"` + TotalCount types.Int64 `tfsdk:"total_count"` +} + +var _ basetypes.ObjectTypable = ResultsType{} + +type ResultsType struct { + basetypes.ObjectType +} + +func (t ResultsType) Equal(o attr.Type) bool { + other, ok := o.(ResultsType) + + if !ok { + return false + } + + return t.ObjectType.Equal(other.ObjectType) +} + +func (t ResultsType) String() string { + return "ResultsType" +} + +func (t ResultsType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { + var diags diag.Diagnostics + + attributes := in.Attributes() + + cloudProviderAttribute, ok := attributes["cloud_provider"] + + if !ok { + diags.AddError( + "Attribute Missing", + `cloud_provider is missing from object`) + + return nil, diags + } + + cloudProviderVal, ok := cloudProviderAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`cloud_provider expected to be basetypes.StringValue, was: %T`, cloudProviderAttribute)) + } + + errorMessageAttribute, ok := attributes["error_message"] + + if !ok { + diags.AddError( + "Attribute Missing", + `error_message is missing from object`) + + return nil, diags + } + + errorMessageVal, ok := errorMessageAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`error_message expected to be basetypes.StringValue, was: %T`, errorMessageAttribute)) + } + + idAttribute, ok := attributes["id"] + + if !ok { + diags.AddError( + "Attribute Missing", + `id is missing from object`) + + return nil, diags + } + + idVal, ok := idAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`id expected to be basetypes.StringValue, was: %T`, idAttribute)) + } + + privateEndpointConnectionNameAttribute, ok := attributes["private_endpoint_connection_name"] + + if !ok { + diags.AddError( + "Attribute Missing", + `private_endpoint_connection_name is missing from object`) + + return nil, diags + } + + privateEndpointConnectionNameVal, ok := privateEndpointConnectionNameAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`private_endpoint_connection_name expected to be basetypes.StringValue, was: %T`, privateEndpointConnectionNameAttribute)) + } + + regionNameAttribute, ok := attributes["region_name"] + + if !ok { + diags.AddError( + "Attribute Missing", + `region_name is missing from object`) + + return nil, diags + } + + regionNameVal, ok := regionNameAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`region_name expected to be basetypes.StringValue, was: %T`, regionNameAttribute)) + } + + statusAttribute, ok := attributes["status"] + + if !ok { + diags.AddError( + "Attribute Missing", + `status is missing from object`) + + return nil, diags + } + + statusVal, ok := statusAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`status expected to be basetypes.StringValue, was: %T`, statusAttribute)) + } + + if diags.HasError() { + return nil, diags + } + + return ResultsValue{ + CloudProvider: cloudProviderVal, + ErrorMessage: errorMessageVal, + Id: idVal, + PrivateEndpointConnectionName: privateEndpointConnectionNameVal, + RegionName: regionNameVal, + Status: statusVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewResultsValueNull() ResultsValue { + return ResultsValue{ + state: attr.ValueStateNull, + } +} + +func NewResultsValueUnknown() ResultsValue { + return ResultsValue{ + state: attr.ValueStateUnknown, + } +} + +func NewResultsValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (ResultsValue, diag.Diagnostics) { + var diags diag.Diagnostics + + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 + ctx := context.Background() + + for name, attributeType := range attributeTypes { + attribute, ok := attributes[name] + + if !ok { + diags.AddError( + "Missing ResultsValue Attribute Value", + "While creating a ResultsValue value, a missing attribute value was detected. "+ + "A ResultsValue must contain values for all attributes, even if null or unknown. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("ResultsValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), + ) + + continue + } + + if !attributeType.Equal(attribute.Type(ctx)) { + diags.AddError( + "Invalid ResultsValue Attribute Type", + "While creating a ResultsValue value, an invalid attribute value was detected. "+ + "A ResultsValue must use a matching attribute type for the value. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("ResultsValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ + fmt.Sprintf("ResultsValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), + ) + } + } + + for name := range attributes { + _, ok := attributeTypes[name] + + if !ok { + diags.AddError( + "Extra ResultsValue Attribute Value", + "While creating a ResultsValue value, an extra attribute value was detected. "+ + "A ResultsValue must not contain values beyond the expected attribute types. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Extra ResultsValue Attribute Name: %s", name), + ) + } + } + + if diags.HasError() { + return NewResultsValueUnknown(), diags + } + + cloudProviderAttribute, ok := attributes["cloud_provider"] + + if !ok { + diags.AddError( + "Attribute Missing", + `cloud_provider is missing from object`) + + return NewResultsValueUnknown(), diags + } + + cloudProviderVal, ok := cloudProviderAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`cloud_provider expected to be basetypes.StringValue, was: %T`, cloudProviderAttribute)) + } + + errorMessageAttribute, ok := attributes["error_message"] + + if !ok { + diags.AddError( + "Attribute Missing", + `error_message is missing from object`) + + return NewResultsValueUnknown(), diags + } + + errorMessageVal, ok := errorMessageAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`error_message expected to be basetypes.StringValue, was: %T`, errorMessageAttribute)) + } + + idAttribute, ok := attributes["id"] + + if !ok { + diags.AddError( + "Attribute Missing", + `id is missing from object`) + + return NewResultsValueUnknown(), diags + } + + idVal, ok := idAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`id expected to be basetypes.StringValue, was: %T`, idAttribute)) + } + + privateEndpointConnectionNameAttribute, ok := attributes["private_endpoint_connection_name"] + + if !ok { + diags.AddError( + "Attribute Missing", + `private_endpoint_connection_name is missing from object`) + + return NewResultsValueUnknown(), diags + } + + privateEndpointConnectionNameVal, ok := privateEndpointConnectionNameAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`private_endpoint_connection_name expected to be basetypes.StringValue, was: %T`, privateEndpointConnectionNameAttribute)) + } + + regionNameAttribute, ok := attributes["region_name"] + + if !ok { + diags.AddError( + "Attribute Missing", + `region_name is missing from object`) + + return NewResultsValueUnknown(), diags + } + + regionNameVal, ok := regionNameAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`region_name expected to be basetypes.StringValue, was: %T`, regionNameAttribute)) + } + + statusAttribute, ok := attributes["status"] + + if !ok { + diags.AddError( + "Attribute Missing", + `status is missing from object`) + + return NewResultsValueUnknown(), diags + } + + statusVal, ok := statusAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`status expected to be basetypes.StringValue, was: %T`, statusAttribute)) + } + + if diags.HasError() { + return NewResultsValueUnknown(), diags + } + + return ResultsValue{ + CloudProvider: cloudProviderVal, + ErrorMessage: errorMessageVal, + Id: idVal, + PrivateEndpointConnectionName: privateEndpointConnectionNameVal, + RegionName: regionNameVal, + Status: statusVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewResultsValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) ResultsValue { + object, diags := NewResultsValue(attributeTypes, attributes) + + if diags.HasError() { + // This could potentially be added to the diag package. + diagsStrings := make([]string, 0, len(diags)) + + for _, diagnostic := range diags { + diagsStrings = append(diagsStrings, fmt.Sprintf( + "%s | %s | %s", + diagnostic.Severity(), + diagnostic.Summary(), + diagnostic.Detail())) + } + + panic("NewResultsValueMust received error(s): " + strings.Join(diagsStrings, "\n")) + } + + return object +} + +func (t ResultsType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + if in.Type() == nil { + return NewResultsValueNull(), nil + } + + if !in.Type().Equal(t.TerraformType(ctx)) { + return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) + } + + if !in.IsKnown() { + return NewResultsValueUnknown(), nil + } + + if in.IsNull() { + return NewResultsValueNull(), nil + } + + attributes := map[string]attr.Value{} + + val := map[string]tftypes.Value{} + + err := in.As(&val) + + if err != nil { + return nil, err + } + + for k, v := range val { + a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) + + if err != nil { + return nil, err + } + + attributes[k] = a + } + + return NewResultsValueMust(ResultsValue{}.AttributeTypes(ctx), attributes), nil +} + +func (t ResultsType) ValueType(ctx context.Context) attr.Value { + return ResultsValue{} +} + +var _ basetypes.ObjectValuable = ResultsValue{} + +type ResultsValue struct { + CloudProvider basetypes.StringValue `tfsdk:"cloud_provider"` + ErrorMessage basetypes.StringValue `tfsdk:"error_message"` + Id basetypes.StringValue `tfsdk:"id"` + PrivateEndpointConnectionName basetypes.StringValue `tfsdk:"private_endpoint_connection_name"` + RegionName basetypes.StringValue `tfsdk:"region_name"` + Status basetypes.StringValue `tfsdk:"status"` + state attr.ValueState +} + +func (v ResultsValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + attrTypes := make(map[string]tftypes.Type, 6) + + var val tftypes.Value + var err error + + attrTypes["cloud_provider"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["error_message"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["id"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["private_endpoint_connection_name"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["region_name"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["status"] = basetypes.StringType{}.TerraformType(ctx) + + objectType := tftypes.Object{AttributeTypes: attrTypes} + + switch v.state { + case attr.ValueStateKnown: + vals := make(map[string]tftypes.Value, 6) + + val, err = v.CloudProvider.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["cloud_provider"] = val + + val, err = v.ErrorMessage.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["error_message"] = val + + val, err = v.Id.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["id"] = val + + val, err = v.PrivateEndpointConnectionName.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["private_endpoint_connection_name"] = val + + val, err = v.RegionName.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["region_name"] = val + + val, err = v.Status.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["status"] = val + + if err := tftypes.ValidateValue(objectType, vals); err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + return tftypes.NewValue(objectType, vals), nil + case attr.ValueStateNull: + return tftypes.NewValue(objectType, nil), nil + case attr.ValueStateUnknown: + return tftypes.NewValue(objectType, tftypes.UnknownValue), nil + default: + panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) + } +} + +func (v ResultsValue) IsNull() bool { + return v.state == attr.ValueStateNull +} + +func (v ResultsValue) IsUnknown() bool { + return v.state == attr.ValueStateUnknown +} + +func (v ResultsValue) String() string { + return "ResultsValue" +} + +func (v ResultsValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { + var diags diag.Diagnostics + + attributeTypes := map[string]attr.Type{ + "cloud_provider": basetypes.StringType{}, + "error_message": basetypes.StringType{}, + "id": basetypes.StringType{}, + "private_endpoint_connection_name": basetypes.StringType{}, + "region_name": basetypes.StringType{}, + "status": basetypes.StringType{}, + } + + if v.IsNull() { + return types.ObjectNull(attributeTypes), diags + } + + if v.IsUnknown() { + return types.ObjectUnknown(attributeTypes), diags + } + + objVal, diags := types.ObjectValue( + attributeTypes, + map[string]attr.Value{ + "cloud_provider": v.CloudProvider, + "error_message": v.ErrorMessage, + "id": v.Id, + "private_endpoint_connection_name": v.PrivateEndpointConnectionName, + "region_name": v.RegionName, + "status": v.Status, + }) + + return objVal, diags +} + +func (v ResultsValue) Equal(o attr.Value) bool { + other, ok := o.(ResultsValue) + + if !ok { + return false + } + + if v.state != other.state { + return false + } + + if v.state != attr.ValueStateKnown { + return true + } + + if !v.CloudProvider.Equal(other.CloudProvider) { + return false + } + + if !v.ErrorMessage.Equal(other.ErrorMessage) { + return false + } + + if !v.Id.Equal(other.Id) { + return false + } + + if !v.PrivateEndpointConnectionName.Equal(other.PrivateEndpointConnectionName) { + return false + } + + if !v.RegionName.Equal(other.RegionName) { + return false + } + + if !v.Status.Equal(other.Status) { + return false + } + + return true +} + +func (v ResultsValue) Type(ctx context.Context) attr.Type { + return ResultsType{ + basetypes.ObjectType{ + AttrTypes: v.AttributeTypes(ctx), + }, + } +} + +func (v ResultsValue) AttributeTypes(ctx context.Context) map[string]attr.Type { + return map[string]attr.Type{ + "cloud_provider": basetypes.StringType{}, + "error_message": basetypes.StringType{}, + "id": basetypes.StringType{}, + "private_endpoint_connection_name": basetypes.StringType{}, + "region_name": basetypes.StringType{}, + "status": basetypes.StringType{}, + } +} From 40ec9d1fc664108e028b407b05efee521783eacf Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Wed, 14 Aug 2024 11:33:28 +0100 Subject: [PATCH 4/5] update models, add unit tests --- .../data_source_schema.go | 7 +- .../encryptionatrestprivateendpoint/model.go | 8 +- .../model_test.go | 73 +- .../plural_data_source.go | 9 +- .../pural_data_source_schema.go | 642 +----------------- .../resource_schema.go | 6 - 6 files changed, 117 insertions(+), 628 deletions(-) diff --git a/internal/service/encryptionatrestprivateendpoint/data_source_schema.go b/internal/service/encryptionatrestprivateendpoint/data_source_schema.go index 08f0a5c66a..cf4b2c0df6 100644 --- a/internal/service/encryptionatrestprivateendpoint/data_source_schema.go +++ b/internal/service/encryptionatrestprivateendpoint/data_source_schema.go @@ -14,11 +14,6 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Description: "Human-readable label that identifies the cloud provider of the private endpoint.", MarkdownDescription: "Human-readable label that identifies the cloud provider of the private endpoint.", }, - "endpoint_id": schema.StringAttribute{ - Required: true, - Description: "Unique 24-hexadecimal digit string that identifies the private endpoint.", - MarkdownDescription: "Unique 24-hexadecimal digit string that identifies the private endpoint.", - }, "error_message": schema.StringAttribute{ Computed: true, Description: "Error message for failures associated with the Encryption At Rest private endpoint.", @@ -30,7 +25,7 @@ func DataSourceSchema(ctx context.Context) schema.Schema { MarkdownDescription: "Unique 24-hexadecimal digit string that identifies your project. Use the [/groups](#tag/Projects/operation/listProjects) endpoint to retrieve all projects to which the authenticated user has access.\n\n**NOTE**: Groups and projects are synonymous terms. Your group id is the same as your project id. For existing groups, your group/project id remains the same. The resource and corresponding endpoints use the term groups.", }, "id": schema.StringAttribute{ - Computed: true, + Required: true, Description: "Unique 24-hexadecimal digit string that identifies the Private Endpoint Service.", MarkdownDescription: "Unique 24-hexadecimal digit string that identifies the Private Endpoint Service.", }, diff --git a/internal/service/encryptionatrestprivateendpoint/model.go b/internal/service/encryptionatrestprivateendpoint/model.go index b15174058f..5467b490cc 100644 --- a/internal/service/encryptionatrestprivateendpoint/model.go +++ b/internal/service/encryptionatrestprivateendpoint/model.go @@ -1,15 +1,19 @@ package encryptionatrestprivateendpoint import ( - "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion" "go.mongodb.org/atlas-sdk/v20240805001/admin" + + "github.com/hashicorp/terraform-plugin-framework/types" + + "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion" ) -func NewTFEarPrivateEndpoint(apiResp *admin.EARPrivateEndpoint) *TFEarPrivateEndpointModel { +func NewTFEarPrivateEndpoint(apiResp *admin.EARPrivateEndpoint, projectID string) *TFEarPrivateEndpointModel { if apiResp == nil { return nil } return &TFEarPrivateEndpointModel{ + ProjectID: types.StringValue(projectID), CloudProvider: conversion.StringNullIfEmpty(apiResp.GetCloudProvider()), ErrorMessage: conversion.StringNullIfEmpty(apiResp.GetErrorMessage()), ID: conversion.StringNullIfEmpty(apiResp.GetId()), diff --git a/internal/service/encryptionatrestprivateendpoint/model_test.go b/internal/service/encryptionatrestprivateendpoint/model_test.go index 6f9fcf9755..2b620aff1d 100644 --- a/internal/service/encryptionatrestprivateendpoint/model_test.go +++ b/internal/service/encryptionatrestprivateendpoint/model_test.go @@ -3,14 +3,19 @@ package encryptionatrestprivateendpoint_test import ( "testing" + "go.mongodb.org/atlas-sdk/v20240805001/admin" + "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/mongodb/terraform-provider-mongodbatlas/internal/service/encryptionatrestprivateendpoint" "github.com/stretchr/testify/assert" - "go.mongodb.org/atlas-sdk/v20240805001/admin" + + "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion" + "github.com/mongodb/terraform-provider-mongodbatlas/internal/service/encryptionatrestprivateendpoint" ) const ( testCloudProvider = "AZURE" + testProjectID = "666666666067bd1e20a8bf14" + testTotalResultCount = 99 testErrMsg = "error occurred" testID = "6666666999999adsfsgdg" testRegionName = "US_EAST" @@ -41,6 +46,7 @@ func TestEncryptionAtRestPrivateEndpointSDKToTFModel(t *testing.T) { RegionName: types.StringValue(testRegionName), Status: types.StringValue(testStatus), PrivateEndpointConnectionName: types.StringValue(testPEConnectionName), + ProjectID: types.StringValue(testProjectID), }, }, "Complete SDK response with error message": { @@ -59,13 +65,14 @@ func TestEncryptionAtRestPrivateEndpointSDKToTFModel(t *testing.T) { RegionName: types.StringValue(testRegionName), Status: types.StringValue(testStatus), PrivateEndpointConnectionName: types.StringValue(testPEConnectionName), + ProjectID: types.StringValue(testProjectID), }, }, } for testName, tc := range testCases { t.Run(testName, func(t *testing.T) { - resultModel := encryptionatrestprivateendpoint.NewTFEarPrivateEndpoint(tc.SDKResp) + resultModel := encryptionatrestprivateendpoint.NewTFEarPrivateEndpoint(tc.SDKResp, testProjectID) assert.Equal(t, tc.expectedTFModel, resultModel, "created terraform model did not match expected output") }) } @@ -119,3 +126,63 @@ func TestEncryptionAtRestPrivateEndpointTFModelToSDK(t *testing.T) { }) } } + +type sdkToTFModelPluralDSTestCase struct { + expectedTFModel *encryptionatrestprivateendpoint.TFEncryptionAtRestPrivateEndpointsDSModel + SDKResp []admin.EARPrivateEndpoint +} + +func TestEncryptionAtRestPrivateEndpointPluralDSSDKToTFModel(t *testing.T) { + testCases := map[string]sdkToTFModelPluralDSTestCase{ + "Complete SDK response": { + SDKResp: []admin.EARPrivateEndpoint{ + { + CloudProvider: admin.PtrString(testCloudProvider), + ErrorMessage: admin.PtrString(""), + Id: admin.PtrString(testID), + RegionName: admin.PtrString(testRegionName), + Status: admin.PtrString(testStatus), + PrivateEndpointConnectionName: admin.PtrString(testPEConnectionName), + }, + { + CloudProvider: admin.PtrString(testCloudProvider), + ErrorMessage: admin.PtrString(testErrMsg), + Id: admin.PtrString(testID), + RegionName: admin.PtrString(testRegionName), + Status: admin.PtrString(testStatus), + PrivateEndpointConnectionName: admin.PtrString(testPEConnectionName), + }, + }, + expectedTFModel: &encryptionatrestprivateendpoint.TFEncryptionAtRestPrivateEndpointsDSModel{ + CloudProvider: types.StringValue(testCloudProvider), + ProjectID: types.StringValue(testProjectID), + TotalCount: types.Int64Value(int64(testTotalResultCount)), + Results: []encryptionatrestprivateendpoint.TFEarPrivateEndpointDSModel{ + { + CloudProvider: types.StringValue(testCloudProvider), + ErrorMessage: types.StringNull(), + ID: types.StringValue(testID), + RegionName: types.StringValue(testRegionName), + Status: types.StringValue(testStatus), + PrivateEndpointConnectionName: types.StringValue(testPEConnectionName), + }, + { + CloudProvider: types.StringValue(testCloudProvider), + ErrorMessage: types.StringValue(testErrMsg), + ID: types.StringValue(testID), + RegionName: types.StringValue(testRegionName), + Status: types.StringValue(testStatus), + PrivateEndpointConnectionName: types.StringValue(testPEConnectionName), + }, + }, + }, + }, + } + + for testName, tc := range testCases { + t.Run(testName, func(t *testing.T) { + resultModel := encryptionatrestprivateendpoint.NewTFEarPrivateEndpoints(testProjectID, testCloudProvider, conversion.IntPtr(testTotalResultCount), tc.SDKResp) + assert.Equal(t, tc.expectedTFModel, resultModel, "created terraform model did not match expected output") + }) + } +} diff --git a/internal/service/encryptionatrestprivateendpoint/plural_data_source.go b/internal/service/encryptionatrestprivateendpoint/plural_data_source.go index 0795ecc55e..c7c7f019e1 100644 --- a/internal/service/encryptionatrestprivateendpoint/plural_data_source.go +++ b/internal/service/encryptionatrestprivateendpoint/plural_data_source.go @@ -1,3 +1,4 @@ +//nolint:gocritic package encryptionatrestprivateendpoint import ( @@ -37,17 +38,19 @@ func (d *encryptionAtRestPrivateEndpointsDS) Read(ctx context.Context, req datas // TODO: make get request to obtain list of results - // connV2 := r.Client.AtlasV2 + // connV2 := d.Client.AtlasV2 + // TODO: GetEncryptionAtRestPrivateEndpointsForCloudProvider returns paginated results + // v, resp, err := connV2.EncryptionAtRestUsingCustomerKeyManagementApi.GetEncryptionAtRestPrivateEndpointsForCloudProvider(ctx, "", "").Execute() // if err != nil { // resp.Diagnostics.AddError("error fetching results", err.Error()) // return //} // TODO: process response into new terraform state - // newEncryptionAtRestPrivateEndpointsModel, diags := NewTFEncryptionAtRestPrivateEndpoints(ctx, apiResp) + // newEncryptionAtRestPrivateEndpointsModel := NewTFEarPrivateEndpoints("","",conversion.IntPtr(99), v.GetResults()) // if diags.HasError() { // resp.Diagnostics.Append(diags...) // return // } - // resp.Diagnostics.Append(resp.State.Set(ctx, newEncryptionAtRestPrivateEndpointsModel)...) + // resp.Diagnostics.Append(resp.State.Set(ctx, NewTFEarPrivateEndpoints(ctx))...) } diff --git a/internal/service/encryptionatrestprivateendpoint/pural_data_source_schema.go b/internal/service/encryptionatrestprivateendpoint/pural_data_source_schema.go index f829031f95..82691090d4 100644 --- a/internal/service/encryptionatrestprivateendpoint/pural_data_source_schema.go +++ b/internal/service/encryptionatrestprivateendpoint/pural_data_source_schema.go @@ -1,18 +1,14 @@ -// Code generated by terraform-plugin-framework-generator DO NOT EDIT. - package encryptionatrestprivateendpoint import ( "context" - "strings" - "fmt" - "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" - "github.com/hashicorp/terraform-plugin-go/tftypes" + "go.mongodb.org/atlas-sdk/v20240805001/admin" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" + + "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion" ) func PluralDataSourceSchema(ctx context.Context) schema.Schema { @@ -23,7 +19,7 @@ func PluralDataSourceSchema(ctx context.Context) schema.Schema { Description: "Human-readable label that identifies the cloud provider for the private endpoints to return.", MarkdownDescription: "Human-readable label that identifies the cloud provider for the private endpoints to return.", }, - "group_id": schema.StringAttribute{ + "project_id": schema.StringAttribute{ Required: true, Description: "Unique 24-hexadecimal digit string that identifies your project. Use the [/groups](#tag/Projects/operation/listProjects) endpoint to retrieve all projects to which the authenticated user has access.\n\n**NOTE**: Groups and projects are synonymous terms. Your group id is the same as your project id. For existing groups, your group/project id remains the same. The resource and corresponding endpoints use the term groups.", MarkdownDescription: "Unique 24-hexadecimal digit string that identifies your project. Use the [/groups](#tag/Projects/operation/listProjects) endpoint to retrieve all projects to which the authenticated user has access.\n\n**NOTE**: Groups and projects are synonymous terms. Your group id is the same as your project id. For existing groups, your group/project id remains the same. The resource and corresponding endpoints use the term groups.", @@ -61,11 +57,6 @@ func PluralDataSourceSchema(ctx context.Context) schema.Schema { Description: "State of the Encryption At Rest private endpoint.", MarkdownDescription: "State of the Encryption At Rest private endpoint.", }, - }, - CustomType: ResultsType{ - ObjectType: types.ObjectType{ - AttrTypes: ResultsValue{}.AttributeTypes(ctx), - }, }, }, Computed: true, @@ -82,607 +73,42 @@ func PluralDataSourceSchema(ctx context.Context) schema.Schema { } type TFEncryptionAtRestPrivateEndpointsDSModel struct { - CloudProvider types.String `tfsdk:"cloud_provider"` - GroupId types.String `tfsdk:"group_id"` - Results types.List `tfsdk:"results"` - TotalCount types.Int64 `tfsdk:"total_count"` -} - -var _ basetypes.ObjectTypable = ResultsType{} - -type ResultsType struct { - basetypes.ObjectType -} - -func (t ResultsType) Equal(o attr.Type) bool { - other, ok := o.(ResultsType) - - if !ok { - return false - } - - return t.ObjectType.Equal(other.ObjectType) -} - -func (t ResultsType) String() string { - return "ResultsType" -} - -func (t ResultsType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { - var diags diag.Diagnostics - - attributes := in.Attributes() - - cloudProviderAttribute, ok := attributes["cloud_provider"] - - if !ok { - diags.AddError( - "Attribute Missing", - `cloud_provider is missing from object`) - - return nil, diags - } - - cloudProviderVal, ok := cloudProviderAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`cloud_provider expected to be basetypes.StringValue, was: %T`, cloudProviderAttribute)) - } - - errorMessageAttribute, ok := attributes["error_message"] - - if !ok { - diags.AddError( - "Attribute Missing", - `error_message is missing from object`) - - return nil, diags - } - - errorMessageVal, ok := errorMessageAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`error_message expected to be basetypes.StringValue, was: %T`, errorMessageAttribute)) - } - - idAttribute, ok := attributes["id"] - - if !ok { - diags.AddError( - "Attribute Missing", - `id is missing from object`) - - return nil, diags - } - - idVal, ok := idAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`id expected to be basetypes.StringValue, was: %T`, idAttribute)) - } - - privateEndpointConnectionNameAttribute, ok := attributes["private_endpoint_connection_name"] - - if !ok { - diags.AddError( - "Attribute Missing", - `private_endpoint_connection_name is missing from object`) - - return nil, diags - } - - privateEndpointConnectionNameVal, ok := privateEndpointConnectionNameAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`private_endpoint_connection_name expected to be basetypes.StringValue, was: %T`, privateEndpointConnectionNameAttribute)) - } - - regionNameAttribute, ok := attributes["region_name"] - - if !ok { - diags.AddError( - "Attribute Missing", - `region_name is missing from object`) - - return nil, diags - } - - regionNameVal, ok := regionNameAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`region_name expected to be basetypes.StringValue, was: %T`, regionNameAttribute)) - } - - statusAttribute, ok := attributes["status"] - - if !ok { - diags.AddError( - "Attribute Missing", - `status is missing from object`) - - return nil, diags - } - - statusVal, ok := statusAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`status expected to be basetypes.StringValue, was: %T`, statusAttribute)) - } - - if diags.HasError() { - return nil, diags - } - - return ResultsValue{ - CloudProvider: cloudProviderVal, - ErrorMessage: errorMessageVal, - Id: idVal, - PrivateEndpointConnectionName: privateEndpointConnectionNameVal, - RegionName: regionNameVal, - Status: statusVal, - state: attr.ValueStateKnown, - }, diags -} - -func NewResultsValueNull() ResultsValue { - return ResultsValue{ - state: attr.ValueStateNull, - } -} - -func NewResultsValueUnknown() ResultsValue { - return ResultsValue{ - state: attr.ValueStateUnknown, - } -} - -func NewResultsValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (ResultsValue, diag.Diagnostics) { - var diags diag.Diagnostics - - // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 - ctx := context.Background() - - for name, attributeType := range attributeTypes { - attribute, ok := attributes[name] - - if !ok { - diags.AddError( - "Missing ResultsValue Attribute Value", - "While creating a ResultsValue value, a missing attribute value was detected. "+ - "A ResultsValue must contain values for all attributes, even if null or unknown. "+ - "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("ResultsValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), - ) - - continue - } - - if !attributeType.Equal(attribute.Type(ctx)) { - diags.AddError( - "Invalid ResultsValue Attribute Type", - "While creating a ResultsValue value, an invalid attribute value was detected. "+ - "A ResultsValue must use a matching attribute type for the value. "+ - "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("ResultsValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ - fmt.Sprintf("ResultsValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), - ) - } - } - - for name := range attributes { - _, ok := attributeTypes[name] - - if !ok { - diags.AddError( - "Extra ResultsValue Attribute Value", - "While creating a ResultsValue value, an extra attribute value was detected. "+ - "A ResultsValue must not contain values beyond the expected attribute types. "+ - "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("Extra ResultsValue Attribute Name: %s", name), - ) - } - } - - if diags.HasError() { - return NewResultsValueUnknown(), diags - } - - cloudProviderAttribute, ok := attributes["cloud_provider"] - - if !ok { - diags.AddError( - "Attribute Missing", - `cloud_provider is missing from object`) - - return NewResultsValueUnknown(), diags - } - - cloudProviderVal, ok := cloudProviderAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`cloud_provider expected to be basetypes.StringValue, was: %T`, cloudProviderAttribute)) - } - - errorMessageAttribute, ok := attributes["error_message"] - - if !ok { - diags.AddError( - "Attribute Missing", - `error_message is missing from object`) - - return NewResultsValueUnknown(), diags - } - - errorMessageVal, ok := errorMessageAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`error_message expected to be basetypes.StringValue, was: %T`, errorMessageAttribute)) - } - - idAttribute, ok := attributes["id"] - - if !ok { - diags.AddError( - "Attribute Missing", - `id is missing from object`) - - return NewResultsValueUnknown(), diags - } - - idVal, ok := idAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`id expected to be basetypes.StringValue, was: %T`, idAttribute)) - } - - privateEndpointConnectionNameAttribute, ok := attributes["private_endpoint_connection_name"] - - if !ok { - diags.AddError( - "Attribute Missing", - `private_endpoint_connection_name is missing from object`) - - return NewResultsValueUnknown(), diags - } - - privateEndpointConnectionNameVal, ok := privateEndpointConnectionNameAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`private_endpoint_connection_name expected to be basetypes.StringValue, was: %T`, privateEndpointConnectionNameAttribute)) - } - - regionNameAttribute, ok := attributes["region_name"] - - if !ok { - diags.AddError( - "Attribute Missing", - `region_name is missing from object`) - - return NewResultsValueUnknown(), diags - } - - regionNameVal, ok := regionNameAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`region_name expected to be basetypes.StringValue, was: %T`, regionNameAttribute)) - } - - statusAttribute, ok := attributes["status"] - - if !ok { - diags.AddError( - "Attribute Missing", - `status is missing from object`) - - return NewResultsValueUnknown(), diags - } - - statusVal, ok := statusAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`status expected to be basetypes.StringValue, was: %T`, statusAttribute)) - } - - if diags.HasError() { - return NewResultsValueUnknown(), diags - } - - return ResultsValue{ - CloudProvider: cloudProviderVal, - ErrorMessage: errorMessageVal, - Id: idVal, - PrivateEndpointConnectionName: privateEndpointConnectionNameVal, - RegionName: regionNameVal, - Status: statusVal, - state: attr.ValueStateKnown, - }, diags + CloudProvider types.String `tfsdk:"cloud_provider"` + ProjectID types.String `tfsdk:"project_id"` + Results []TFEarPrivateEndpointDSModel `tfsdk:"results"` + TotalCount types.Int64 `tfsdk:"total_count"` } -func NewResultsValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) ResultsValue { - object, diags := NewResultsValue(attributeTypes, attributes) - - if diags.HasError() { - // This could potentially be added to the diag package. - diagsStrings := make([]string, 0, len(diags)) - - for _, diagnostic := range diags { - diagsStrings = append(diagsStrings, fmt.Sprintf( - "%s | %s | %s", - diagnostic.Severity(), - diagnostic.Summary(), - diagnostic.Detail())) - } - - panic("NewResultsValueMust received error(s): " + strings.Join(diagsStrings, "\n")) - } - - return object +type TFEarPrivateEndpointDSModel struct { + CloudProvider types.String `tfsdk:"cloud_provider"` + ErrorMessage types.String `tfsdk:"error_message"` + ID types.String `tfsdk:"id"` + PrivateEndpointConnectionName types.String `tfsdk:"private_endpoint_connection_name"` + RegionName types.String `tfsdk:"region_name"` + Status types.String `tfsdk:"status"` } -func (t ResultsType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { - if in.Type() == nil { - return NewResultsValueNull(), nil - } - - if !in.Type().Equal(t.TerraformType(ctx)) { - return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) - } - - if !in.IsKnown() { - return NewResultsValueUnknown(), nil - } - - if in.IsNull() { - return NewResultsValueNull(), nil - } - - attributes := map[string]attr.Value{} - - val := map[string]tftypes.Value{} - - err := in.As(&val) - - if err != nil { - return nil, err - } - - for k, v := range val { - a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) - - if err != nil { - return nil, err - } - - attributes[k] = a +func NewTFEarPrivateEndpoints(projectID, cloudProvider string, totalCount *int, results []admin.EARPrivateEndpoint) *TFEncryptionAtRestPrivateEndpointsDSModel { + return &TFEncryptionAtRestPrivateEndpointsDSModel{ + ProjectID: types.StringValue(projectID), + TotalCount: types.Int64PointerValue(conversion.IntPtrToInt64Ptr(totalCount)), + CloudProvider: types.StringValue(cloudProvider), + Results: NewTFEarPrivateEndpointsDS(results), } - - return NewResultsValueMust(ResultsValue{}.AttributeTypes(ctx), attributes), nil -} - -func (t ResultsType) ValueType(ctx context.Context) attr.Value { - return ResultsValue{} } -var _ basetypes.ObjectValuable = ResultsValue{} - -type ResultsValue struct { - CloudProvider basetypes.StringValue `tfsdk:"cloud_provider"` - ErrorMessage basetypes.StringValue `tfsdk:"error_message"` - Id basetypes.StringValue `tfsdk:"id"` - PrivateEndpointConnectionName basetypes.StringValue `tfsdk:"private_endpoint_connection_name"` - RegionName basetypes.StringValue `tfsdk:"region_name"` - Status basetypes.StringValue `tfsdk:"status"` - state attr.ValueState -} - -func (v ResultsValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { - attrTypes := make(map[string]tftypes.Type, 6) - - var val tftypes.Value - var err error - - attrTypes["cloud_provider"] = basetypes.StringType{}.TerraformType(ctx) - attrTypes["error_message"] = basetypes.StringType{}.TerraformType(ctx) - attrTypes["id"] = basetypes.StringType{}.TerraformType(ctx) - attrTypes["private_endpoint_connection_name"] = basetypes.StringType{}.TerraformType(ctx) - attrTypes["region_name"] = basetypes.StringType{}.TerraformType(ctx) - attrTypes["status"] = basetypes.StringType{}.TerraformType(ctx) - - objectType := tftypes.Object{AttributeTypes: attrTypes} - - switch v.state { - case attr.ValueStateKnown: - vals := make(map[string]tftypes.Value, 6) - - val, err = v.CloudProvider.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["cloud_provider"] = val - - val, err = v.ErrorMessage.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["error_message"] = val - - val, err = v.Id.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["id"] = val - - val, err = v.PrivateEndpointConnectionName.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["private_endpoint_connection_name"] = val - - val, err = v.RegionName.ToTerraformValue(ctx) +func NewTFEarPrivateEndpointsDS(endpoints []admin.EARPrivateEndpoint) []TFEarPrivateEndpointDSModel { + results := make([]TFEarPrivateEndpointDSModel, len(endpoints)) - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err + for i, v := range endpoints { + results[i] = TFEarPrivateEndpointDSModel{ + CloudProvider: conversion.StringNullIfEmpty(v.GetCloudProvider()), + ErrorMessage: conversion.StringNullIfEmpty(v.GetErrorMessage()), + ID: conversion.StringNullIfEmpty(v.GetId()), + RegionName: conversion.StringNullIfEmpty(v.GetRegionName()), + Status: conversion.StringNullIfEmpty(v.GetStatus()), + PrivateEndpointConnectionName: conversion.StringNullIfEmpty(v.GetPrivateEndpointConnectionName()), } - - vals["region_name"] = val - - val, err = v.Status.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["status"] = val - - if err := tftypes.ValidateValue(objectType, vals); err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - return tftypes.NewValue(objectType, vals), nil - case attr.ValueStateNull: - return tftypes.NewValue(objectType, nil), nil - case attr.ValueStateUnknown: - return tftypes.NewValue(objectType, tftypes.UnknownValue), nil - default: - panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) - } -} - -func (v ResultsValue) IsNull() bool { - return v.state == attr.ValueStateNull -} - -func (v ResultsValue) IsUnknown() bool { - return v.state == attr.ValueStateUnknown -} - -func (v ResultsValue) String() string { - return "ResultsValue" -} - -func (v ResultsValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { - var diags diag.Diagnostics - - attributeTypes := map[string]attr.Type{ - "cloud_provider": basetypes.StringType{}, - "error_message": basetypes.StringType{}, - "id": basetypes.StringType{}, - "private_endpoint_connection_name": basetypes.StringType{}, - "region_name": basetypes.StringType{}, - "status": basetypes.StringType{}, - } - - if v.IsNull() { - return types.ObjectNull(attributeTypes), diags - } - - if v.IsUnknown() { - return types.ObjectUnknown(attributeTypes), diags - } - - objVal, diags := types.ObjectValue( - attributeTypes, - map[string]attr.Value{ - "cloud_provider": v.CloudProvider, - "error_message": v.ErrorMessage, - "id": v.Id, - "private_endpoint_connection_name": v.PrivateEndpointConnectionName, - "region_name": v.RegionName, - "status": v.Status, - }) - - return objVal, diags -} - -func (v ResultsValue) Equal(o attr.Value) bool { - other, ok := o.(ResultsValue) - - if !ok { - return false - } - - if v.state != other.state { - return false - } - - if v.state != attr.ValueStateKnown { - return true - } - - if !v.CloudProvider.Equal(other.CloudProvider) { - return false - } - - if !v.ErrorMessage.Equal(other.ErrorMessage) { - return false - } - - if !v.Id.Equal(other.Id) { - return false - } - - if !v.PrivateEndpointConnectionName.Equal(other.PrivateEndpointConnectionName) { - return false - } - - if !v.RegionName.Equal(other.RegionName) { - return false - } - - if !v.Status.Equal(other.Status) { - return false - } - - return true -} - -func (v ResultsValue) Type(ctx context.Context) attr.Type { - return ResultsType{ - basetypes.ObjectType{ - AttrTypes: v.AttributeTypes(ctx), - }, - } -} - -func (v ResultsValue) AttributeTypes(ctx context.Context) map[string]attr.Type { - return map[string]attr.Type{ - "cloud_provider": basetypes.StringType{}, - "error_message": basetypes.StringType{}, - "id": basetypes.StringType{}, - "private_endpoint_connection_name": basetypes.StringType{}, - "region_name": basetypes.StringType{}, - "status": basetypes.StringType{}, } + return results } diff --git a/internal/service/encryptionatrestprivateendpoint/resource_schema.go b/internal/service/encryptionatrestprivateendpoint/resource_schema.go index 076488886c..13a2ef96d3 100644 --- a/internal/service/encryptionatrestprivateendpoint/resource_schema.go +++ b/internal/service/encryptionatrestprivateendpoint/resource_schema.go @@ -15,11 +15,6 @@ func ResourceSchema(ctx context.Context) schema.Schema { Description: "Human-readable label that identifies the cloud provider for the Encryption At Rest private endpoint.", MarkdownDescription: "Human-readable label that identifies the cloud provider for the Encryption At Rest private endpoint.", }, - "endpoint_id": schema.StringAttribute{ - Computed: true, - Description: "Unique 24-hexadecimal digit string that identifies the private endpoint.", - MarkdownDescription: "Unique 24-hexadecimal digit string that identifies the private endpoint.", - }, "error_message": schema.StringAttribute{ Computed: true, Description: "Error message for failures associated with the Encryption At Rest private endpoint.", @@ -56,7 +51,6 @@ func ResourceSchema(ctx context.Context) schema.Schema { type TFEarPrivateEndpointModel struct { CloudProvider types.String `tfsdk:"cloud_provider"` - EndpointID types.String `tfsdk:"endpoint_id"` ErrorMessage types.String `tfsdk:"error_message"` ProjectID types.String `tfsdk:"project_id"` ID types.String `tfsdk:"id"` From 4e1b5f457cd3ae8206a5bab8ba658c102dd8e882 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Mon, 19 Aug 2024 15:38:02 +0100 Subject: [PATCH 5/5] remove totalCount --- .../encryptionatrestprivateendpoint/model_test.go | 4 +--- .../pural_data_source_schema.go | 9 +-------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/internal/service/encryptionatrestprivateendpoint/model_test.go b/internal/service/encryptionatrestprivateendpoint/model_test.go index 2b620aff1d..322e3c0629 100644 --- a/internal/service/encryptionatrestprivateendpoint/model_test.go +++ b/internal/service/encryptionatrestprivateendpoint/model_test.go @@ -8,7 +8,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" "github.com/stretchr/testify/assert" - "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion" "github.com/mongodb/terraform-provider-mongodbatlas/internal/service/encryptionatrestprivateendpoint" ) @@ -156,7 +155,6 @@ func TestEncryptionAtRestPrivateEndpointPluralDSSDKToTFModel(t *testing.T) { expectedTFModel: &encryptionatrestprivateendpoint.TFEncryptionAtRestPrivateEndpointsDSModel{ CloudProvider: types.StringValue(testCloudProvider), ProjectID: types.StringValue(testProjectID), - TotalCount: types.Int64Value(int64(testTotalResultCount)), Results: []encryptionatrestprivateendpoint.TFEarPrivateEndpointDSModel{ { CloudProvider: types.StringValue(testCloudProvider), @@ -181,7 +179,7 @@ func TestEncryptionAtRestPrivateEndpointPluralDSSDKToTFModel(t *testing.T) { for testName, tc := range testCases { t.Run(testName, func(t *testing.T) { - resultModel := encryptionatrestprivateendpoint.NewTFEarPrivateEndpoints(testProjectID, testCloudProvider, conversion.IntPtr(testTotalResultCount), tc.SDKResp) + resultModel := encryptionatrestprivateendpoint.NewTFEarPrivateEndpoints(testProjectID, testCloudProvider, tc.SDKResp) assert.Equal(t, tc.expectedTFModel, resultModel, "created terraform model did not match expected output") }) } diff --git a/internal/service/encryptionatrestprivateendpoint/pural_data_source_schema.go b/internal/service/encryptionatrestprivateendpoint/pural_data_source_schema.go index 82691090d4..9f88d4979a 100644 --- a/internal/service/encryptionatrestprivateendpoint/pural_data_source_schema.go +++ b/internal/service/encryptionatrestprivateendpoint/pural_data_source_schema.go @@ -63,11 +63,6 @@ func PluralDataSourceSchema(ctx context.Context) schema.Schema { Description: "List of returned documents that MongoDB Cloud providers when completing this request.", MarkdownDescription: "List of returned documents that MongoDB Cloud providers when completing this request.", }, - "total_count": schema.Int64Attribute{ - Computed: true, - Description: "Total number of documents available. MongoDB Cloud omits this value if `includeCount` is set to `false`.", - MarkdownDescription: "Total number of documents available. MongoDB Cloud omits this value if `includeCount` is set to `false`.", - }, }, } } @@ -76,7 +71,6 @@ type TFEncryptionAtRestPrivateEndpointsDSModel struct { CloudProvider types.String `tfsdk:"cloud_provider"` ProjectID types.String `tfsdk:"project_id"` Results []TFEarPrivateEndpointDSModel `tfsdk:"results"` - TotalCount types.Int64 `tfsdk:"total_count"` } type TFEarPrivateEndpointDSModel struct { @@ -88,10 +82,9 @@ type TFEarPrivateEndpointDSModel struct { Status types.String `tfsdk:"status"` } -func NewTFEarPrivateEndpoints(projectID, cloudProvider string, totalCount *int, results []admin.EARPrivateEndpoint) *TFEncryptionAtRestPrivateEndpointsDSModel { +func NewTFEarPrivateEndpoints(projectID, cloudProvider string, results []admin.EARPrivateEndpoint) *TFEncryptionAtRestPrivateEndpointsDSModel { return &TFEncryptionAtRestPrivateEndpointsDSModel{ ProjectID: types.StringValue(projectID), - TotalCount: types.Int64PointerValue(conversion.IntPtrToInt64Ptr(totalCount)), CloudProvider: types.StringValue(cloudProvider), Results: NewTFEarPrivateEndpointsDS(results), }