From ef2d11d89c8d733e88592485982983f88e968e9b Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Fri, 11 Aug 2023 14:08:34 +0100 Subject: [PATCH 01/19] initial setup --- .../validator/aws_kms_config_validator.go | 60 ++ mongodbatlas/fw_provider.go | 1 + ...esource_mongodbatlas_encryption_at_rest.go | 522 ++++++++++++++++++ ...atlas_encryption_at_rest_migration_test.go | 1 + ...e_mongodbatlas_encryption_at_rest_test.go} | 10 +- mongodbatlas/provider.go | 1 - 6 files changed, 589 insertions(+), 6 deletions(-) create mode 100644 mongodbatlas/framework/validator/aws_kms_config_validator.go create mode 100644 mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go create mode 100644 mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_migration_test.go rename mongodbatlas/{resource_mongodbatlas_encryption_at_rest_test.go => fw_resource_mongodbatlas_encryption_at_rest_test.go} (98%) diff --git a/mongodbatlas/framework/validator/aws_kms_config_validator.go b/mongodbatlas/framework/validator/aws_kms_config_validator.go new file mode 100644 index 0000000000..9f54c8f077 --- /dev/null +++ b/mongodbatlas/framework/validator/aws_kms_config_validator.go @@ -0,0 +1,60 @@ +package validator + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework-validators/helpers/validatordiag" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" +) + +type awsKmsConfigValidator struct{} + +func (v awsKmsConfigValidator) Description(_ context.Context) string { + return "for credentials: `access_key_id` and `secret_access_key` are allowed but not `role_id`." + + " For roles: `access_key_id` and `secret_access_key` are not allowed but `role_id` is allowed" +} + +func (v awsKmsConfigValidator) MarkdownDescription(ctx context.Context) string { + return v.Description(ctx) +} + +func (v awsKmsConfigValidator) ValidateObject(ctx context.Context, req validator.ObjectRequest, response *validator.ObjectResponse) { + // If the value is unknown or null, there is nothing to validate. + if req.ConfigValue.IsUnknown() || req.ConfigValue.IsNull() { + return + } + + obj, diag := req.ConfigValue.ToObjectValue(ctx) + if diag.HasError() { + response.Diagnostics.Append(diag.Errors()...) + return + } + + attrMap := obj.Attributes() + ak, akOk := attrMap["access_key_id"] + sa, saOk := attrMap["secret_access_key"] + r, rOk := attrMap["role_id"] + + if ((akOk && !ak.IsNull()) && (saOk && !sa.IsNull()) && (rOk && !r.IsNull())) || + ((akOk && !ak.IsNull()) && (rOk && !r.IsNull())) || + ((saOk && !sa.IsNull()) && (rOk && !r.IsNull())) { + response.Diagnostics.Append(validatordiag.InvalidAttributeValueDiagnostic( + req.Path, + v.Description(ctx), + req.ConfigValue.String(), + )) + + } + + // if _, err := structure.NormalizeJsonString(req.ConfigValue.ValueString()); err != nil { + // response.Diagnostics.Append(validatordiag.InvalidAttributeValueDiagnostic( + // req.Path, + // v.Description(ctx), + // req.ConfigValue.ValueString(), + // )) + // } +} + +func AwsKmsConfig() validator.Object { + return awsKmsConfigValidator{} +} diff --git a/mongodbatlas/fw_provider.go b/mongodbatlas/fw_provider.go index 9f7cfcb1f4..fb7975f878 100644 --- a/mongodbatlas/fw_provider.go +++ b/mongodbatlas/fw_provider.go @@ -373,6 +373,7 @@ func (p *MongodbtlasProvider) DataSources(context.Context) []func() datasource.D func (p *MongodbtlasProvider) Resources(context.Context) []func() resource.Resource { return []func() resource.Resource{ NewProjectRS, + NewEncryptionAtRestRS, } } diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go new file mode 100644 index 0000000000..2af7a69680 --- /dev/null +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go @@ -0,0 +1,522 @@ +package mongodbatlas + +import ( + "context" + "fmt" + "log" + "net/http" + "reflect" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" + "github.com/hashicorp/terraform-plugin-log/tflog" + validators "github.com/mongodb/terraform-provider-mongodbatlas/mongodbatlas/framework/validator" + matlas "go.mongodb.org/atlas/mongodbatlas" +) + +const encryptionAtRestResourceName = "encryption_at_rest" + +var _ resource.Resource = &EncryptionAtRestRS{} +var _ resource.ResourceWithImportState = &EncryptionAtRestRS{} + +func NewEncryptionAtRestRS() resource.Resource { + return &EncryptionAtRestRS{} +} + +type EncryptionAtRestRS struct { + client *MongoDBClient +} + +type tfEncryptionAtRestRSModel struct { + ID types.String `tfsdk:"id"` + ProjectID types.String `tfsdk:"project_id"` + + // AwsKms types.Map `tfsdk:"aws_kms"` + // AzureKeyVault types.Map `tfsdk:"azure_key_vault"` + // GoogleCloudKms types.Map `tfsdk:"google_cloud_kms"` + + AwsKmsConfig types.List `tfsdk:"aws_kms_config"` + AzureKeyVaultConfig types.List `tfsdk:"azure_key_vault_config"` + GoogleCloudKmsConfig types.List `tfsdk:"google_cloud_kms_config"` +} + +type tfAwsKmsConfigModel struct { + Enabled types.Bool `tfsdk:"enabled"` + AccessKeyID types.String `tfsdk:"access_key_id"` + SecretAccessKey types.String `tfsdk:"secret_access_key"` + CustomerMasterKeyID types.String `tfsdk:"customer_master_key_id"` + Region types.String `tfsdk:"region"` + RoleID types.String `tfsdk:"role_id"` +} +type tfAzureKeyVaultConfigModel struct { + Enabled types.Bool `tfsdk:"enabled"` + ClientID types.String `tfsdk:"client_id"` + AzureEnvironment types.String `tfsdk:"azure_environment"` + SubscriptionID types.String `tfsdk:"subscription_id"` + ResourceGroupName types.String `tfsdk:"resource_group_name"` + KeyVaultName types.String `tfsdk:"key_vault_name"` + KeyIdentifier types.String `tfsdk:"key_identifier"` + Secret types.String `tfsdk:"secret"` + TenantID types.String `tfsdk:"tenant_id"` +} +type tfGcpKmsConfigModel struct { + Enabled types.Bool `tfsdk:"enabled"` + ServiceAccountKey types.String `tfsdk:"service_account_key"` + KeyVersionResourceID types.String `tfsdk:"key_version_resource_id"` +} + +var tfAwsKmsObjectType = types.ObjectType{AttrTypes: map[string]attr.Type{ + "enabled": types.BoolType, + "access_key_id": types.StringType, + "secret_access_key": types.StringType, + "customer_master_key_id": types.StringType, + "region": types.StringType, + "role_id": types.StringType, +}} +var tfAzureKeyVaultObjectType = types.ObjectType{AttrTypes: map[string]attr.Type{ + "enabled": types.BoolType, + "client_id": types.StringType, + "azure_environment": types.StringType, + "subscription_id": types.StringType, + "resource_group_name": types.StringType, + "key_vault_name": types.StringType, + "key_identifier": types.StringType, + "secret": types.StringType, + "tenant_id": types.StringType, +}} +var tfGcpKmsObjectType = types.ObjectType{AttrTypes: map[string]attr.Type{ + "enabled": types.BoolType, + "service_account_key": types.StringType, + "key_version_resource_id": types.StringType, +}} + +func (r *EncryptionAtRestRS) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = fmt.Sprintf("%s_%s", req.ProviderTypeName, encryptionAtRestResourceName) +} + +func (r *EncryptionAtRestRS) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + client, err := ConfigureClientInResource(req.ProviderData) + if err != nil { + resp.Diagnostics.AddError(errorConfigureSummary, err.Error()) + return + } + r.client = client +} + +func (r *EncryptionAtRestRS) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "project_id": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + }, + Blocks: map[string]schema.Block{ + "aws_kms_config": schema.ListNestedBlock{ + Validators: []validator.List{listvalidator.SizeAtMost(1)}, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "enabled": schema.BoolAttribute{ + Optional: true, + }, + "access_key_id": schema.StringAttribute{ + Optional: true, + Sensitive: true, + }, + "secret_access_key": schema.StringAttribute{ + Optional: true, + Sensitive: true, + }, + "customer_master_key_id": schema.StringAttribute{ + Optional: true, + Sensitive: true, + }, + "region": schema.StringAttribute{ + Optional: true, + }, + "role_id": schema.StringAttribute{ + Optional: true, + }, + }, + Validators: []validator.Object{validators.AwsKmsConfig()}, + }, + }, + "azure_key_vault_config": schema.ListNestedBlock{ + Validators: []validator.List{listvalidator.SizeAtMost(1)}, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "enabled": schema.BoolAttribute{ + Required: true, + }, + "client_id": schema.StringAttribute{ + Optional: true, + Sensitive: true, + }, + "azure_environment": schema.StringAttribute{ + Optional: true, + }, + "subscription_id": schema.StringAttribute{ + Optional: true, + Sensitive: true, + }, + "resource_group_name": schema.StringAttribute{ + Optional: true, + }, + "key_vault_name": schema.StringAttribute{ + Optional: true, + }, + "key_identifier": schema.StringAttribute{ + Optional: true, + Sensitive: true, + }, + "secret": schema.StringAttribute{ + Optional: true, + Sensitive: true, + }, + "tenant_id": schema.StringAttribute{ + Optional: true, + Sensitive: true, + }, + }, + }, + }, + "google_cloud_kms_config": schema.ListNestedBlock{ + Validators: []validator.List{listvalidator.SizeAtMost(1)}, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "enabled": schema.BoolAttribute{ + Optional: true, + }, + "service_account_key": schema.StringAttribute{ + Optional: true, + Sensitive: true, + }, + "key_version_resource_id": schema.StringAttribute{ + Optional: true, + Sensitive: true, + }, + }, + }, + }, + }, + } +} + +func (r *EncryptionAtRestRS) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var encryptionAtRestPlan tfEncryptionAtRestRSModel + var awsKmsConfig []tfAwsKmsConfigModel + // var azureKeyVaultConfig tfAzureKeyVaultConfigModel + // var googleCloudKmsConfig tfGcpKmsConfigModel + + conn := r.client.Atlas + + resp.Diagnostics.Append(req.Plan.Get(ctx, &encryptionAtRestPlan)...) + if resp.Diagnostics.HasError() { + return + } + + projectID := encryptionAtRestPlan.ProjectID.ValueString() + encryptionAtRestReq := &matlas.EncryptionAtRest{ + GroupID: projectID, + } + + if !encryptionAtRestPlan.AwsKmsConfig.IsNull() { + req.Plan.GetAttribute(ctx, path.Root("aws_kms_config"), &awsKmsConfig) + encryptionAtRestReq.AwsKms = *toAtlasAwsKms(ctx, encryptionAtRestPlan.AwsKmsConfig) + } + if !encryptionAtRestPlan.AzureKeyVaultConfig.IsNull() { + encryptionAtRestReq.AzureKeyVault = *toAtlasAzureKeyVault(ctx, encryptionAtRestPlan.AzureKeyVaultConfig) + } + if !encryptionAtRestPlan.GoogleCloudKmsConfig.IsNull() { + encryptionAtRestReq.GoogleCloudKms = *toAtlasGcpKms(ctx, encryptionAtRestPlan.GoogleCloudKmsConfig) + } + + for i := 0; i < 5; i++ { + _, _, err := conn.EncryptionsAtRest.Create(ctx, encryptionAtRestReq) + if err != nil { + if strings.Contains(err.Error(), "CANNOT_ASSUME_ROLE") || strings.Contains(err.Error(), "INVALID_AWS_CREDENTIALS") || + strings.Contains(err.Error(), "CLOUD_PROVIDER_ACCESS_ROLE_NOT_AUTHORIZED") { + log.Printf("warning issue performing authorize EncryptionsAtRest not done try again: %s \n", err.Error()) + log.Println("retrying ") + time.Sleep(10 * time.Second) + encryptionAtRestReq.GroupID = projectID + continue + } + } + if err != nil { + resp.Diagnostics.AddError(fmt.Sprintf(errorCreateEncryptionAtRest, projectID), err.Error()) + return + } + break + } + + // read + encryptionResp, response, err := conn.EncryptionsAtRest.Get(context.Background(), projectID) + tflog.Debug(ctx, fmt.Sprintf("encryptionResp from api: %v", encryptionResp)) + if err != nil { + if resp != nil && response.StatusCode == http.StatusNotFound { + resp.State.RemoveResource(ctx) + return + } + resp.Diagnostics.AddError("error when getting encryption at rest resource after create", fmt.Sprintf(errorReadEncryptionAtRest, err.Error())) + return + } + + encryptionAtRestPlanNew := toTFEncryptionAtRestRSModel(ctx, encryptionResp) + + // set state to fully populated data + diags := resp.State.Set(ctx, encryptionAtRestPlanNew) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +func (r *EncryptionAtRestRS) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var encryptionAtRestState tfEncryptionAtRestRSModel + + // get current state + resp.Diagnostics.Append(req.State.Get(ctx, &encryptionAtRestState)...) + if resp.Diagnostics.HasError() { + return + } + + // get resource from API + conn := r.client.Atlas + projectID := encryptionAtRestState.ProjectID.ValueString() + encryptionResp, _, err := conn.EncryptionsAtRest.Get(context.Background(), projectID) + tflog.Debug(ctx, fmt.Sprintf("encryptionResp from api: %v", encryptionResp)) + if err != nil { + resp.Diagnostics.AddError("error when getting encryption at rest resource during read", fmt.Sprintf(errorReadEncryptionAtRest, err.Error())) + return + } + + encryptionAtRestStateNew := toTFEncryptionAtRestRSModel(ctx, encryptionResp) + + // save read data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &encryptionAtRestStateNew)...) + if resp.Diagnostics.HasError() { + return + } +} + +func (r *EncryptionAtRestRS) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var encryptionAtRestState tfEncryptionAtRestRSModel + var encryptionAtRestPlan tfEncryptionAtRestRSModel + conn := r.client.Atlas + + // get current state + resp.Diagnostics.Append(req.State.Get(ctx, &encryptionAtRestState)...) + if resp.Diagnostics.HasError() { + return + } + // get current plan + resp.Diagnostics.Append(req.Plan.Get(ctx, &encryptionAtRestPlan)...) + if resp.Diagnostics.HasError() { + return + } + projectID := encryptionAtRestState.ProjectID.ValueString() + atlasEncryptionAtRest, atlasResp, err := conn.EncryptionsAtRest.Get(context.Background(), projectID) + if err != nil { + if resp != nil && atlasResp.StatusCode == http.StatusNotFound { + resp.State.RemoveResource(ctx) + return + } + resp.Diagnostics.AddError("error when getting encryption at rest resource during update", fmt.Sprintf(errorProjectRead, projectID, err.Error())) + return + } + + if !hasAwsKmsConfigChanged(encryptionAtRestPlan.AwsKmsConfig, encryptionAtRestState.AwsKmsConfig) { + atlasEncryptionAtRest.AwsKms = *toAtlasAwsKms(ctx, encryptionAtRestPlan.AwsKmsConfig) + } + if !hasAzureKeyVaultConfigChanged(encryptionAtRestPlan.AzureKeyVaultConfig, encryptionAtRestState.AzureKeyVaultConfig) { + atlasEncryptionAtRest.AzureKeyVault = *toAtlasAzureKeyVault(ctx, encryptionAtRestPlan.AzureKeyVaultConfig) + } + if !hasGcpKmsConfigChanged(encryptionAtRestPlan.GoogleCloudKmsConfig, encryptionAtRestState.GoogleCloudKmsConfig) { + atlasEncryptionAtRest.GoogleCloudKms = *toAtlasGcpKms(ctx, encryptionAtRestPlan.GoogleCloudKmsConfig) + } + + _, _, err = conn.EncryptionsAtRest.Create(ctx, atlasEncryptionAtRest) + if err != nil { + resp.Diagnostics.AddError("error updating encryption at rest", fmt.Sprintf(errorUpdateEncryptionAtRest, err.Error())) + return + } + + // read + encryptionResp, response, err := conn.EncryptionsAtRest.Get(context.Background(), projectID) + tflog.Debug(ctx, fmt.Sprintf("encryptionResp from api: %v", encryptionResp)) + if err != nil { + if resp != nil && response.StatusCode == http.StatusNotFound { + resp.State.RemoveResource(ctx) + return + } + resp.Diagnostics.AddError("error when getting encryption at rest resource after update", fmt.Sprintf(errorReadEncryptionAtRest, err.Error())) + return + } + + encryptionAtRestStateNew := toTFEncryptionAtRestRSModel(ctx, encryptionResp) + + // save updated data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &encryptionAtRestStateNew)...) + +} + +func hasGcpKmsConfigChanged(gcpKmsConfigsPlan, gcpKmsConfigsState basetypes.ListValue) bool { + return !reflect.DeepEqual(gcpKmsConfigsPlan, gcpKmsConfigsState) +} + +func hasAzureKeyVaultConfigChanged(azureKeyVaultConfigPlan, azureKeyVaultConfigState basetypes.ListValue) bool { + return !reflect.DeepEqual(azureKeyVaultConfigPlan, azureKeyVaultConfigState) +} + +func hasAwsKmsConfigChanged(awsKmsConfigPlan, awsKmsConfigState basetypes.ListValue) bool { + return !reflect.DeepEqual(awsKmsConfigPlan, awsKmsConfigState) + +} + +func (r *EncryptionAtRestRS) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var encryptionAtRestState *tfEncryptionAtRestRSModel + + // read prior state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &encryptionAtRestState)...) + if resp.Diagnostics.HasError() { + return + } + + conn := r.client.Atlas + projectID := encryptionAtRestState.ProjectID.ValueString() + _, err := conn.EncryptionsAtRest.Delete(ctx, projectID) + + if err != nil { + resp.Diagnostics.AddError("error when destroying resource", fmt.Sprintf(errorDeleteEncryptionAtRest, projectID, err.Error())) + return + } +} + +func (r *EncryptionAtRestRS) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} + +func toTFEncryptionAtRestRSModel(ctx context.Context, encryptionResp *matlas.EncryptionAtRest) *tfEncryptionAtRestRSModel { + encryptionAtRest := tfEncryptionAtRestRSModel{ + ID: types.StringValue(encryptionResp.GroupID), + ProjectID: types.StringValue(encryptionResp.GroupID), + AwsKmsConfig: toTFAwsKmsConfig(ctx, &encryptionResp.AwsKms), + AzureKeyVaultConfig: toTFAzureKeyVaultConfig(ctx, &encryptionResp.AzureKeyVault), + GoogleCloudKmsConfig: toTFGcpKmsConfig(ctx, &encryptionResp.GoogleCloudKms), + } + return &encryptionAtRest +} + +func toTFAwsKmsConfig(ctx context.Context, awsKms *matlas.AwsKms) types.List { + tfAwsKmsConfigs := make([]tfAwsKmsConfigModel, 1) + + tfAwsKmsConfigs[0].Enabled = types.BoolPointerValue(awsKms.Enabled) + tfAwsKmsConfigs[0].AccessKeyID = types.StringValue(awsKms.AccessKeyID) + tfAwsKmsConfigs[0].SecretAccessKey = types.StringValue(awsKms.SecretAccessKey) + tfAwsKmsConfigs[0].CustomerMasterKeyID = types.StringValue(awsKms.CustomerMasterKeyID) + tfAwsKmsConfigs[0].Region = types.StringValue(awsKms.Region) + tfAwsKmsConfigs[0].RoleID = types.StringValue(awsKms.RoleID) + + list, _ := types.ListValueFrom(ctx, tfAwsKmsObjectType, tfAwsKmsConfigs) + return list +} + +func toTFAzureKeyVaultConfig(ctx context.Context, az *matlas.AzureKeyVault) types.List { + tfAzKeyVaultConfigs := make([]tfAzureKeyVaultConfigModel, 1) + + tfAzKeyVaultConfigs[0].Enabled = types.BoolPointerValue(az.Enabled) + tfAzKeyVaultConfigs[0].ClientID = types.StringValue(az.ClientID) + tfAzKeyVaultConfigs[0].AzureEnvironment = types.StringValue(az.AzureEnvironment) + tfAzKeyVaultConfigs[0].SubscriptionID = types.StringValue(az.SubscriptionID) + tfAzKeyVaultConfigs[0].ResourceGroupName = types.StringValue(az.ResourceGroupName) + tfAzKeyVaultConfigs[0].KeyVaultName = types.StringValue(az.KeyVaultName) + tfAzKeyVaultConfigs[0].KeyIdentifier = types.StringValue(az.KeyIdentifier) + tfAzKeyVaultConfigs[0].Secret = types.StringValue(az.Secret) + tfAzKeyVaultConfigs[0].TenantID = types.StringValue(az.TenantID) + + list, _ := types.ListValueFrom(ctx, tfAzureKeyVaultObjectType, tfAzKeyVaultConfigs) + return list +} + +func toTFGcpKmsConfig(ctx context.Context, gcpKms *matlas.GoogleCloudKms) types.List { + tfGcpKmsConfigs := make([]tfGcpKmsConfigModel, 1) + + tfGcpKmsConfigs[0].Enabled = types.BoolPointerValue(gcpKms.Enabled) + tfGcpKmsConfigs[0].ServiceAccountKey = types.StringValue(gcpKms.ServiceAccountKey) + tfGcpKmsConfigs[0].KeyVersionResourceID = types.StringValue(gcpKms.KeyVersionResourceID) + + list, _ := types.ListValueFrom(ctx, tfGcpKmsObjectType, tfGcpKmsConfigs) + return list +} + +func toAtlasAwsKms(ctx context.Context, tfAwsKmsConfigList basetypes.ListValue) *matlas.AwsKms { + if len(tfAwsKmsConfigList.Elements()) == 0 { + return &matlas.AwsKms{} + } + var awsKmsConfigs []tfAwsKmsConfigModel + tfAwsKmsConfigList.ElementsAs(ctx, &awsKmsConfigs, false) + + awsRegion, _ := valRegion(awsKmsConfigs[0].Region.ValueString()) + + return &matlas.AwsKms{ + Enabled: awsKmsConfigs[0].Enabled.ValueBoolPointer(), + AccessKeyID: awsKmsConfigs[0].AccessKeyID.ValueString(), + SecretAccessKey: awsKmsConfigs[0].SecretAccessKey.ValueString(), + CustomerMasterKeyID: awsKmsConfigs[0].CustomerMasterKeyID.ValueString(), + Region: awsRegion, + RoleID: awsKmsConfigs[0].RoleID.ValueString(), + } +} + +func toAtlasGcpKms(ctx context.Context, tfGcpKmsConfigList basetypes.ListValue) *matlas.GoogleCloudKms { + if len(tfGcpKmsConfigList.Elements()) == 0 { + return &matlas.GoogleCloudKms{} + } + var gcpKmsConfigs []tfGcpKmsConfigModel + tfGcpKmsConfigList.ElementsAs(ctx, &gcpKmsConfigs, false) + + return &matlas.GoogleCloudKms{ + Enabled: gcpKmsConfigs[0].Enabled.ValueBoolPointer(), + ServiceAccountKey: gcpKmsConfigs[0].ServiceAccountKey.ValueString(), + KeyVersionResourceID: gcpKmsConfigs[0].KeyVersionResourceID.ValueString(), + } +} + +func toAtlasAzureKeyVault(ctx context.Context, tfAzureKeyVaultList basetypes.ListValue) *matlas.AzureKeyVault { + if len(tfAzureKeyVaultList.Elements()) == 0 { + return &matlas.AzureKeyVault{} + } + var azureKeyVaultConfigs []tfAzureKeyVaultConfigModel + tfAzureKeyVaultList.ElementsAs(ctx, &azureKeyVaultConfigs, false) + + return &matlas.AzureKeyVault{ + Enabled: azureKeyVaultConfigs[0].Enabled.ValueBoolPointer(), + ClientID: azureKeyVaultConfigs[0].ClientID.ValueString(), + AzureEnvironment: azureKeyVaultConfigs[0].AzureEnvironment.ValueString(), + SubscriptionID: azureKeyVaultConfigs[0].SubscriptionID.ValueString(), + ResourceGroupName: azureKeyVaultConfigs[0].ResourceGroupName.ValueString(), + KeyVaultName: azureKeyVaultConfigs[0].KeyVaultName.ValueString(), + KeyIdentifier: azureKeyVaultConfigs[0].KeyIdentifier.ValueString(), + Secret: azureKeyVaultConfigs[0].Secret.ValueString(), + TenantID: azureKeyVaultConfigs[0].TenantID.ValueString(), + } +} diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_migration_test.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_migration_test.go new file mode 100644 index 0000000000..6d2d87bca5 --- /dev/null +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_migration_test.go @@ -0,0 +1 @@ +package mongodbatlas diff --git a/mongodbatlas/resource_mongodbatlas_encryption_at_rest_test.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go similarity index 98% rename from mongodbatlas/resource_mongodbatlas_encryption_at_rest_test.go rename to mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go index 89a5c4ed23..cda187aa8a 100644 --- a/mongodbatlas/resource_mongodbatlas_encryption_at_rest_test.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go @@ -97,7 +97,7 @@ data "aws_iam_role" "test" { ) func TestAccAdvRSEncryptionAtRest_basicAWS(t *testing.T) { - SkipTestExtCred(t) + // SkipTestExtCred(t) var ( resourceName = "mongodbatlas_encryption_at_rest.test" projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") @@ -143,7 +143,7 @@ func TestAccAdvRSEncryptionAtRest_basicAWS(t *testing.T) { } func TestAccAdvRSEncryptionAtRest_basicAzure(t *testing.T) { - SkipTestExtCred(t) + // SkipTestExtCred(t) var ( resourceName = "mongodbatlas_encryption_at_rest.test" projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") @@ -197,7 +197,7 @@ func TestAccAdvRSEncryptionAtRest_basicAzure(t *testing.T) { } func TestAccAdvRSEncryptionAtRest_basicGCP(t *testing.T) { - SkipTestExtCred(t) + // SkipTestExtCred(t) var ( resourceName = "mongodbatlas_encryption_at_rest.test" projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") @@ -277,7 +277,7 @@ func TestAccAdvRSEncryptionAtRestWithRole_basicAWS(t *testing.T) { func testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := testAccProviderSdkV2.Meta().(*MongoDBClient).Atlas + conn := testMongoDBClient.(*MongoDBClient).Atlas rs, ok := s.RootModule().Resources[resourceName] if !ok { @@ -297,7 +297,7 @@ func testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName string) resourc } func testAccCheckMongoDBAtlasEncryptionAtRestDestroy(s *terraform.State) error { - conn := testAccProviderSdkV2.Meta().(*MongoDBClient).Atlas + conn := testMongoDBClient.(*MongoDBClient).Atlas for _, rs := range s.RootModule().Resources { if rs.Type != "mongodbatlas_encryption_at_rest" { diff --git a/mongodbatlas/provider.go b/mongodbatlas/provider.go index da9ff1188c..bc1baf9674 100644 --- a/mongodbatlas/provider.go +++ b/mongodbatlas/provider.go @@ -225,7 +225,6 @@ func getResourcesMap() map[string]*schema.Resource { "mongodbatlas_cluster": resourceMongoDBAtlasCluster(), "mongodbatlas_network_container": resourceMongoDBAtlasNetworkContainer(), "mongodbatlas_network_peering": resourceMongoDBAtlasNetworkPeering(), - "mongodbatlas_encryption_at_rest": resourceMongoDBAtlasEncryptionAtRest(), "mongodbatlas_maintenance_window": resourceMongoDBAtlasMaintenanceWindow(), "mongodbatlas_auditing": resourceMongoDBAtlasAuditing(), "mongodbatlas_team": resourceMongoDBAtlasTeam(), From e7ca0516dca3209e781ad8bcbfd7663f457ac6f3 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Fri, 11 Aug 2023 14:16:10 +0100 Subject: [PATCH 02/19] lint fix --- .../validator/aws_kms_config_validator.go | 9 - ...esource_mongodbatlas_encryption_at_rest.go | 36 +- ...ce_mongodbatlas_encryption_at_rest_test.go | 3 - .../resource_mongodbatlas_data_lake.go | 14 + ...esource_mongodbatlas_encryption_at_rest.go | 677 ------------------ 5 files changed, 29 insertions(+), 710 deletions(-) delete mode 100644 mongodbatlas/resource_mongodbatlas_encryption_at_rest.go diff --git a/mongodbatlas/framework/validator/aws_kms_config_validator.go b/mongodbatlas/framework/validator/aws_kms_config_validator.go index 9f54c8f077..3a4a0e8b27 100644 --- a/mongodbatlas/framework/validator/aws_kms_config_validator.go +++ b/mongodbatlas/framework/validator/aws_kms_config_validator.go @@ -43,16 +43,7 @@ func (v awsKmsConfigValidator) ValidateObject(ctx context.Context, req validator v.Description(ctx), req.ConfigValue.String(), )) - } - - // if _, err := structure.NormalizeJsonString(req.ConfigValue.ValueString()); err != nil { - // response.Diagnostics.Append(validatordiag.InvalidAttributeValueDiagnostic( - // req.Path, - // v.Description(ctx), - // req.ConfigValue.ValueString(), - // )) - // } } func AwsKmsConfig() validator.Object { diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go index 2af7a69680..5cc7141e25 100644 --- a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go @@ -24,7 +24,13 @@ import ( matlas "go.mongodb.org/atlas/mongodbatlas" ) -const encryptionAtRestResourceName = "encryption_at_rest" +const ( + encryptionAtRestResourceName = "encryption_at_rest" + errorCreateEncryptionAtRest = "error creating Encryption At Rest: %s" + errorReadEncryptionAtRest = "error getting Encryption At Rest: %s" + errorDeleteEncryptionAtRest = "error deleting Encryption At Rest: (%s): %s" + errorUpdateEncryptionAtRest = "error updating Encryption At Rest: %s" +) var _ resource.Resource = &EncryptionAtRestRS{} var _ resource.ResourceWithImportState = &EncryptionAtRestRS{} @@ -38,28 +44,22 @@ type EncryptionAtRestRS struct { } type tfEncryptionAtRestRSModel struct { - ID types.String `tfsdk:"id"` - ProjectID types.String `tfsdk:"project_id"` - - // AwsKms types.Map `tfsdk:"aws_kms"` - // AzureKeyVault types.Map `tfsdk:"azure_key_vault"` - // GoogleCloudKms types.Map `tfsdk:"google_cloud_kms"` - - AwsKmsConfig types.List `tfsdk:"aws_kms_config"` - AzureKeyVaultConfig types.List `tfsdk:"azure_key_vault_config"` - GoogleCloudKmsConfig types.List `tfsdk:"google_cloud_kms_config"` + ID types.String `tfsdk:"id"` + ProjectID types.String `tfsdk:"project_id"` + AwsKmsConfig types.List `tfsdk:"aws_kms_config"` + AzureKeyVaultConfig types.List `tfsdk:"azure_key_vault_config"` + GoogleCloudKmsConfig types.List `tfsdk:"google_cloud_kms_config"` } type tfAwsKmsConfigModel struct { - Enabled types.Bool `tfsdk:"enabled"` AccessKeyID types.String `tfsdk:"access_key_id"` SecretAccessKey types.String `tfsdk:"secret_access_key"` CustomerMasterKeyID types.String `tfsdk:"customer_master_key_id"` Region types.String `tfsdk:"region"` RoleID types.String `tfsdk:"role_id"` + Enabled types.Bool `tfsdk:"enabled"` } type tfAzureKeyVaultConfigModel struct { - Enabled types.Bool `tfsdk:"enabled"` ClientID types.String `tfsdk:"client_id"` AzureEnvironment types.String `tfsdk:"azure_environment"` SubscriptionID types.String `tfsdk:"subscription_id"` @@ -68,11 +68,12 @@ type tfAzureKeyVaultConfigModel struct { KeyIdentifier types.String `tfsdk:"key_identifier"` Secret types.String `tfsdk:"secret"` TenantID types.String `tfsdk:"tenant_id"` + Enabled types.Bool `tfsdk:"enabled"` } type tfGcpKmsConfigModel struct { - Enabled types.Bool `tfsdk:"enabled"` ServiceAccountKey types.String `tfsdk:"service_account_key"` KeyVersionResourceID types.String `tfsdk:"key_version_resource_id"` + Enabled types.Bool `tfsdk:"enabled"` } var tfAwsKmsObjectType = types.ObjectType{AttrTypes: map[string]attr.Type{ @@ -222,10 +223,6 @@ func (r *EncryptionAtRestRS) Schema(ctx context.Context, req resource.SchemaRequ func (r *EncryptionAtRestRS) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var encryptionAtRestPlan tfEncryptionAtRestRSModel - var awsKmsConfig []tfAwsKmsConfigModel - // var azureKeyVaultConfig tfAzureKeyVaultConfigModel - // var googleCloudKmsConfig tfGcpKmsConfigModel - conn := r.client.Atlas resp.Diagnostics.Append(req.Plan.Get(ctx, &encryptionAtRestPlan)...) @@ -239,7 +236,6 @@ func (r *EncryptionAtRestRS) Create(ctx context.Context, req resource.CreateRequ } if !encryptionAtRestPlan.AwsKmsConfig.IsNull() { - req.Plan.GetAttribute(ctx, path.Root("aws_kms_config"), &awsKmsConfig) encryptionAtRestReq.AwsKms = *toAtlasAwsKms(ctx, encryptionAtRestPlan.AwsKmsConfig) } if !encryptionAtRestPlan.AzureKeyVaultConfig.IsNull() { @@ -376,7 +372,6 @@ func (r *EncryptionAtRestRS) Update(ctx context.Context, req resource.UpdateRequ // save updated data into Terraform state resp.Diagnostics.Append(resp.State.Set(ctx, &encryptionAtRestStateNew)...) - } func hasGcpKmsConfigChanged(gcpKmsConfigsPlan, gcpKmsConfigsState basetypes.ListValue) bool { @@ -389,7 +384,6 @@ func hasAzureKeyVaultConfigChanged(azureKeyVaultConfigPlan, azureKeyVaultConfigS func hasAwsKmsConfigChanged(awsKmsConfigPlan, awsKmsConfigState basetypes.ListValue) bool { return !reflect.DeepEqual(awsKmsConfigPlan, awsKmsConfigState) - } func (r *EncryptionAtRestRS) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go index cda187aa8a..95445f69d2 100644 --- a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go @@ -97,7 +97,6 @@ data "aws_iam_role" "test" { ) func TestAccAdvRSEncryptionAtRest_basicAWS(t *testing.T) { - // SkipTestExtCred(t) var ( resourceName = "mongodbatlas_encryption_at_rest.test" projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") @@ -143,7 +142,6 @@ func TestAccAdvRSEncryptionAtRest_basicAWS(t *testing.T) { } func TestAccAdvRSEncryptionAtRest_basicAzure(t *testing.T) { - // SkipTestExtCred(t) var ( resourceName = "mongodbatlas_encryption_at_rest.test" projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") @@ -197,7 +195,6 @@ func TestAccAdvRSEncryptionAtRest_basicAzure(t *testing.T) { } func TestAccAdvRSEncryptionAtRest_basicGCP(t *testing.T) { - // SkipTestExtCred(t) var ( resourceName = "mongodbatlas_encryption_at_rest.test" projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") diff --git a/mongodbatlas/resource_mongodbatlas_data_lake.go b/mongodbatlas/resource_mongodbatlas_data_lake.go index be9c85236b..ce6ced87b4 100644 --- a/mongodbatlas/resource_mongodbatlas_data_lake.go +++ b/mongodbatlas/resource_mongodbatlas_data_lake.go @@ -545,3 +545,17 @@ func expandDataLakeDataProcessRegion(d *schema.ResourceData) *matlas.DataProcess } return nil } + +func counterEmptyValues(values map[string]interface{}) bool { + count := 0 + for i := range values { + if val, ok := values[i]; ok { + strval, okT := val.(string) + if okT && strval == "" || strval == "false" { + count++ + } + } + } + + return len(values) == count +} diff --git a/mongodbatlas/resource_mongodbatlas_encryption_at_rest.go b/mongodbatlas/resource_mongodbatlas_encryption_at_rest.go deleted file mode 100644 index 1cda7f4bd4..0000000000 --- a/mongodbatlas/resource_mongodbatlas_encryption_at_rest.go +++ /dev/null @@ -1,677 +0,0 @@ -package mongodbatlas - -import ( - "context" - "fmt" - "log" - "net/http" - "strings" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/mwielbut/pointy" - "github.com/spf13/cast" - matlas "go.mongodb.org/atlas/mongodbatlas" -) - -const ( - errorCreateEncryptionAtRest = "error creating Encryption At Rest: %s" - errorReadEncryptionAtRest = "error getting Encryption At Rest: %s" - errorDeleteEncryptionAtRest = "error deleting Encryption At Rest: (%s): %s" - errorUpdateEncryptionAtRest = "error updating Encryption At Rest: %s" - errorAlertEncryptionAtRestSetting = "error setting `%s` for Encryption At Rest (%s): %s" -) - -func resourceMongoDBAtlasEncryptionAtRest() *schema.Resource { - return &schema.Resource{ - CreateContext: resourceMongoDBAtlasEncryptionAtRestCreate, - ReadContext: resourceMongoDBAtlasEncryptionAtRestRead, - DeleteContext: resourceMongoDBAtlasEncryptionAtRestDelete, - UpdateContext: resourceMongoDBAtlasEncryptionAtRestUpdate, - Importer: &schema.ResourceImporter{}, - Schema: map[string]*schema.Schema{ - "project_id": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "aws_kms": { - Type: schema.TypeMap, - Optional: true, - Sensitive: true, - Deprecated: "use aws_kms_config instead", - ConflictsWith: []string{"aws_kms_config"}, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) { - v := val.(map[string]interface{}) - - _, akOk := v["access_key_id"] - _, saOk := v["secret_access_key"] - _, rOk := v["role_id"] - - if (akOk && saOk && rOk) || (akOk && rOk) || (saOk && rOk) { - errs = append(errs, fmt.Errorf("%q For credentials: `access_key_id` and `secret_access_key` are allowed but not `role_id`."+ - " For roles: `access_key_id` and `secret_access_key` are not allowed but `role_id` is allowed", key)) - } - - return - }, - }, - "azure_key_vault": { - Type: schema.TypeMap, - Optional: true, - Sensitive: true, - Deprecated: "use azure_key_vault_config instead", - ConflictsWith: []string{"azure_key_vault_config"}, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "google_cloud_kms": { - Type: schema.TypeMap, - Optional: true, - Sensitive: true, - Deprecated: "use google_cloud_kms_config instead", - ConflictsWith: []string{"google_cloud_kms_config"}, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "aws_kms_config": { - Type: schema.TypeList, - MaxItems: 1, - Optional: true, - Sensitive: true, - ConflictsWith: []string{"aws_kms"}, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "enabled": { - Type: schema.TypeBool, - Optional: true, - }, - "access_key_id": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - }, - "secret_access_key": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - }, - "customer_master_key_id": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - }, - "region": { - Type: schema.TypeString, - Optional: true, - }, - "role_id": { - Type: schema.TypeString, - Optional: true, - }, - }, - }, - }, - "azure_key_vault_config": { - Type: schema.TypeList, - MaxItems: 1, - Optional: true, - Sensitive: true, - ConflictsWith: []string{"azure_key_vault"}, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "enabled": { - Type: schema.TypeBool, - Required: true, - }, - "client_id": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - }, - "azure_environment": { - Type: schema.TypeString, - Optional: true, - }, - "subscription_id": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - }, - "resource_group_name": { - Type: schema.TypeString, - Optional: true, - }, - "key_vault_name": { - Type: schema.TypeString, - Optional: true, - }, - "key_identifier": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - }, - "secret": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - }, - "tenant_id": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - }, - }, - }, - }, - "google_cloud_kms_config": { - Type: schema.TypeList, - MaxItems: 1, - Optional: true, - Sensitive: true, - ConflictsWith: []string{"google_cloud_kms"}, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "enabled": { - Type: schema.TypeBool, - Optional: true, - }, - "service_account_key": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - }, - "key_version_resource_id": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - }, - }, - }, - }, - }, - } -} - -func resourceMongoDBAtlasEncryptionAtRestCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - conn := meta.(*MongoDBClient).Atlas - - encryptionAtRestReq := &matlas.EncryptionAtRest{ - GroupID: d.Get("project_id").(string), - } - - // Deprecated workflows - aws, awsOk := d.GetOk("aws_kms") - if awsOk { - encryptionAtRestReq.AwsKms = expandAwsKms(aws.(map[string]interface{})) - } - azure, azureOk := d.GetOk("azure_key_vault") - if azureOk { - encryptionAtRestReq.AzureKeyVault = expandAzureKeyVault(azure.(map[string]interface{})) - } - gcp, gcpOk := d.GetOk("google_cloud_kms") - if gcpOk { - encryptionAtRestReq.GoogleCloudKms = expandGCPKms(gcp.(map[string]interface{})) - } - - // End Depprecated workflows - - awsC, awsCOk := d.GetOk("aws_kms_config") - if awsCOk { - err := validateAwsKms(awsC.([]interface{})) - if err != nil { - return diag.FromErr(err) - } - encryptionAtRestReq.AwsKms = expandAwsKmsConfig(awsC.([]interface{})) - } - azureC, azureCOk := d.GetOk("azure_key_vault_config") - if azureCOk { - encryptionAtRestReq.AzureKeyVault = expandAzureKeyVaultConfig(azureC.([]interface{})) - } - gcpC, gcpCOk := d.GetOk("google_cloud_kms_config") - if gcpCOk { - encryptionAtRestReq.GoogleCloudKms = expandGCPKmsConfig(gcpC.([]interface{})) - } - - for i := 0; i < 5; i++ { - _, _, err := conn.EncryptionsAtRest.Create(ctx, encryptionAtRestReq) - if err != nil { - if strings.Contains(err.Error(), "CANNOT_ASSUME_ROLE") || strings.Contains(err.Error(), "INVALID_AWS_CREDENTIALS") || - strings.Contains(err.Error(), "CLOUD_PROVIDER_ACCESS_ROLE_NOT_AUTHORIZED") { - log.Printf("warning issue performing authorize EncryptionsAtRest not done try again: %s \n", err.Error()) - log.Println("retrying ") - time.Sleep(10 * time.Second) - encryptionAtRestReq.GroupID = d.Get("project_id").(string) - continue - } - } - if err != nil { - return diag.FromErr(fmt.Errorf(errorCreateEncryptionAtRest, err)) - } - break - } - - d.SetId(d.Get("project_id").(string)) - - return resourceMongoDBAtlasEncryptionAtRestRead(ctx, d, meta) -} - -func resourceMongoDBAtlasEncryptionAtRestRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - conn := meta.(*MongoDBClient).Atlas - - resp, response, err := conn.EncryptionsAtRest.Get(context.Background(), d.Id()) - if err != nil { - if response != nil && response.StatusCode == http.StatusNotFound { - d.SetId("") - return nil - } - - return diag.FromErr(fmt.Errorf(errorReadEncryptionAtRest, err)) - } - - // Deprecated workflows - values := flattenAWSKMS(&resp.AwsKms) - if !counterEmptyValues(values) { - aws, awsOk := d.GetOk("aws_kms") - if awsOk { - aws2 := aws.(map[string]interface{}) - values["secret_access_key"] = cast.ToString(aws2["secret_access_key"]) - if v, sa := values["role_id"]; sa { - if v.(string) == "" { - delete(values, "role_id") - } - } - if v, sa := values["access_key_id"]; sa { - if v.(string) == "" { - delete(values, "access_key_id") - delete(values, "secret_access_key") - } - } - if err = d.Set("aws_kms", values); err != nil { - return diag.FromErr(fmt.Errorf(errorAlertEncryptionAtRestSetting, "aws_kms", d.Id(), err)) - } - } - } - - values = flattenAzureVault(&resp.AzureKeyVault) - if !counterEmptyValues(values) { - azure, azureOk := d.GetOk("azure_key_vault") - if azureOk { - azure2 := azure.(map[string]interface{}) - values["secret"] = cast.ToString(azure2["secret"]) - if v, sa := values["secret"]; sa { - if v.(string) == "" { - delete(values, "secret") - } - } - if err = d.Set("azure_key_vault", values); err != nil { - return diag.FromErr(fmt.Errorf(errorAlertEncryptionAtRestSetting, "azure_key_vault", d.Id(), err)) - } - } - } - - values = flattenGCPKms(&resp.GoogleCloudKms) - if !counterEmptyValues(values) { - gcp, gcpOk := d.GetOk("google_cloud_kms") - if gcpOk { - gcp2 := gcp.(map[string]interface{}) - values["service_account_key"] = cast.ToString(gcp2["service_account_key"]) - if v, sa := values["service_account_key"]; sa { - if v.(string) == "" { - delete(values, "service_account_key") - } - } - if err = d.Set("google_cloud_kms", values); err != nil { - return diag.FromErr(fmt.Errorf(errorAlertEncryptionAtRestSetting, "google_cloud_kms", d.Id(), err)) - } - } - } - // End Deprecated workflows - - values2 := flattenAWSKMSConfig(&resp.AwsKms) - if len(values2) != 0 { - value := values2[0].(map[string]interface{}) - if !counterEmptyValues(value) { - aws, awsOk := d.GetOk("aws_kms_config") - if awsOk { - awsObj := aws.([]interface{}) - if len(awsObj) > 0 { - aws2 := awsObj[0].(map[string]interface{}) - value["secret_access_key"] = cast.ToString(aws2["secret_access_key"]) - if v, sa := value["role_id"]; sa { - if v.(string) == "" { - delete(value, "role_id") - } - } - if v, sa := value["access_key_id"]; sa { - if v.(string) == "" { - delete(value, "access_key_id") - delete(value, "secret_access_key") - } - } - } - } - values2[0] = value - - if err = d.Set("aws_kms_config", values2); err != nil { - return diag.FromErr(fmt.Errorf(errorAlertEncryptionAtRestSetting, "aws_kms_config", d.Id(), err)) - } - } - } - - values2 = flattenAzureVaultConfig(&resp.AzureKeyVault) - if len(values2) != 0 { - value := values2[0].(map[string]interface{}) - - if !counterEmptyValues(value) { - azure, azureOk := d.GetOk("azure_key_vault_config") - if azureOk { - azureObj := azure.([]interface{}) - if len(azureObj) > 0 { - azure2 := azureObj[0].(map[string]interface{}) - value["secret"] = cast.ToString(azure2["secret"]) - if v, sa := value["secret"]; sa { - if v.(string) == "" { - delete(value, "secret") - } - } - } - } - values2[0] = value - - if err = d.Set("azure_key_vault_config", values2); err != nil { - return diag.FromErr(fmt.Errorf(errorAlertEncryptionAtRestSetting, "azure_key_vault_config", d.Id(), err)) - } - } - } - - values2 = flattenGCPKmsConfig(&resp.GoogleCloudKms) - if len(values2) != 0 { - value := values2[0].(map[string]interface{}) - if !counterEmptyValues(value) { - gcp, gcpOk := d.GetOk("google_cloud_kms_config") - if gcpOk { - gcpObj := gcp.([]interface{}) - if len(gcpObj) > 0 { - gcp2 := gcpObj[0].(map[string]interface{}) - value["service_account_key"] = cast.ToString(gcp2["service_account_key"]) - if v, sa := value["service_account_key"]; sa { - if v.(string) == "" { - delete(value, "service_account_key") - } - } - } - } - values2[0] = value - - if err = d.Set("google_cloud_kms_config", values2); err != nil { - return diag.FromErr(fmt.Errorf(errorAlertEncryptionAtRestSetting, "google_cloud_kms_config", d.Id(), err)) - } - } - } - - if err = d.Set("project_id", d.Id()); err != nil { - return diag.FromErr(fmt.Errorf(errorAlertEncryptionAtRestSetting, "project_id", d.Id(), err)) - } - - return nil -} - -func resourceMongoDBAtlasEncryptionAtRestUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - conn := meta.(*MongoDBClient).Atlas - projectID := d.Id() - - encrypt, _, err := conn.EncryptionsAtRest.Get(ctx, projectID) - if err != nil { - return diag.FromErr(fmt.Errorf(errorUpdateEncryptionAtRest, err)) - } - - encrypt.GroupID = projectID - - if d.HasChange("aws_kms") { - encrypt.AwsKms = expandAwsKms(d.Get("aws_kms").(map[string]interface{})) - } - - if d.HasChange("azure_key_vault") { - encrypt.AzureKeyVault = expandAzureKeyVault(d.Get("azure_key_vault").(map[string]interface{})) - } - - if d.HasChange("google_cloud_kms") { - encrypt.GoogleCloudKms = expandGCPKms(d.Get("google_cloud_kms").(map[string]interface{})) - } - - if d.HasChange("aws_kms_config") { - encrypt.AwsKms = expandAwsKmsConfig(d.Get("aws_kms_config").([]interface{})) - } - - if d.HasChange("azure_key_vault_config") { - encrypt.AzureKeyVault = expandAzureKeyVaultConfig(d.Get("azure_key_vault_config").([]interface{})) - } - - if d.HasChange("google_cloud_kms_config") { - encrypt.GoogleCloudKms = expandGCPKmsConfig(d.Get("google_cloud_kms_config").([]interface{})) - } - - _, _, err = conn.EncryptionsAtRest.Create(ctx, encrypt) - if err != nil { - return diag.FromErr(fmt.Errorf("error updating encryption at rest (%s): %s", projectID, err)) - } - - return resourceMongoDBAtlasEncryptionAtRestRead(ctx, d, meta) -} - -func resourceMongoDBAtlasEncryptionAtRestDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - conn := meta.(*MongoDBClient).Atlas - - _, err := conn.EncryptionsAtRest.Delete(ctx, d.Id()) - if err != nil { - return diag.FromErr(fmt.Errorf(errorDeleteEncryptionAtRest, d.Id(), err)) - } - - return nil -} - -func expandAwsKms(awsKms map[string]interface{}) matlas.AwsKms { - awsRegion, _ := valRegion(awsKms["region"]) - - return matlas.AwsKms{ - Enabled: pointy.Bool(cast.ToBool(awsKms["enabled"])), - AccessKeyID: cast.ToString(awsKms["access_key_id"]), - SecretAccessKey: cast.ToString(awsKms["secret_access_key"]), - CustomerMasterKeyID: cast.ToString(awsKms["customer_master_key_id"]), - Region: awsRegion, - RoleID: cast.ToString(awsKms["role_id"]), - } -} - -func expandAzureKeyVault(azure map[string]interface{}) matlas.AzureKeyVault { - return matlas.AzureKeyVault{ - Enabled: pointy.Bool(cast.ToBool(azure["enabled"])), - ClientID: cast.ToString(azure["client_id"]), - AzureEnvironment: cast.ToString(azure["azure_environment"]), - SubscriptionID: cast.ToString(azure["subscription_id"]), - ResourceGroupName: cast.ToString(azure["resource_group_name"]), - KeyVaultName: cast.ToString(azure["key_vault_name"]), - KeyIdentifier: cast.ToString(azure["key_identifier"]), - Secret: cast.ToString(azure["secret"]), - TenantID: cast.ToString(azure["tenant_id"]), - } -} - -func expandGCPKms(gcpKms map[string]interface{}) matlas.GoogleCloudKms { - return matlas.GoogleCloudKms{ - Enabled: pointy.Bool(cast.ToBool(gcpKms["enabled"])), - ServiceAccountKey: cast.ToString(gcpKms["service_account_key"]), - KeyVersionResourceID: cast.ToString(gcpKms["key_version_resource_id"]), - } -} - -func flattenAWSKMS(m *matlas.AwsKms) map[string]interface{} { - return map[string]interface{}{ - "enabled": cast.ToString(m.Enabled), - "access_key_id": m.AccessKeyID, - "customer_master_key_id": m.CustomerMasterKeyID, - "region": m.Region, - "role_id": m.RoleID, - } -} - -func flattenAzureVault(m *matlas.AzureKeyVault) map[string]interface{} { - return map[string]interface{}{ - "enabled": cast.ToString(m.Enabled), - "client_id": m.ClientID, - "azure_environment": m.AzureEnvironment, - "subscription_id": m.SubscriptionID, - "resource_group_name": m.ResourceGroupName, - "key_vault_name": m.KeyVaultName, - "key_identifier": m.KeyIdentifier, - "secret": m.Secret, - "tenant_id": m.TenantID, - } -} - -func flattenGCPKms(m *matlas.GoogleCloudKms) map[string]interface{} { - return map[string]interface{}{ - "enabled": cast.ToString(m.Enabled), - "service_account_key": m.ServiceAccountKey, - "key_version_resource_id": m.KeyVersionResourceID, - } -} - -func expandAwsKmsConfig(awsKms []interface{}) matlas.AwsKms { - if len(awsKms) == 0 { - return matlas.AwsKms{} - } - - awsKmsObj := awsKms[0].(map[string]interface{}) - - awsRegion, _ := valRegion(awsKmsObj["region"]) - - return matlas.AwsKms{ - Enabled: pointy.Bool(cast.ToBool(awsKmsObj["enabled"])), - AccessKeyID: cast.ToString(awsKmsObj["access_key_id"]), - SecretAccessKey: cast.ToString(awsKmsObj["secret_access_key"]), - CustomerMasterKeyID: cast.ToString(awsKmsObj["customer_master_key_id"]), - Region: awsRegion, - RoleID: cast.ToString(awsKmsObj["role_id"]), - } -} - -func validateAwsKms(awsKms []interface{}) error { - if len(awsKms) == 0 { - return fmt.Errorf("empty aws_kms_config") - } - - v := awsKms[0].(map[string]interface{}) - - ak, akOk := v["access_key_id"] - sa, saOk := v["secret_access_key"] - r, rOk := v["role_id"] - - if ((akOk && ak != "") && (saOk && sa != "") && (rOk && r != "")) || ((akOk && ak != "") && (rOk && r != "")) || ((saOk && sa != "") && (rOk && r != "")) { - return fmt.Errorf("for credentials: `access_key_id` and `secret_access_key` are allowed but not `role_id`." + - " For roles: `access_key_id` and `secret_access_key` are not allowed but `role_id` is allowed") - } - - return nil -} - -func expandAzureKeyVaultConfig(azure []interface{}) matlas.AzureKeyVault { - if len(azure) == 0 { - return matlas.AzureKeyVault{} - } - - azureObj := azure[0].(map[string]interface{}) - - return matlas.AzureKeyVault{ - Enabled: pointy.Bool(cast.ToBool(azureObj["enabled"])), - ClientID: cast.ToString(azureObj["client_id"]), - AzureEnvironment: cast.ToString(azureObj["azure_environment"]), - SubscriptionID: cast.ToString(azureObj["subscription_id"]), - ResourceGroupName: cast.ToString(azureObj["resource_group_name"]), - KeyVaultName: cast.ToString(azureObj["key_vault_name"]), - KeyIdentifier: cast.ToString(azureObj["key_identifier"]), - Secret: cast.ToString(azureObj["secret"]), - TenantID: cast.ToString(azureObj["tenant_id"]), - } -} - -func expandGCPKmsConfig(gcpKms []interface{}) matlas.GoogleCloudKms { - if len(gcpKms) == 0 { - return matlas.GoogleCloudKms{} - } - - gcpKmsObj := gcpKms[0].(map[string]interface{}) - - return matlas.GoogleCloudKms{ - Enabled: pointy.Bool(cast.ToBool(gcpKmsObj["enabled"])), - ServiceAccountKey: cast.ToString(gcpKmsObj["service_account_key"]), - KeyVersionResourceID: cast.ToString(gcpKmsObj["key_version_resource_id"]), - } -} - -func flattenAWSKMSConfig(m *matlas.AwsKms) []interface{} { - objMap := make(map[string]interface{}, 1) - - if cast.ToBool(m.Enabled) { - objMap["enabled"] = m.Enabled - } - - objMap["access_key_id"] = m.AccessKeyID - objMap["customer_master_key_id"] = m.CustomerMasterKeyID - objMap["region"] = m.Region - objMap["role_id"] = m.RoleID - - return []interface{}{objMap} -} - -func flattenAzureVaultConfig(m *matlas.AzureKeyVault) []interface{} { - objMap := make(map[string]interface{}, 1) - - if cast.ToBool(m.Enabled) { - objMap["enabled"] = m.Enabled - } - - objMap["client_id"] = m.ClientID - objMap["azure_environment"] = m.AzureEnvironment - objMap["subscription_id"] = m.SubscriptionID - objMap["resource_group_name"] = m.ResourceGroupName - objMap["key_vault_name"] = m.KeyVaultName - objMap["key_identifier"] = m.KeyIdentifier - objMap["secret"] = m.Secret - objMap["tenant_id"] = m.TenantID - - return []interface{}{objMap} -} - -func flattenGCPKmsConfig(m *matlas.GoogleCloudKms) []interface{} { - objMap := make(map[string]interface{}, 1) - - if cast.ToBool(m.Enabled) { - objMap["enabled"] = m.Enabled - } - objMap["service_account_key"] = m.ServiceAccountKey - objMap["key_version_resource_id"] = m.KeyVersionResourceID - - return []interface{}{objMap} -} - -func counterEmptyValues(values map[string]interface{}) bool { - count := 0 - for i := range values { - if val, ok := values[i]; ok { - strval, okT := val.(string) - if okT && strval == "" || strval == "false" { - count++ - } - } - } - - return len(values) == count -} From 1609322bd0ba6bf3829d25bb7680ad5466b24956 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Mon, 14 Aug 2023 13:22:32 +0100 Subject: [PATCH 03/19] fix region --- ...esource_mongodbatlas_encryption_at_rest.go | 125 +++++++++++++++--- ...ce_mongodbatlas_encryption_at_rest_test.go | 37 +++--- 2 files changed, 125 insertions(+), 37 deletions(-) diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go index 5cc7141e25..043910cd37 100644 --- a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go @@ -222,10 +222,12 @@ func (r *EncryptionAtRestRS) Schema(ctx context.Context, req resource.SchemaRequ } func (r *EncryptionAtRestRS) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - var encryptionAtRestPlan tfEncryptionAtRestRSModel + var encryptionAtRestPlan *tfEncryptionAtRestRSModel + var encryptionAtRestConfig *tfEncryptionAtRestRSModel conn := r.client.Atlas resp.Diagnostics.Append(req.Plan.Get(ctx, &encryptionAtRestPlan)...) + resp.Diagnostics.Append(req.Config.Get(ctx, &encryptionAtRestConfig)...) if resp.Diagnostics.HasError() { return } @@ -276,7 +278,8 @@ func (r *EncryptionAtRestRS) Create(ctx context.Context, req resource.CreateRequ return } - encryptionAtRestPlanNew := toTFEncryptionAtRestRSModel(ctx, encryptionResp) + encryptionAtRestPlanNew := toTFEncryptionAtRestRSModel(ctx, projectID, encryptionResp) + resetDefaults(ctx, encryptionAtRestPlan, encryptionAtRestPlanNew, encryptionAtRestConfig) // set state to fully populated data diags := resp.State.Set(ctx, encryptionAtRestPlanNew) @@ -286,6 +289,46 @@ func (r *EncryptionAtRestRS) Create(ctx context.Context, req resource.CreateRequ } } +func resetDefaults(ctx context.Context, encryptionAtRestRS *tfEncryptionAtRestRSModel, encryptionAtRestRSNew *tfEncryptionAtRestRSModel, encryptionAtRestRSConfig *tfEncryptionAtRestRSModel) { + if encryptionAtRestRS.AwsKmsConfig.IsNull() { + tfAwsKmsConfigs := make([]tfAwsKmsConfigModel, 0) + encryptionAtRestRSNew.AwsKmsConfig, _ = types.ListValueFrom(ctx, tfAwsKmsObjectType, tfAwsKmsConfigs) + } else { + + var awsKmsConfigsNew []tfAwsKmsConfigModel + encryptionAtRestRSNew.AwsKmsConfig.ElementsAs(ctx, &awsKmsConfigsNew, false) + + // user may set "region" equal to 'US_EAST_1' or 'US-EAST-1' in config, we ensure to update new plan/state with value that is used in the config + if encryptionAtRestRSConfig != nil { + var awsKmsConfigs []tfAwsKmsConfigModel + encryptionAtRestRSConfig.AwsKmsConfig.ElementsAs(ctx, &awsKmsConfigs, false) + + awsKmsConfigsNew[0].Region = awsKmsConfigs[0].Region + } else { + var awsKmsConfigs []tfAwsKmsConfigModel + encryptionAtRestRS.AwsKmsConfig.ElementsAs(ctx, &awsKmsConfigs, false) + + awsKmsConfigsNew[0].Region = awsKmsConfigs[0].Region + } + encryptionAtRestRSNew.AwsKmsConfig, _ = types.ListValueFrom(ctx, tfAwsKmsObjectType, awsKmsConfigsNew) + } + if encryptionAtRestRS.AzureKeyVaultConfig.IsNull() { + // encryptionAtRestPlanNew.AzureKeyVaultConfig = types.ListNull(tfAzureKeyVaultObjectType) + tfAzKeyVaultConfigs := make([]tfAzureKeyVaultConfigModel, 0) + encryptionAtRestRSNew.AzureKeyVaultConfig, _ = types.ListValueFrom(ctx, tfAzureKeyVaultObjectType, tfAzKeyVaultConfigs) + } + if encryptionAtRestRS.GoogleCloudKmsConfig.IsNull() { + // encryptionAtRestPlanNew.GoogleCloudKmsConfig = types.ListNull(tfGcpKmsObjectType) + tfGcpKmsConfigs := make([]tfGcpKmsConfigModel, 0) + encryptionAtRestRSNew.GoogleCloudKmsConfig, _ = types.ListValueFrom(ctx, tfGcpKmsObjectType, tfGcpKmsConfigs) + + } +} + +func resetDefaultsForRead(encryptionAtRestState *tfEncryptionAtRestRSModel, encryptionAtRestStateNew *tfEncryptionAtRestRSModel) { + +} + func (r *EncryptionAtRestRS) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var encryptionAtRestState tfEncryptionAtRestRSModel @@ -305,7 +348,9 @@ func (r *EncryptionAtRestRS) Read(ctx context.Context, req resource.ReadRequest, return } - encryptionAtRestStateNew := toTFEncryptionAtRestRSModel(ctx, encryptionResp) + encryptionAtRestStateNew := toTFEncryptionAtRestRSModel(ctx, projectID, encryptionResp) + resetDefaults(ctx, &encryptionAtRestState, encryptionAtRestStateNew, nil) + // resetDefaultsForRead(&encryptionAtRestState, encryptionAtRestStateNew) // save read data into Terraform state resp.Diagnostics.Append(resp.State.Set(ctx, &encryptionAtRestStateNew)...) @@ -315,10 +360,16 @@ func (r *EncryptionAtRestRS) Read(ctx context.Context, req resource.ReadRequest, } func (r *EncryptionAtRestRS) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - var encryptionAtRestState tfEncryptionAtRestRSModel - var encryptionAtRestPlan tfEncryptionAtRestRSModel + var encryptionAtRestState *tfEncryptionAtRestRSModel + var encryptionAtRestConfig *tfEncryptionAtRestRSModel + var encryptionAtRestPlan *tfEncryptionAtRestRSModel conn := r.client.Atlas + // get current config + resp.Diagnostics.Append(req.Config.Get(ctx, &encryptionAtRestConfig)...) + if resp.Diagnostics.HasError() { + return + } // get current state resp.Diagnostics.Append(req.State.Get(ctx, &encryptionAtRestState)...) if resp.Diagnostics.HasError() { @@ -340,16 +391,17 @@ func (r *EncryptionAtRestRS) Update(ctx context.Context, req resource.UpdateRequ return } - if !hasAwsKmsConfigChanged(encryptionAtRestPlan.AwsKmsConfig, encryptionAtRestState.AwsKmsConfig) { + if hasAwsKmsConfigChanged(encryptionAtRestPlan.AwsKmsConfig, encryptionAtRestState.AwsKmsConfig) { atlasEncryptionAtRest.AwsKms = *toAtlasAwsKms(ctx, encryptionAtRestPlan.AwsKmsConfig) } - if !hasAzureKeyVaultConfigChanged(encryptionAtRestPlan.AzureKeyVaultConfig, encryptionAtRestState.AzureKeyVaultConfig) { + if hasAzureKeyVaultConfigChanged(encryptionAtRestPlan.AzureKeyVaultConfig, encryptionAtRestState.AzureKeyVaultConfig) { atlasEncryptionAtRest.AzureKeyVault = *toAtlasAzureKeyVault(ctx, encryptionAtRestPlan.AzureKeyVaultConfig) } - if !hasGcpKmsConfigChanged(encryptionAtRestPlan.GoogleCloudKmsConfig, encryptionAtRestState.GoogleCloudKmsConfig) { + if hasGcpKmsConfigChanged(encryptionAtRestPlan.GoogleCloudKmsConfig, encryptionAtRestState.GoogleCloudKmsConfig) { atlasEncryptionAtRest.GoogleCloudKms = *toAtlasGcpKms(ctx, encryptionAtRestPlan.GoogleCloudKmsConfig) } + atlasEncryptionAtRest.GroupID = projectID _, _, err = conn.EncryptionsAtRest.Create(ctx, atlasEncryptionAtRest) if err != nil { resp.Diagnostics.AddError("error updating encryption at rest", fmt.Sprintf(errorUpdateEncryptionAtRest, err.Error())) @@ -368,7 +420,8 @@ func (r *EncryptionAtRestRS) Update(ctx context.Context, req resource.UpdateRequ return } - encryptionAtRestStateNew := toTFEncryptionAtRestRSModel(ctx, encryptionResp) + encryptionAtRestStateNew := toTFEncryptionAtRestRSModel(ctx, projectID, encryptionResp) + resetDefaults(ctx, encryptionAtRestState, encryptionAtRestStateNew, encryptionAtRestConfig) // save updated data into Terraform state resp.Diagnostics.Append(resp.State.Set(ctx, &encryptionAtRestStateNew)...) @@ -409,10 +462,10 @@ func (r *EncryptionAtRestRS) ImportState(ctx context.Context, req resource.Impor resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) } -func toTFEncryptionAtRestRSModel(ctx context.Context, encryptionResp *matlas.EncryptionAtRest) *tfEncryptionAtRestRSModel { +func toTFEncryptionAtRestRSModel(ctx context.Context, projectID string, encryptionResp *matlas.EncryptionAtRest) *tfEncryptionAtRestRSModel { encryptionAtRest := tfEncryptionAtRestRSModel{ - ID: types.StringValue(encryptionResp.GroupID), - ProjectID: types.StringValue(encryptionResp.GroupID), + ID: types.StringValue(projectID), + ProjectID: types.StringValue(projectID), AwsKmsConfig: toTFAwsKmsConfig(ctx, &encryptionResp.AwsKms), AzureKeyVaultConfig: toTFAzureKeyVaultConfig(ctx, &encryptionResp.AzureKeyVault), GoogleCloudKmsConfig: toTFGcpKmsConfig(ctx, &encryptionResp.GoogleCloudKms), @@ -423,12 +476,32 @@ func toTFEncryptionAtRestRSModel(ctx context.Context, encryptionResp *matlas.Enc func toTFAwsKmsConfig(ctx context.Context, awsKms *matlas.AwsKms) types.List { tfAwsKmsConfigs := make([]tfAwsKmsConfigModel, 1) - tfAwsKmsConfigs[0].Enabled = types.BoolPointerValue(awsKms.Enabled) - tfAwsKmsConfigs[0].AccessKeyID = types.StringValue(awsKms.AccessKeyID) - tfAwsKmsConfigs[0].SecretAccessKey = types.StringValue(awsKms.SecretAccessKey) - tfAwsKmsConfigs[0].CustomerMasterKeyID = types.StringValue(awsKms.CustomerMasterKeyID) - tfAwsKmsConfigs[0].Region = types.StringValue(awsKms.Region) - tfAwsKmsConfigs[0].RoleID = types.StringValue(awsKms.RoleID) + if awsKms != nil { + tfAwsKmsConfigs[0].Enabled = types.BoolPointerValue(awsKms.Enabled) + tfAwsKmsConfigs[0].CustomerMasterKeyID = types.StringValue(awsKms.CustomerMasterKeyID) + tfAwsKmsConfigs[0].Region = types.StringValue(awsKms.Region) + + if accessKeyID := awsKms.AccessKeyID; accessKeyID == "" { + tfAwsKmsConfigs[0].AccessKeyID = types.StringNull() + } else { + tfAwsKmsConfigs[0].AccessKeyID = types.StringValue(accessKeyID) + } + // tfAwsKmsConfigs[0].AccessKeyID = types.StringValue(awsKms.AccessKeyID) + + if secretAccessKey := awsKms.SecretAccessKey; secretAccessKey == "" { + tfAwsKmsConfigs[0].SecretAccessKey = types.StringNull() + } else { + tfAwsKmsConfigs[0].SecretAccessKey = types.StringValue(secretAccessKey) + } + // tfAwsKmsConfigs[0].SecretAccessKey = types.StringValue(awsKms.SecretAccessKey) + + if roleID := awsKms.RoleID; roleID == "" { + tfAwsKmsConfigs[0].RoleID = types.StringNull() + } else { + tfAwsKmsConfigs[0].RoleID = types.StringValue(roleID) + } + // tfAwsKmsConfigs[0].RoleID = types.StringValue(awsKms.RoleID) + } list, _ := types.ListValueFrom(ctx, tfAwsKmsObjectType, tfAwsKmsConfigs) return list @@ -444,9 +517,15 @@ func toTFAzureKeyVaultConfig(ctx context.Context, az *matlas.AzureKeyVault) type tfAzKeyVaultConfigs[0].ResourceGroupName = types.StringValue(az.ResourceGroupName) tfAzKeyVaultConfigs[0].KeyVaultName = types.StringValue(az.KeyVaultName) tfAzKeyVaultConfigs[0].KeyIdentifier = types.StringValue(az.KeyIdentifier) - tfAzKeyVaultConfigs[0].Secret = types.StringValue(az.Secret) tfAzKeyVaultConfigs[0].TenantID = types.StringValue(az.TenantID) + if secret := az.Secret; secret == "" { + tfAzKeyVaultConfigs[0].Secret = types.StringNull() + } else { + tfAzKeyVaultConfigs[0].Secret = types.StringValue(secret) + } + // tfAzKeyVaultConfigs[0].Secret = types.StringValue(az.Secret) + list, _ := types.ListValueFrom(ctx, tfAzureKeyVaultObjectType, tfAzKeyVaultConfigs) return list } @@ -455,9 +534,15 @@ func toTFGcpKmsConfig(ctx context.Context, gcpKms *matlas.GoogleCloudKms) types. tfGcpKmsConfigs := make([]tfGcpKmsConfigModel, 1) tfGcpKmsConfigs[0].Enabled = types.BoolPointerValue(gcpKms.Enabled) - tfGcpKmsConfigs[0].ServiceAccountKey = types.StringValue(gcpKms.ServiceAccountKey) + // tfGcpKmsConfigs[0].ServiceAccountKey = types.StringValue(gcpKms.ServiceAccountKey) tfGcpKmsConfigs[0].KeyVersionResourceID = types.StringValue(gcpKms.KeyVersionResourceID) + if serviceAccountKey := gcpKms.ServiceAccountKey; serviceAccountKey == "" { + tfGcpKmsConfigs[0].ServiceAccountKey = types.StringNull() + } else { + tfGcpKmsConfigs[0].ServiceAccountKey = types.StringValue(serviceAccountKey) + } + list, _ := types.ListValueFrom(ctx, tfGcpKmsObjectType, tfGcpKmsConfigs) return list } diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go index 95445f69d2..af66be0e30 100644 --- a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go @@ -99,22 +99,25 @@ data "aws_iam_role" "test" { func TestAccAdvRSEncryptionAtRest_basicAWS(t *testing.T) { var ( resourceName = "mongodbatlas_encryption_at_rest.test" - projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") + // projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") + projectID = "63bec58b014da65b8f73c06c" awsKms = matlas.AwsKms{ - Enabled: pointy.Bool(true), - AccessKeyID: os.Getenv("AWS_ACCESS_KEY_ID"), - SecretAccessKey: os.Getenv("AWS_SECRET_ACCESS_KEY"), + Enabled: pointy.Bool(true), + // AccessKeyID: os.Getenv("AWS_ACCESS_KEY_ID"), + // SecretAccessKey: os.Getenv("AWS_SECRET_ACCESS_KEY"), CustomerMasterKeyID: os.Getenv("AWS_CUSTOMER_MASTER_KEY_ID"), Region: os.Getenv("AWS_REGION"), + RoleID: os.Getenv("AWS_ROLE_ID"), } awsKmsUpdated = matlas.AwsKms{ - Enabled: pointy.Bool(true), - AccessKeyID: os.Getenv("AWS_ACCESS_KEY_ID_UPDATED"), - SecretAccessKey: os.Getenv("AWS_SECRET_ACCESS_KEY_UPDATED"), + Enabled: pointy.Bool(true), + // AccessKeyID: os.Getenv("AWS_ACCESS_KEY_ID_UPDATED"), + // SecretAccessKey: os.Getenv("AWS_SECRET_ACCESS_KEY_UPDATED"), CustomerMasterKeyID: os.Getenv("AWS_CUSTOMER_MASTER_KEY_ID_UPDATED"), Region: os.Getenv("AWS_REGION_UPDATED"), + RoleID: os.Getenv("AWS_ROLE_ID"), } ) @@ -236,15 +239,16 @@ func TestAccAdvRSEncryptionAtRest_basicGCP(t *testing.T) { } func TestAccAdvRSEncryptionAtRestWithRole_basicAWS(t *testing.T) { - SkipTest(t) // For now it will skipped because of aws errors reasons, already made another test using terratest. - SkipTestExtCred(t) + // SkipTest(t) // For now it will skipped because of aws errors reasons, already made another test using terratest. + // SkipTestExtCred(t) var ( resourceName = "mongodbatlas_encryption_at_rest.test" - projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") - accessKeyID = os.Getenv("AWS_ACCESS_KEY_ID") - secretKey = os.Getenv("AWS_SECRET_ACCESS_KEY") - policyName = acctest.RandomWithPrefix("test-aws-policy") - roleName = acctest.RandomWithPrefix("test-aws-role") + // projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") + projectID = "64da133335aa2242e1889109" + accessKeyID = os.Getenv("AWS_ACCESS_KEY_ID") + secretKey = os.Getenv("AWS_SECRET_ACCESS_KEY") + policyName = acctest.RandomWithPrefix("test-aws-policy") + roleName = acctest.RandomWithPrefix("test-aws-role") awsKms = matlas.AwsKms{ Enabled: pointy.Bool(true), @@ -321,13 +325,12 @@ func testAccMongoDBAtlasEncryptionAtRestConfigAwsKms(projectID string, aws *matl aws_kms_config { enabled = %t - access_key_id = "%s" - secret_access_key = "%s" customer_master_key_id = "%s" region = "%s" + role_id = "%s" } } - `, projectID, *aws.Enabled, aws.AccessKeyID, aws.SecretAccessKey, aws.CustomerMasterKeyID, aws.Region) + `, projectID, *aws.Enabled, aws.CustomerMasterKeyID, aws.Region, aws.RoleID) } func testAccMongoDBAtlasEncryptionAtRestConfigAzureKeyVault(projectID string, azure *matlas.AzureKeyVault) string { From 13c0fefd654c6e1505e8a299d14e3f98dfa3e06e Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Tue, 15 Aug 2023 17:05:15 +0100 Subject: [PATCH 04/19] add migration tests --- ...esource_mongodbatlas_encryption_at_rest.go | 4 - ...atlas_encryption_at_rest_migration_test.go | 116 ++++++++++++++++++ ...ce_mongodbatlas_encryption_at_rest_test.go | 12 +- .../docs/r/encryption_at_rest.html.markdown | 3 - 4 files changed, 125 insertions(+), 10 deletions(-) diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go index 043910cd37..42ca70ddb6 100644 --- a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go @@ -325,10 +325,6 @@ func resetDefaults(ctx context.Context, encryptionAtRestRS *tfEncryptionAtRestRS } } -func resetDefaultsForRead(encryptionAtRestState *tfEncryptionAtRestRSModel, encryptionAtRestStateNew *tfEncryptionAtRestRSModel) { - -} - func (r *EncryptionAtRestRS) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var encryptionAtRestState tfEncryptionAtRestRSModel diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_migration_test.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_migration_test.go index 6d2d87bca5..a47c4d35aa 100644 --- a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_migration_test.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_migration_test.go @@ -1 +1,117 @@ package mongodbatlas + +import ( + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/mwielbut/pointy" + matlas "go.mongodb.org/atlas/mongodbatlas" +) + +func TestAccAdvRS_Migration_EncryptionAtRest_basicAWS(t *testing.T) { + var ( + resourceName = "mongodbatlas_encryption_at_rest.test" + // projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") + projectID = "63bec58b014da65b8f73c06c" + + awsKms = matlas.AwsKms{ + Enabled: pointy.Bool(true), + CustomerMasterKeyID: os.Getenv("AWS_CUSTOMER_MASTER_KEY_ID"), + Region: os.Getenv("AWS_REGION"), + RoleID: os.Getenv("AWS_ROLE_ID"), + } + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testCheckAwsEnv(t) }, + CheckDestroy: testAccCheckMongoDBAtlasEncryptionAtRestDestroy, + Steps: []resource.TestStep{ + { + ExternalProviders: map[string]resource.ExternalProvider{ + "mongodbatlas": { + VersionConstraint: "1.11.0", + Source: "mongodb/mongodbatlas", + }, + }, + Config: testAccMongoDBAtlasEncryptionAtRestConfigAwsKms(projectID, &awsKms), + Check: resource.ComposeTestCheckFunc( + testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "project_id", projectID), + ), + }, + { + ProtoV6ProviderFactories: testAccProviderV6Factories, + Config: testAccMongoDBAtlasEncryptionAtRestConfigAwsKms(projectID, &awsKms), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PostApplyPreRefresh: []plancheck.PlanCheck{ + DebugPlan(), + }, + }, + PlanOnly: true, + }, + }, + }) +} + +func TestAccAdvRS_Migration_EncryptionAtRest_WithRole_basicAWS(t *testing.T) { + // SkipTest(t) // For now it will skipped because of aws errors reasons, already made another test using terratest. + // SkipTestExtCred(t) + var ( + resourceName = "mongodbatlas_encryption_at_rest.test" + // projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") + projectID = "63bec58b014da65b8f73c06c" + accessKeyID = os.Getenv("AWS_ACCESS_KEY_ID") + secretKey = os.Getenv("AWS_SECRET_ACCESS_KEY") + policyName = acctest.RandomWithPrefix("test-aws-policy") + roleName = acctest.RandomWithPrefix("test-aws-role") + + awsKms = matlas.AwsKms{ + Enabled: pointy.Bool(true), + CustomerMasterKeyID: os.Getenv("AWS_CUSTOMER_MASTER_KEY_ID"), + Region: os.Getenv("AWS_REGION"), + } + ) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testCheckAwsEnv(t) }, + CheckDestroy: testAccCheckMongoDBAtlasEncryptionAtRestDestroy, + Steps: []resource.TestStep{ + { + ExternalProviders: map[string]resource.ExternalProvider{ + "mongodbatlas": { + VersionConstraint: "1.11.0", + Source: "mongodb/mongodbatlas", + }, + "aws": { + VersionConstraint: "5.1.0", + Source: "hashicorp/aws", + }, + }, + Config: testAccMongoDBAtlasEncryptionAtRestConfigAwsKmsWithRole(awsKms.Region, accessKeyID, secretKey, projectID, policyName, roleName, false, &awsKms), + }, + { + ExternalProviders: map[string]resource.ExternalProvider{ + "aws": { + VersionConstraint: "5.1.0", + Source: "hashicorp/aws", + }, + }, + ProtoV6ProviderFactories: testAccProviderV6Factories, + Config: testAccMongoDBAtlasEncryptionAtRestConfigAwsKmsWithRole(awsKms.Region, accessKeyID, secretKey, projectID, policyName, roleName, false, &awsKms), + Check: resource.ComposeTestCheckFunc( + testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "project_id", projectID), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PostApplyPreRefresh: []plancheck.PlanCheck{ + DebugPlan(), + }, + }, + PlanOnly: true, + }, + }, + }) +} diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go index af66be0e30..4d3250bdb5 100644 --- a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go @@ -81,7 +81,7 @@ EOF resource "mongodbatlas_encryption_at_rest" "test" { project_id = "%s" - aws_kms { + aws_kms_config { enabled = %t customer_master_key_id = "%s" region = "%s" @@ -244,7 +244,7 @@ func TestAccAdvRSEncryptionAtRestWithRole_basicAWS(t *testing.T) { var ( resourceName = "mongodbatlas_encryption_at_rest.test" // projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") - projectID = "64da133335aa2242e1889109" + projectID = "63bec58b014da65b8f73c06c" accessKeyID = os.Getenv("AWS_ACCESS_KEY_ID") secretKey = os.Getenv("AWS_SECRET_ACCESS_KEY") policyName = acctest.RandomWithPrefix("test-aws-policy") @@ -258,7 +258,13 @@ func TestAccAdvRSEncryptionAtRestWithRole_basicAWS(t *testing.T) { ) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testCheckAwsEnv(t) }, + PreCheck: func() { testAccPreCheck(t); testCheckAwsEnv(t) }, + ExternalProviders: map[string]resource.ExternalProvider{ + "aws": { + VersionConstraint: "5.1.0", + Source: "hashicorp/aws", + }, + }, ProtoV6ProviderFactories: testAccProviderV6Factories, CheckDestroy: testAccCheckMongoDBAtlasEncryptionAtRestDestroy, Steps: []resource.TestStep{ diff --git a/website/docs/r/encryption_at_rest.html.markdown b/website/docs/r/encryption_at_rest.html.markdown index d83ea2937d..3169025981 100644 --- a/website/docs/r/encryption_at_rest.html.markdown +++ b/website/docs/r/encryption_at_rest.html.markdown @@ -116,9 +116,6 @@ resource "mongodbatlas_cluster" "example_cluster" { ## Argument Reference * `project_id` - (Required) The unique identifier for the project. -* `aws_kms` - (Required) Specifies AWS KMS configuration details and whether Encryption at Rest is enabled for an Atlas project. -* `azure_key_vault` - (Required) Specifies Azure Key Vault configuration details and whether Encryption at Rest is enabled for an Atlas project. -* `google_cloud_kms` - (Required) Specifies GCP KMS configuration details and whether Encryption at Rest is enabled for an Atlas project. ### aws_kms_config Refer to the example in the [official github repository](https://github.com/mongodb/terraform-provider-mongodbatlas/tree/master/examples) to implement Encryption at Rest From 7450781bad959909977ad2721af573b1ab9912f5 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Wed, 16 Aug 2023 10:27:19 +0100 Subject: [PATCH 05/19] delete old resource --- ...esource_mongodbatlas_encryption_at_rest.go | 677 ------------------ 1 file changed, 677 deletions(-) delete mode 100644 mongodbatlas/resource_mongodbatlas_encryption_at_rest.go diff --git a/mongodbatlas/resource_mongodbatlas_encryption_at_rest.go b/mongodbatlas/resource_mongodbatlas_encryption_at_rest.go deleted file mode 100644 index ac2263e697..0000000000 --- a/mongodbatlas/resource_mongodbatlas_encryption_at_rest.go +++ /dev/null @@ -1,677 +0,0 @@ -package mongodbatlas - -import ( - "context" - "fmt" - "log" - "net/http" - "strings" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/mwielbut/pointy" - "github.com/spf13/cast" - matlas "go.mongodb.org/atlas/mongodbatlas" -) - -const ( - errorCreateEncryptionAtRest = "error creating Encryption At Rest: %s" - errorReadEncryptionAtRest = "error getting Encryption At Rest: %s" - errorDeleteEncryptionAtRest = "error deleting Encryption At Rest: (%s): %s" - errorUpdateEncryptionAtRest = "error updating Encryption At Rest: %s" - errorAlertEncryptionAtRestSetting = "error setting `%s` for Encryption At Rest (%s): %s" -) - -func resourceMongoDBAtlasEncryptionAtRest() *schema.Resource { - return &schema.Resource{ - CreateContext: resourceMongoDBAtlasEncryptionAtRestCreate, - ReadContext: resourceMongoDBAtlasEncryptionAtRestRead, - DeleteContext: resourceMongoDBAtlasEncryptionAtRestDelete, - UpdateContext: resourceMongoDBAtlasEncryptionAtRestUpdate, - Importer: &schema.ResourceImporter{}, - Schema: map[string]*schema.Schema{ - "project_id": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "aws_kms": { - Type: schema.TypeMap, - Optional: true, - Sensitive: true, - Deprecated: fmt.Sprintf(DeprecationMessageParameterToResource, "v1.12.0", "aws_kms_config"), - ConflictsWith: []string{"aws_kms_config"}, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) { - v := val.(map[string]interface{}) - - _, akOk := v["access_key_id"] - _, saOk := v["secret_access_key"] - _, rOk := v["role_id"] - - if (akOk && saOk && rOk) || (akOk && rOk) || (saOk && rOk) { - errs = append(errs, fmt.Errorf("%q For credentials: `access_key_id` and `secret_access_key` are allowed but not `role_id`."+ - " For roles: `access_key_id` and `secret_access_key` are not allowed but `role_id` is allowed", key)) - } - - return - }, - }, - "azure_key_vault": { - Type: schema.TypeMap, - Optional: true, - Sensitive: true, - Deprecated: fmt.Sprintf(DeprecationMessageParameterToResource, "v1.12.0", "azure_key_vault_config"), - ConflictsWith: []string{"azure_key_vault_config"}, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "google_cloud_kms": { - Type: schema.TypeMap, - Optional: true, - Sensitive: true, - Deprecated: fmt.Sprintf(DeprecationMessageParameterToResource, "v1.12.0", "google_cloud_kms_config"), - ConflictsWith: []string{"google_cloud_kms_config"}, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "aws_kms_config": { - Type: schema.TypeList, - MaxItems: 1, - Optional: true, - Sensitive: true, - ConflictsWith: []string{"aws_kms"}, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "enabled": { - Type: schema.TypeBool, - Optional: true, - }, - "access_key_id": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - }, - "secret_access_key": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - }, - "customer_master_key_id": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - }, - "region": { - Type: schema.TypeString, - Optional: true, - }, - "role_id": { - Type: schema.TypeString, - Optional: true, - }, - }, - }, - }, - "azure_key_vault_config": { - Type: schema.TypeList, - MaxItems: 1, - Optional: true, - Sensitive: true, - ConflictsWith: []string{"azure_key_vault"}, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "enabled": { - Type: schema.TypeBool, - Required: true, - }, - "client_id": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - }, - "azure_environment": { - Type: schema.TypeString, - Optional: true, - }, - "subscription_id": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - }, - "resource_group_name": { - Type: schema.TypeString, - Optional: true, - }, - "key_vault_name": { - Type: schema.TypeString, - Optional: true, - }, - "key_identifier": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - }, - "secret": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - }, - "tenant_id": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - }, - }, - }, - }, - "google_cloud_kms_config": { - Type: schema.TypeList, - MaxItems: 1, - Optional: true, - Sensitive: true, - ConflictsWith: []string{"google_cloud_kms"}, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "enabled": { - Type: schema.TypeBool, - Optional: true, - }, - "service_account_key": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - }, - "key_version_resource_id": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - }, - }, - }, - }, - }, - } -} - -func resourceMongoDBAtlasEncryptionAtRestCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - conn := meta.(*MongoDBClient).Atlas - - encryptionAtRestReq := &matlas.EncryptionAtRest{ - GroupID: d.Get("project_id").(string), - } - - // Deprecated workflows - aws, awsOk := d.GetOk("aws_kms") - if awsOk { - encryptionAtRestReq.AwsKms = expandAwsKms(aws.(map[string]interface{})) - } - azure, azureOk := d.GetOk("azure_key_vault") - if azureOk { - encryptionAtRestReq.AzureKeyVault = expandAzureKeyVault(azure.(map[string]interface{})) - } - gcp, gcpOk := d.GetOk("google_cloud_kms") - if gcpOk { - encryptionAtRestReq.GoogleCloudKms = expandGCPKms(gcp.(map[string]interface{})) - } - - // End Depprecated workflows - - awsC, awsCOk := d.GetOk("aws_kms_config") - if awsCOk { - err := validateAwsKms(awsC.([]interface{})) - if err != nil { - return diag.FromErr(err) - } - encryptionAtRestReq.AwsKms = expandAwsKmsConfig(awsC.([]interface{})) - } - azureC, azureCOk := d.GetOk("azure_key_vault_config") - if azureCOk { - encryptionAtRestReq.AzureKeyVault = expandAzureKeyVaultConfig(azureC.([]interface{})) - } - gcpC, gcpCOk := d.GetOk("google_cloud_kms_config") - if gcpCOk { - encryptionAtRestReq.GoogleCloudKms = expandGCPKmsConfig(gcpC.([]interface{})) - } - - for i := 0; i < 5; i++ { - _, _, err := conn.EncryptionsAtRest.Create(ctx, encryptionAtRestReq) - if err != nil { - if strings.Contains(err.Error(), "CANNOT_ASSUME_ROLE") || strings.Contains(err.Error(), "INVALID_AWS_CREDENTIALS") || - strings.Contains(err.Error(), "CLOUD_PROVIDER_ACCESS_ROLE_NOT_AUTHORIZED") { - log.Printf("warning issue performing authorize EncryptionsAtRest not done try again: %s \n", err.Error()) - log.Println("retrying ") - time.Sleep(10 * time.Second) - encryptionAtRestReq.GroupID = d.Get("project_id").(string) - continue - } - } - if err != nil { - return diag.FromErr(fmt.Errorf(errorCreateEncryptionAtRest, err)) - } - break - } - - d.SetId(d.Get("project_id").(string)) - - return resourceMongoDBAtlasEncryptionAtRestRead(ctx, d, meta) -} - -func resourceMongoDBAtlasEncryptionAtRestRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - conn := meta.(*MongoDBClient).Atlas - - resp, response, err := conn.EncryptionsAtRest.Get(context.Background(), d.Id()) - if err != nil { - if response != nil && response.StatusCode == http.StatusNotFound { - d.SetId("") - return nil - } - - return diag.FromErr(fmt.Errorf(errorReadEncryptionAtRest, err)) - } - - // Deprecated workflows - values := flattenAWSKMS(&resp.AwsKms) - if !counterEmptyValues(values) { - aws, awsOk := d.GetOk("aws_kms") - if awsOk { - aws2 := aws.(map[string]interface{}) - values["secret_access_key"] = cast.ToString(aws2["secret_access_key"]) - if v, sa := values["role_id"]; sa { - if v.(string) == "" { - delete(values, "role_id") - } - } - if v, sa := values["access_key_id"]; sa { - if v.(string) == "" { - delete(values, "access_key_id") - delete(values, "secret_access_key") - } - } - if err = d.Set("aws_kms", values); err != nil { - return diag.FromErr(fmt.Errorf(errorAlertEncryptionAtRestSetting, "aws_kms", d.Id(), err)) - } - } - } - - values = flattenAzureVault(&resp.AzureKeyVault) - if !counterEmptyValues(values) { - azure, azureOk := d.GetOk("azure_key_vault") - if azureOk { - azure2 := azure.(map[string]interface{}) - values["secret"] = cast.ToString(azure2["secret"]) - if v, sa := values["secret"]; sa { - if v.(string) == "" { - delete(values, "secret") - } - } - if err = d.Set("azure_key_vault", values); err != nil { - return diag.FromErr(fmt.Errorf(errorAlertEncryptionAtRestSetting, "azure_key_vault", d.Id(), err)) - } - } - } - - values = flattenGCPKms(&resp.GoogleCloudKms) - if !counterEmptyValues(values) { - gcp, gcpOk := d.GetOk("google_cloud_kms") - if gcpOk { - gcp2 := gcp.(map[string]interface{}) - values["service_account_key"] = cast.ToString(gcp2["service_account_key"]) - if v, sa := values["service_account_key"]; sa { - if v.(string) == "" { - delete(values, "service_account_key") - } - } - if err = d.Set("google_cloud_kms", values); err != nil { - return diag.FromErr(fmt.Errorf(errorAlertEncryptionAtRestSetting, "google_cloud_kms", d.Id(), err)) - } - } - } - // End Deprecated workflows - - values2 := flattenAWSKMSConfig(&resp.AwsKms) - if len(values2) != 0 { - value := values2[0].(map[string]interface{}) - if !counterEmptyValues(value) { - aws, awsOk := d.GetOk("aws_kms_config") - if awsOk { - awsObj := aws.([]interface{}) - if len(awsObj) > 0 { - aws2 := awsObj[0].(map[string]interface{}) - value["secret_access_key"] = cast.ToString(aws2["secret_access_key"]) - if v, sa := value["role_id"]; sa { - if v.(string) == "" { - delete(value, "role_id") - } - } - if v, sa := value["access_key_id"]; sa { - if v.(string) == "" { - delete(value, "access_key_id") - delete(value, "secret_access_key") - } - } - } - } - values2[0] = value - - if err = d.Set("aws_kms_config", values2); err != nil { - return diag.FromErr(fmt.Errorf(errorAlertEncryptionAtRestSetting, "aws_kms_config", d.Id(), err)) - } - } - } - - values2 = flattenAzureVaultConfig(&resp.AzureKeyVault) - if len(values2) != 0 { - value := values2[0].(map[string]interface{}) - - if !counterEmptyValues(value) { - azure, azureOk := d.GetOk("azure_key_vault_config") - if azureOk { - azureObj := azure.([]interface{}) - if len(azureObj) > 0 { - azure2 := azureObj[0].(map[string]interface{}) - value["secret"] = cast.ToString(azure2["secret"]) - if v, sa := value["secret"]; sa { - if v.(string) == "" { - delete(value, "secret") - } - } - } - } - values2[0] = value - - if err = d.Set("azure_key_vault_config", values2); err != nil { - return diag.FromErr(fmt.Errorf(errorAlertEncryptionAtRestSetting, "azure_key_vault_config", d.Id(), err)) - } - } - } - - values2 = flattenGCPKmsConfig(&resp.GoogleCloudKms) - if len(values2) != 0 { - value := values2[0].(map[string]interface{}) - if !counterEmptyValues(value) { - gcp, gcpOk := d.GetOk("google_cloud_kms_config") - if gcpOk { - gcpObj := gcp.([]interface{}) - if len(gcpObj) > 0 { - gcp2 := gcpObj[0].(map[string]interface{}) - value["service_account_key"] = cast.ToString(gcp2["service_account_key"]) - if v, sa := value["service_account_key"]; sa { - if v.(string) == "" { - delete(value, "service_account_key") - } - } - } - } - values2[0] = value - - if err = d.Set("google_cloud_kms_config", values2); err != nil { - return diag.FromErr(fmt.Errorf(errorAlertEncryptionAtRestSetting, "google_cloud_kms_config", d.Id(), err)) - } - } - } - - if err = d.Set("project_id", d.Id()); err != nil { - return diag.FromErr(fmt.Errorf(errorAlertEncryptionAtRestSetting, "project_id", d.Id(), err)) - } - - return nil -} - -func resourceMongoDBAtlasEncryptionAtRestUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - conn := meta.(*MongoDBClient).Atlas - projectID := d.Id() - - encrypt, _, err := conn.EncryptionsAtRest.Get(ctx, projectID) - if err != nil { - return diag.FromErr(fmt.Errorf(errorUpdateEncryptionAtRest, err)) - } - - encrypt.GroupID = projectID - - if d.HasChange("aws_kms") { - encrypt.AwsKms = expandAwsKms(d.Get("aws_kms").(map[string]interface{})) - } - - if d.HasChange("azure_key_vault") { - encrypt.AzureKeyVault = expandAzureKeyVault(d.Get("azure_key_vault").(map[string]interface{})) - } - - if d.HasChange("google_cloud_kms") { - encrypt.GoogleCloudKms = expandGCPKms(d.Get("google_cloud_kms").(map[string]interface{})) - } - - if d.HasChange("aws_kms_config") { - encrypt.AwsKms = expandAwsKmsConfig(d.Get("aws_kms_config").([]interface{})) - } - - if d.HasChange("azure_key_vault_config") { - encrypt.AzureKeyVault = expandAzureKeyVaultConfig(d.Get("azure_key_vault_config").([]interface{})) - } - - if d.HasChange("google_cloud_kms_config") { - encrypt.GoogleCloudKms = expandGCPKmsConfig(d.Get("google_cloud_kms_config").([]interface{})) - } - - _, _, err = conn.EncryptionsAtRest.Create(ctx, encrypt) - if err != nil { - return diag.FromErr(fmt.Errorf("error updating encryption at rest (%s): %s", projectID, err)) - } - - return resourceMongoDBAtlasEncryptionAtRestRead(ctx, d, meta) -} - -func resourceMongoDBAtlasEncryptionAtRestDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - conn := meta.(*MongoDBClient).Atlas - - _, err := conn.EncryptionsAtRest.Delete(ctx, d.Id()) - if err != nil { - return diag.FromErr(fmt.Errorf(errorDeleteEncryptionAtRest, d.Id(), err)) - } - - return nil -} - -func expandAwsKms(awsKms map[string]interface{}) matlas.AwsKms { - awsRegion, _ := valRegion(awsKms["region"]) - - return matlas.AwsKms{ - Enabled: pointy.Bool(cast.ToBool(awsKms["enabled"])), - AccessKeyID: cast.ToString(awsKms["access_key_id"]), - SecretAccessKey: cast.ToString(awsKms["secret_access_key"]), - CustomerMasterKeyID: cast.ToString(awsKms["customer_master_key_id"]), - Region: awsRegion, - RoleID: cast.ToString(awsKms["role_id"]), - } -} - -func expandAzureKeyVault(azure map[string]interface{}) matlas.AzureKeyVault { - return matlas.AzureKeyVault{ - Enabled: pointy.Bool(cast.ToBool(azure["enabled"])), - ClientID: cast.ToString(azure["client_id"]), - AzureEnvironment: cast.ToString(azure["azure_environment"]), - SubscriptionID: cast.ToString(azure["subscription_id"]), - ResourceGroupName: cast.ToString(azure["resource_group_name"]), - KeyVaultName: cast.ToString(azure["key_vault_name"]), - KeyIdentifier: cast.ToString(azure["key_identifier"]), - Secret: cast.ToString(azure["secret"]), - TenantID: cast.ToString(azure["tenant_id"]), - } -} - -func expandGCPKms(gcpKms map[string]interface{}) matlas.GoogleCloudKms { - return matlas.GoogleCloudKms{ - Enabled: pointy.Bool(cast.ToBool(gcpKms["enabled"])), - ServiceAccountKey: cast.ToString(gcpKms["service_account_key"]), - KeyVersionResourceID: cast.ToString(gcpKms["key_version_resource_id"]), - } -} - -func flattenAWSKMS(m *matlas.AwsKms) map[string]interface{} { - return map[string]interface{}{ - "enabled": cast.ToString(m.Enabled), - "access_key_id": m.AccessKeyID, - "customer_master_key_id": m.CustomerMasterKeyID, - "region": m.Region, - "role_id": m.RoleID, - } -} - -func flattenAzureVault(m *matlas.AzureKeyVault) map[string]interface{} { - return map[string]interface{}{ - "enabled": cast.ToString(m.Enabled), - "client_id": m.ClientID, - "azure_environment": m.AzureEnvironment, - "subscription_id": m.SubscriptionID, - "resource_group_name": m.ResourceGroupName, - "key_vault_name": m.KeyVaultName, - "key_identifier": m.KeyIdentifier, - "secret": m.Secret, - "tenant_id": m.TenantID, - } -} - -func flattenGCPKms(m *matlas.GoogleCloudKms) map[string]interface{} { - return map[string]interface{}{ - "enabled": cast.ToString(m.Enabled), - "service_account_key": m.ServiceAccountKey, - "key_version_resource_id": m.KeyVersionResourceID, - } -} - -func expandAwsKmsConfig(awsKms []interface{}) matlas.AwsKms { - if len(awsKms) == 0 { - return matlas.AwsKms{} - } - - awsKmsObj := awsKms[0].(map[string]interface{}) - - awsRegion, _ := valRegion(awsKmsObj["region"]) - - return matlas.AwsKms{ - Enabled: pointy.Bool(cast.ToBool(awsKmsObj["enabled"])), - AccessKeyID: cast.ToString(awsKmsObj["access_key_id"]), - SecretAccessKey: cast.ToString(awsKmsObj["secret_access_key"]), - CustomerMasterKeyID: cast.ToString(awsKmsObj["customer_master_key_id"]), - Region: awsRegion, - RoleID: cast.ToString(awsKmsObj["role_id"]), - } -} - -func validateAwsKms(awsKms []interface{}) error { - if len(awsKms) == 0 { - return fmt.Errorf("empty aws_kms_config") - } - - v := awsKms[0].(map[string]interface{}) - - ak, akOk := v["access_key_id"] - sa, saOk := v["secret_access_key"] - r, rOk := v["role_id"] - - if ((akOk && ak != "") && (saOk && sa != "") && (rOk && r != "")) || ((akOk && ak != "") && (rOk && r != "")) || ((saOk && sa != "") && (rOk && r != "")) { - return fmt.Errorf("for credentials: `access_key_id` and `secret_access_key` are allowed but not `role_id`." + - " For roles: `access_key_id` and `secret_access_key` are not allowed but `role_id` is allowed") - } - - return nil -} - -func expandAzureKeyVaultConfig(azure []interface{}) matlas.AzureKeyVault { - if len(azure) == 0 { - return matlas.AzureKeyVault{} - } - - azureObj := azure[0].(map[string]interface{}) - - return matlas.AzureKeyVault{ - Enabled: pointy.Bool(cast.ToBool(azureObj["enabled"])), - ClientID: cast.ToString(azureObj["client_id"]), - AzureEnvironment: cast.ToString(azureObj["azure_environment"]), - SubscriptionID: cast.ToString(azureObj["subscription_id"]), - ResourceGroupName: cast.ToString(azureObj["resource_group_name"]), - KeyVaultName: cast.ToString(azureObj["key_vault_name"]), - KeyIdentifier: cast.ToString(azureObj["key_identifier"]), - Secret: cast.ToString(azureObj["secret"]), - TenantID: cast.ToString(azureObj["tenant_id"]), - } -} - -func expandGCPKmsConfig(gcpKms []interface{}) matlas.GoogleCloudKms { - if len(gcpKms) == 0 { - return matlas.GoogleCloudKms{} - } - - gcpKmsObj := gcpKms[0].(map[string]interface{}) - - return matlas.GoogleCloudKms{ - Enabled: pointy.Bool(cast.ToBool(gcpKmsObj["enabled"])), - ServiceAccountKey: cast.ToString(gcpKmsObj["service_account_key"]), - KeyVersionResourceID: cast.ToString(gcpKmsObj["key_version_resource_id"]), - } -} - -func flattenAWSKMSConfig(m *matlas.AwsKms) []interface{} { - objMap := make(map[string]interface{}, 1) - - if cast.ToBool(m.Enabled) { - objMap["enabled"] = m.Enabled - } - - objMap["access_key_id"] = m.AccessKeyID - objMap["customer_master_key_id"] = m.CustomerMasterKeyID - objMap["region"] = m.Region - objMap["role_id"] = m.RoleID - - return []interface{}{objMap} -} - -func flattenAzureVaultConfig(m *matlas.AzureKeyVault) []interface{} { - objMap := make(map[string]interface{}, 1) - - if cast.ToBool(m.Enabled) { - objMap["enabled"] = m.Enabled - } - - objMap["client_id"] = m.ClientID - objMap["azure_environment"] = m.AzureEnvironment - objMap["subscription_id"] = m.SubscriptionID - objMap["resource_group_name"] = m.ResourceGroupName - objMap["key_vault_name"] = m.KeyVaultName - objMap["key_identifier"] = m.KeyIdentifier - objMap["secret"] = m.Secret - objMap["tenant_id"] = m.TenantID - - return []interface{}{objMap} -} - -func flattenGCPKmsConfig(m *matlas.GoogleCloudKms) []interface{} { - objMap := make(map[string]interface{}, 1) - - if cast.ToBool(m.Enabled) { - objMap["enabled"] = m.Enabled - } - objMap["service_account_key"] = m.ServiceAccountKey - objMap["key_version_resource_id"] = m.KeyVersionResourceID - - return []interface{}{objMap} -} - -func counterEmptyValues(values map[string]interface{}) bool { - count := 0 - for i := range values { - if val, ok := values[i]; ok { - strval, okT := val.(string) - if okT && strval == "" || strval == "false" { - count++ - } - } - } - - return len(values) == count -} From 14df35056397671db49ebaf902c0b8ac72bf2c8d Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Wed, 16 Aug 2023 14:17:45 +0100 Subject: [PATCH 06/19] fix azure reset logic --- ...esource_mongodbatlas_encryption_at_rest.go | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go index 42ca70ddb6..ea12538321 100644 --- a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go @@ -9,6 +9,8 @@ import ( "strings" "time" + matlas "go.mongodb.org/atlas/mongodbatlas" + "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/path" @@ -20,8 +22,8 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-log/tflog" + validators "github.com/mongodb/terraform-provider-mongodbatlas/mongodbatlas/framework/validator" - matlas "go.mongodb.org/atlas/mongodbatlas" ) const ( @@ -316,7 +318,25 @@ func resetDefaults(ctx context.Context, encryptionAtRestRS *tfEncryptionAtRestRS // encryptionAtRestPlanNew.AzureKeyVaultConfig = types.ListNull(tfAzureKeyVaultObjectType) tfAzKeyVaultConfigs := make([]tfAzureKeyVaultConfigModel, 0) encryptionAtRestRSNew.AzureKeyVaultConfig, _ = types.ListValueFrom(ctx, tfAzureKeyVaultObjectType, tfAzKeyVaultConfigs) + } else { + + var azureConfigsNew []tfAzureKeyVaultConfigModel + encryptionAtRestRSNew.AzureKeyVaultConfig.ElementsAs(ctx, &azureConfigsNew, false) + + if encryptionAtRestRSConfig != nil { + var azureConfigs []tfAzureKeyVaultConfigModel + encryptionAtRestRSConfig.AzureKeyVaultConfig.ElementsAs(ctx, &azureConfigs, false) + + azureConfigsNew[0].Secret = azureConfigs[0].Secret + } else { + var azureConfigs []tfAzureKeyVaultConfigModel + encryptionAtRestRS.AzureKeyVaultConfig.ElementsAs(ctx, &azureConfigs, false) + + azureConfigsNew[0].Secret = azureConfigs[0].Secret + } + encryptionAtRestRSNew.AzureKeyVaultConfig, _ = types.ListValueFrom(ctx, tfAzureKeyVaultObjectType, azureConfigsNew) } + if encryptionAtRestRS.GoogleCloudKmsConfig.IsNull() { // encryptionAtRestPlanNew.GoogleCloudKmsConfig = types.ListNull(tfGcpKmsObjectType) tfGcpKmsConfigs := make([]tfGcpKmsConfigModel, 0) From de73d9c71a15869c86173190f58ac5b53edac597 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Fri, 18 Aug 2023 10:10:38 +0100 Subject: [PATCH 07/19] temp --- .../fw_resource_mongodbatlas_encryption_at_rest_test.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go index 4d3250bdb5..ea41928a43 100644 --- a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go @@ -6,12 +6,12 @@ import ( "os" "testing" - "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + matlas "go.mongodb.org/atlas/mongodbatlas" + "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/mwielbut/pointy" - matlas "go.mongodb.org/atlas/mongodbatlas" ) const ( @@ -200,7 +200,8 @@ func TestAccAdvRSEncryptionAtRest_basicAzure(t *testing.T) { func TestAccAdvRSEncryptionAtRest_basicGCP(t *testing.T) { var ( resourceName = "mongodbatlas_encryption_at_rest.test" - projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") + // projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") + projectID = "63bec58b014da65b8f73c06c" googleCloudKms = matlas.GoogleCloudKms{ Enabled: pointy.Bool(true), From 5216baa851f4e623d7bdb93c78c74199e6624687 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Tue, 22 Aug 2023 19:03:43 +0100 Subject: [PATCH 08/19] add migration tests --- ...esource_mongodbatlas_encryption_at_rest.go | 16 +++ ...atlas_encryption_at_rest_migration_test.go | 120 ++++++++++++++++-- ...ce_mongodbatlas_encryption_at_rest_test.go | 90 +++++++++++-- 3 files changed, 207 insertions(+), 19 deletions(-) diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go index ea12538321..880ab7cb5f 100644 --- a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go @@ -341,6 +341,22 @@ func resetDefaults(ctx context.Context, encryptionAtRestRS *tfEncryptionAtRestRS // encryptionAtRestPlanNew.GoogleCloudKmsConfig = types.ListNull(tfGcpKmsObjectType) tfGcpKmsConfigs := make([]tfGcpKmsConfigModel, 0) encryptionAtRestRSNew.GoogleCloudKmsConfig, _ = types.ListValueFrom(ctx, tfGcpKmsObjectType, tfGcpKmsConfigs) + } else { + var gcpConfigsNew []tfGcpKmsConfigModel + encryptionAtRestRSNew.GoogleCloudKmsConfig.ElementsAs(ctx, &gcpConfigsNew, false) + + if encryptionAtRestRSConfig != nil { + var gcpConfigs []tfGcpKmsConfigModel + encryptionAtRestRSConfig.GoogleCloudKmsConfig.ElementsAs(ctx, &gcpConfigs, false) + + gcpConfigsNew[0].ServiceAccountKey = gcpConfigs[0].ServiceAccountKey + } else { + var gcpConfigs []tfGcpKmsConfigModel + encryptionAtRestRS.GoogleCloudKmsConfig.ElementsAs(ctx, &gcpConfigs, false) + + gcpConfigsNew[0].ServiceAccountKey = gcpConfigs[0].ServiceAccountKey + } + encryptionAtRestRSNew.GoogleCloudKmsConfig, _ = types.ListValueFrom(ctx, tfGcpKmsObjectType, gcpConfigsNew) } } diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_migration_test.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_migration_test.go index a47c4d35aa..cc3815bb22 100644 --- a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_migration_test.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_migration_test.go @@ -4,18 +4,18 @@ import ( "os" "testing" + matlas "go.mongodb.org/atlas/mongodbatlas" + "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/plancheck" "github.com/mwielbut/pointy" - matlas "go.mongodb.org/atlas/mongodbatlas" ) func TestAccAdvRS_Migration_EncryptionAtRest_basicAWS(t *testing.T) { var ( resourceName = "mongodbatlas_encryption_at_rest.test" - // projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") - projectID = "63bec58b014da65b8f73c06c" + projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") awsKms = matlas.AwsKms{ Enabled: pointy.Bool(true), @@ -40,6 +40,9 @@ func TestAccAdvRS_Migration_EncryptionAtRest_basicAWS(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName), resource.TestCheckResourceAttr(resourceName, "project_id", projectID), + resource.TestCheckResourceAttr(resourceName, "aws_kms_config.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "aws_kms_config.0.region", awsKms.Region), + resource.TestCheckResourceAttr(resourceName, "aws_kms_config.0.role_id", awsKms.RoleID), ), }, { @@ -61,12 +64,11 @@ func TestAccAdvRS_Migration_EncryptionAtRest_WithRole_basicAWS(t *testing.T) { // SkipTestExtCred(t) var ( resourceName = "mongodbatlas_encryption_at_rest.test" - // projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") - projectID = "63bec58b014da65b8f73c06c" - accessKeyID = os.Getenv("AWS_ACCESS_KEY_ID") - secretKey = os.Getenv("AWS_SECRET_ACCESS_KEY") - policyName = acctest.RandomWithPrefix("test-aws-policy") - roleName = acctest.RandomWithPrefix("test-aws-role") + projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") + accessKeyID = os.Getenv("AWS_ACCESS_KEY_ID") + secretKey = os.Getenv("AWS_SECRET_ACCESS_KEY") + policyName = acctest.RandomWithPrefix("test-aws-policy") + roleName = acctest.RandomWithPrefix("test-aws-role") awsKms = matlas.AwsKms{ Enabled: pointy.Bool(true), @@ -104,7 +106,107 @@ func TestAccAdvRS_Migration_EncryptionAtRest_WithRole_basicAWS(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName), resource.TestCheckResourceAttr(resourceName, "project_id", projectID), + resource.TestCheckResourceAttr(resourceName, "aws_kms_config.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "aws_kms_config.0.region", awsKms.Region), + resource.TestCheckResourceAttr(resourceName, "aws_kms_config.0.role_id", awsKms.RoleID), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PostApplyPreRefresh: []plancheck.PlanCheck{ + DebugPlan(), + }, + }, + PlanOnly: true, + }, + }, + }) +} + +func TestAccAdvRS_Migration_EncryptionAtRest_basicAzure(t *testing.T) { + var ( + resourceName = "mongodbatlas_encryption_at_rest.test" + projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") + + azureKeyVault = matlas.AzureKeyVault{ + Enabled: pointy.Bool(true), + ClientID: os.Getenv("AZURE_CLIENT_ID"), + AzureEnvironment: "AZURE", + SubscriptionID: os.Getenv("AZURE_SUBSCRIPTION_ID"), + ResourceGroupName: os.Getenv("AZURE_RESOURCE_GROUP_NAME"), + KeyVaultName: os.Getenv("AZURE_KEY_VAULT_NAME"), + KeyIdentifier: os.Getenv("AZURE_KEY_IDENTIFIER"), + Secret: os.Getenv("AZURE_SECRET"), + TenantID: os.Getenv("AZURE_TENANT_ID"), + } + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testCheckEncryptionAtRestEnvAzure(t) }, + CheckDestroy: testAccCheckMongoDBAtlasEncryptionAtRestDestroy, + Steps: []resource.TestStep{ + { + ExternalProviders: map[string]resource.ExternalProvider{ + "mongodbatlas": { + VersionConstraint: "1.11.0", + Source: "mongodb/mongodbatlas", + }, + }, + Config: testAccMongoDBAtlasEncryptionAtRestConfigAzureKeyVault(projectID, &azureKeyVault), + Check: resource.ComposeTestCheckFunc( + testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "project_id", projectID), + resource.TestCheckResourceAttr(resourceName, "azure_key_vault_config.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "azure_key_vault_config.0.azure_environment", azureKeyVault.AzureEnvironment), + resource.TestCheckResourceAttr(resourceName, "azure_key_vault_config.0.resource_group_name", azureKeyVault.ResourceGroupName), + resource.TestCheckResourceAttr(resourceName, "azure_key_vault_config.0.key_vault_name", azureKeyVault.KeyVaultName), ), + }, + { + ProtoV6ProviderFactories: testAccProviderV6Factories, + Config: testAccMongoDBAtlasEncryptionAtRestConfigAzureKeyVault(projectID, &azureKeyVault), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PostApplyPreRefresh: []plancheck.PlanCheck{ + DebugPlan(), + }, + }, + PlanOnly: true, + }, + }, + }) +} + +func TestAccAdvRS_Migration_EncryptionAtRest_basicGCP(t *testing.T) { + var ( + resourceName = "mongodbatlas_encryption_at_rest.test" + projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") + + googleCloudKms = matlas.GoogleCloudKms{ + Enabled: pointy.Bool(true), + ServiceAccountKey: os.Getenv("GCP_SERVICE_ACCOUNT_KEY"), + KeyVersionResourceID: os.Getenv("GCP_KEY_VERSION_RESOURCE_ID"), + } + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckGPCEnv(t) }, + CheckDestroy: testAccCheckMongoDBAtlasEncryptionAtRestDestroy, + Steps: []resource.TestStep{ + { + ExternalProviders: map[string]resource.ExternalProvider{ + "mongodbatlas": { + VersionConstraint: "1.11.0", + Source: "mongodb/mongodbatlas", + }, + }, + Config: testAccMongoDBAtlasEncryptionAtRestConfigGoogleCloudKms(projectID, &googleCloudKms), + Check: resource.ComposeTestCheckFunc( + testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "project_id", projectID), + resource.TestCheckResourceAttr(resourceName, "google_cloud_kms_config.0.enabled", "true"), + ), + }, + { + ProtoV6ProviderFactories: testAccProviderV6Factories, + Config: testAccMongoDBAtlasEncryptionAtRestConfigGoogleCloudKms(projectID, &googleCloudKms), ConfigPlanChecks: resource.ConfigPlanChecks{ PostApplyPreRefresh: []plancheck.PlanCheck{ DebugPlan(), diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go index ea41928a43..0f10d181b2 100644 --- a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go @@ -99,8 +99,7 @@ data "aws_iam_role" "test" { func TestAccAdvRSEncryptionAtRest_basicAWS(t *testing.T) { var ( resourceName = "mongodbatlas_encryption_at_rest.test" - // projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") - projectID = "63bec58b014da65b8f73c06c" + projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") awsKms = matlas.AwsKms{ Enabled: pointy.Bool(true), @@ -131,6 +130,9 @@ func TestAccAdvRSEncryptionAtRest_basicAWS(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName), resource.TestCheckResourceAttr(resourceName, "project_id", projectID), + resource.TestCheckResourceAttr(resourceName, "aws_kms_config.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "aws_kms_config.0.region", awsKms.Region), + resource.TestCheckResourceAttr(resourceName, "aws_kms_config.0.role_id", awsKms.RoleID), ), }, { @@ -138,6 +140,9 @@ func TestAccAdvRSEncryptionAtRest_basicAWS(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName), resource.TestCheckResourceAttr(resourceName, "project_id", projectID), + resource.TestCheckResourceAttr(resourceName, "aws_kms_config.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "aws_kms_config.0.region", awsKmsUpdated.Region), + resource.TestCheckResourceAttr(resourceName, "aws_kms_config.0.role_id", awsKmsUpdated.RoleID), ), }, }, @@ -184,6 +189,10 @@ func TestAccAdvRSEncryptionAtRest_basicAzure(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName), resource.TestCheckResourceAttr(resourceName, "project_id", projectID), + resource.TestCheckResourceAttr(resourceName, "azure_key_vault_config.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "azure_key_vault_config.0.azure_environment", azureKeyVault.AzureEnvironment), + resource.TestCheckResourceAttr(resourceName, "azure_key_vault_config.0.resource_group_name", azureKeyVault.ResourceGroupName), + resource.TestCheckResourceAttr(resourceName, "azure_key_vault_config.0.key_vault_name", azureKeyVault.KeyVaultName), ), }, { @@ -191,6 +200,10 @@ func TestAccAdvRSEncryptionAtRest_basicAzure(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName), resource.TestCheckResourceAttr(resourceName, "project_id", projectID), + resource.TestCheckResourceAttr(resourceName, "azure_key_vault_config.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "azure_key_vault_config.0.azure_environment", azureKeyVaultUpdated.AzureEnvironment), + resource.TestCheckResourceAttr(resourceName, "azure_key_vault_config.0.resource_group_name", azureKeyVaultUpdated.ResourceGroupName), + resource.TestCheckResourceAttr(resourceName, "azure_key_vault_config.0.key_vault_name", azureKeyVaultUpdated.KeyVaultName), ), }, }, @@ -200,8 +213,7 @@ func TestAccAdvRSEncryptionAtRest_basicAzure(t *testing.T) { func TestAccAdvRSEncryptionAtRest_basicGCP(t *testing.T) { var ( resourceName = "mongodbatlas_encryption_at_rest.test" - // projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") - projectID = "63bec58b014da65b8f73c06c" + projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") googleCloudKms = matlas.GoogleCloudKms{ Enabled: pointy.Bool(true), @@ -226,6 +238,7 @@ func TestAccAdvRSEncryptionAtRest_basicGCP(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName), resource.TestCheckResourceAttr(resourceName, "project_id", projectID), + resource.TestCheckResourceAttr(resourceName, "google_cloud_kms_config.0.enabled", "true"), ), }, { @@ -233,6 +246,7 @@ func TestAccAdvRSEncryptionAtRest_basicGCP(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName), resource.TestCheckResourceAttr(resourceName, "project_id", projectID), + resource.TestCheckResourceAttr(resourceName, "google_cloud_kms_config.0.enabled", "true"), ), }, }, @@ -244,12 +258,11 @@ func TestAccAdvRSEncryptionAtRestWithRole_basicAWS(t *testing.T) { // SkipTestExtCred(t) var ( resourceName = "mongodbatlas_encryption_at_rest.test" - // projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") - projectID = "63bec58b014da65b8f73c06c" - accessKeyID = os.Getenv("AWS_ACCESS_KEY_ID") - secretKey = os.Getenv("AWS_SECRET_ACCESS_KEY") - policyName = acctest.RandomWithPrefix("test-aws-policy") - roleName = acctest.RandomWithPrefix("test-aws-role") + projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") + accessKeyID = os.Getenv("AWS_ACCESS_KEY_ID") + secretKey = os.Getenv("AWS_SECRET_ACCESS_KEY") + policyName = acctest.RandomWithPrefix("test-aws-policy") + roleName = acctest.RandomWithPrefix("test-aws-role") awsKms = matlas.AwsKms{ Enabled: pointy.Bool(true), @@ -277,12 +290,69 @@ func TestAccAdvRSEncryptionAtRestWithRole_basicAWS(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName), resource.TestCheckResourceAttr(resourceName, "project_id", projectID), + resource.TestCheckResourceAttr(resourceName, "project_id", projectID), ), }, }, }) } +func TestAccAdvRSEncryptionAtRest_basicAWS_WithAccessKey(t *testing.T) { + var ( + resourceName = "mongodbatlas_encryption_at_rest.test" + projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") + + awsKms = matlas.AwsKms{ + Enabled: pointy.Bool(true), + AccessKeyID: os.Getenv("AWS_ACCESS_KEY_ID"), + SecretAccessKey: os.Getenv("AWS_SECRET_ACCESS_KEY"), + CustomerMasterKeyID: os.Getenv("AWS_CUSTOMER_MASTER_KEY_ID"), + Region: os.Getenv("AWS_REGION"), + // RoleID: os.Getenv("AWS_ROLE_ID"), + } + + // awsKmsUpdated = matlas.AwsKms{ + // Enabled: pointy.Bool(true), + // AccessKeyID: os.Getenv("AWS_ACCESS_KEY_ID_UPDATED"), + // SecretAccessKey: os.Getenv("AWS_SECRET_ACCESS_KEY_UPDATED"), + // CustomerMasterKeyID: os.Getenv("AWS_CUSTOMER_MASTER_KEY_ID_UPDATED"), + // Region: os.Getenv("AWS_REGION_UPDATED"), + // // RoleID: os.Getenv("AWS_ROLE_ID"), + // } + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testCheckAwsEnv(t) }, + ProtoV6ProviderFactories: testAccProviderV6Factories, + CheckDestroy: testAccCheckMongoDBAtlasEncryptionAtRestDestroy, + Steps: []resource.TestStep{ + { + Config: testAccMongoDBAtlasEncryptionAtRestConfigAwsKmsWithAccessKeys(projectID, &awsKms), + Check: resource.ComposeTestCheckFunc( + testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "project_id", projectID), + ), + }, + }, + }) +} + +func testAccMongoDBAtlasEncryptionAtRestConfigAwsKmsWithAccessKeys(projectID string, aws *matlas.AwsKms) string { + return fmt.Sprintf(` + resource "mongodbatlas_encryption_at_rest" "test" { + project_id = "%s" + + aws_kms_config { + enabled = %t + customer_master_key_id = "%s" + region = "%s" + access_key_id = "%s" + secret_access_key = "%s" + } + } + `, projectID, *aws.Enabled, aws.CustomerMasterKeyID, aws.Region, aws.AccessKeyID, aws.SecretAccessKey) +} + func testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { conn := testMongoDBClient.(*MongoDBClient).Atlas From 22cfab53db7d714c0e1568103a36c810e549de83 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Tue, 22 Aug 2023 19:06:44 +0100 Subject: [PATCH 09/19] add migration tests --- mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go index 880ab7cb5f..1ac0a5306c 100644 --- a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go @@ -108,7 +108,7 @@ func (r *EncryptionAtRestRS) Metadata(ctx context.Context, req resource.Metadata } func (r *EncryptionAtRestRS) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { - client, err := ConfigureClientInResource(req.ProviderData) + client, err := ConfigureClient(req.ProviderData) if err != nil { resp.Diagnostics.AddError(errorConfigureSummary, err.Error()) return From 7c01d1e99730812d7665d485cc43de5eb4baf9ec Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Tue, 22 Aug 2023 19:46:09 +0100 Subject: [PATCH 10/19] add validator tests --- .../aws_kms_config_validator_test.go | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 mongodbatlas/framework/validator/aws_kms_config_validator_test.go diff --git a/mongodbatlas/framework/validator/aws_kms_config_validator_test.go b/mongodbatlas/framework/validator/aws_kms_config_validator_test.go new file mode 100644 index 0000000000..5d340cd2e2 --- /dev/null +++ b/mongodbatlas/framework/validator/aws_kms_config_validator_test.go @@ -0,0 +1,105 @@ +package validator + +import ( + "context" + "testing" + + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +func TestValidAwsKmsConfig(t *testing.T) { + enabled := true + validType1 := map[string]attr.Type{ + "enabled": types.BoolType, + "customer_master_key_id": types.StringType, + "region": types.StringType, + "role_id": types.StringType, + } + validValue1 := map[string]attr.Value{ + "enabled": types.BoolValue(enabled), + "customer_master_key_id": types.StringValue("testCustomerMasterKeyID"), + "region": types.StringValue("testRegion"), + "role_id": types.StringValue("testRoleID"), + } + validType2 := map[string]attr.Type{ + "enabled": types.BoolType, + "access_key_id": types.StringType, + "secret_access_key": types.StringType, + "customer_master_key_id": types.StringType, + "region": types.StringType, + } + validValue2 := map[string]attr.Value{ + "enabled": types.BoolValue(enabled), + "access_key_id": types.StringValue("testAccessKey"), + "secret_access_key": types.StringValue("testSecretAccessKey"), + "customer_master_key_id": types.StringValue("testCustomerMasterKeyID"), + "region": types.StringValue("testRegion"), + } + inValidType := map[string]attr.Type{ + "enabled": types.BoolType, + "access_key_id": types.StringType, + "secret_access_key": types.StringType, + "customer_master_key_id": types.StringType, + "region": types.StringType, + "role_id": types.StringType, + } + inValidValue := map[string]attr.Value{ + "enabled": types.BoolValue(enabled), + "access_key_id": types.StringValue("testAccessKey"), + "secret_access_key": types.StringValue("testSecretAccessKey"), + "customer_master_key_id": types.StringValue("testCustomerMasterKeyID"), + "region": types.StringValue("testRegion"), + "role_id": types.StringValue("testRoleID"), + } + + tests := []struct { + name string + awsKmsConfigValue map[string]attr.Value + awsKmsConfigType map[string]attr.Type + wantErr bool + }{ + { + name: "Valid Value 1", + awsKmsConfigValue: validValue1, + awsKmsConfigType: validType1, + wantErr: false, + }, + { + name: "Valid Value 2", + awsKmsConfigValue: validValue2, + awsKmsConfigType: validType2, + wantErr: false, + }, + { + name: "Invalid Value", + awsKmsConfigValue: inValidValue, + awsKmsConfigType: inValidType, + wantErr: true, + }, + } + + for _, tt := range tests { + wantErr := tt.wantErr + + awsKmsConfigValidator := awsKmsConfigValidator{} + validatorRequest := validator.ObjectRequest{ + ConfigValue: types.ObjectValueMust(tt.awsKmsConfigType, tt.awsKmsConfigValue), + } + + validatorResponse := validator.ObjectResponse{ + Diagnostics: diag.Diagnostics{}, + } + + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + awsKmsConfigValidator.ValidateObject(context.Background(), validatorRequest, &validatorResponse) + + if validatorResponse.Diagnostics.HasError() && !wantErr { + t.Errorf("error = %v, wantErr %v", validatorResponse.Diagnostics.Errors(), wantErr) + } + }) + } +} From 42096b04f2e2f138acae7955bdb1bc81e00438bf Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Tue, 22 Aug 2023 23:08:56 +0100 Subject: [PATCH 11/19] cleanup --- ...esource_mongodbatlas_encryption_at_rest.go | 239 +++++++++--------- 1 file changed, 116 insertions(+), 123 deletions(-) diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go index 1ac0a5306c..31bbef27b4 100644 --- a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go @@ -16,6 +16,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" @@ -23,6 +24,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/mongodb/terraform-provider-mongodbatlas/mongodbatlas/framework/conversion" validators "github.com/mongodb/terraform-provider-mongodbatlas/mongodbatlas/framework/validator" ) @@ -139,6 +141,10 @@ func (r *EncryptionAtRestRS) Schema(ctx context.Context, req resource.SchemaRequ Attributes: map[string]schema.Attribute{ "enabled": schema.BoolAttribute{ Optional: true, + Computed: true, + PlanModifiers: []planmodifier.Bool{ + boolplanmodifier.UseStateForUnknown(), + }, }, "access_key_id": schema.StringAttribute{ Optional: true, @@ -167,7 +173,11 @@ func (r *EncryptionAtRestRS) Schema(ctx context.Context, req resource.SchemaRequ NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ "enabled": schema.BoolAttribute{ - Required: true, + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.Bool{ + boolplanmodifier.UseStateForUnknown(), + }, }, "client_id": schema.StringAttribute{ Optional: true, @@ -207,6 +217,10 @@ func (r *EncryptionAtRestRS) Schema(ctx context.Context, req resource.SchemaRequ Attributes: map[string]schema.Attribute{ "enabled": schema.BoolAttribute{ Optional: true, + Computed: true, + PlanModifiers: []planmodifier.Bool{ + boolplanmodifier.UseStateForUnknown(), + }, }, "service_account_key": schema.StringAttribute{ Optional: true, @@ -281,7 +295,7 @@ func (r *EncryptionAtRestRS) Create(ctx context.Context, req resource.CreateRequ } encryptionAtRestPlanNew := toTFEncryptionAtRestRSModel(ctx, projectID, encryptionResp) - resetDefaults(ctx, encryptionAtRestPlan, encryptionAtRestPlanNew, encryptionAtRestConfig) + resetDefaultsFromConfig(ctx, encryptionAtRestPlan, encryptionAtRestPlanNew, encryptionAtRestConfig) // set state to fully populated data diags := resp.State.Set(ctx, encryptionAtRestPlanNew) @@ -291,76 +305,6 @@ func (r *EncryptionAtRestRS) Create(ctx context.Context, req resource.CreateRequ } } -func resetDefaults(ctx context.Context, encryptionAtRestRS *tfEncryptionAtRestRSModel, encryptionAtRestRSNew *tfEncryptionAtRestRSModel, encryptionAtRestRSConfig *tfEncryptionAtRestRSModel) { - if encryptionAtRestRS.AwsKmsConfig.IsNull() { - tfAwsKmsConfigs := make([]tfAwsKmsConfigModel, 0) - encryptionAtRestRSNew.AwsKmsConfig, _ = types.ListValueFrom(ctx, tfAwsKmsObjectType, tfAwsKmsConfigs) - } else { - - var awsKmsConfigsNew []tfAwsKmsConfigModel - encryptionAtRestRSNew.AwsKmsConfig.ElementsAs(ctx, &awsKmsConfigsNew, false) - - // user may set "region" equal to 'US_EAST_1' or 'US-EAST-1' in config, we ensure to update new plan/state with value that is used in the config - if encryptionAtRestRSConfig != nil { - var awsKmsConfigs []tfAwsKmsConfigModel - encryptionAtRestRSConfig.AwsKmsConfig.ElementsAs(ctx, &awsKmsConfigs, false) - - awsKmsConfigsNew[0].Region = awsKmsConfigs[0].Region - } else { - var awsKmsConfigs []tfAwsKmsConfigModel - encryptionAtRestRS.AwsKmsConfig.ElementsAs(ctx, &awsKmsConfigs, false) - - awsKmsConfigsNew[0].Region = awsKmsConfigs[0].Region - } - encryptionAtRestRSNew.AwsKmsConfig, _ = types.ListValueFrom(ctx, tfAwsKmsObjectType, awsKmsConfigsNew) - } - if encryptionAtRestRS.AzureKeyVaultConfig.IsNull() { - // encryptionAtRestPlanNew.AzureKeyVaultConfig = types.ListNull(tfAzureKeyVaultObjectType) - tfAzKeyVaultConfigs := make([]tfAzureKeyVaultConfigModel, 0) - encryptionAtRestRSNew.AzureKeyVaultConfig, _ = types.ListValueFrom(ctx, tfAzureKeyVaultObjectType, tfAzKeyVaultConfigs) - } else { - - var azureConfigsNew []tfAzureKeyVaultConfigModel - encryptionAtRestRSNew.AzureKeyVaultConfig.ElementsAs(ctx, &azureConfigsNew, false) - - if encryptionAtRestRSConfig != nil { - var azureConfigs []tfAzureKeyVaultConfigModel - encryptionAtRestRSConfig.AzureKeyVaultConfig.ElementsAs(ctx, &azureConfigs, false) - - azureConfigsNew[0].Secret = azureConfigs[0].Secret - } else { - var azureConfigs []tfAzureKeyVaultConfigModel - encryptionAtRestRS.AzureKeyVaultConfig.ElementsAs(ctx, &azureConfigs, false) - - azureConfigsNew[0].Secret = azureConfigs[0].Secret - } - encryptionAtRestRSNew.AzureKeyVaultConfig, _ = types.ListValueFrom(ctx, tfAzureKeyVaultObjectType, azureConfigsNew) - } - - if encryptionAtRestRS.GoogleCloudKmsConfig.IsNull() { - // encryptionAtRestPlanNew.GoogleCloudKmsConfig = types.ListNull(tfGcpKmsObjectType) - tfGcpKmsConfigs := make([]tfGcpKmsConfigModel, 0) - encryptionAtRestRSNew.GoogleCloudKmsConfig, _ = types.ListValueFrom(ctx, tfGcpKmsObjectType, tfGcpKmsConfigs) - } else { - var gcpConfigsNew []tfGcpKmsConfigModel - encryptionAtRestRSNew.GoogleCloudKmsConfig.ElementsAs(ctx, &gcpConfigsNew, false) - - if encryptionAtRestRSConfig != nil { - var gcpConfigs []tfGcpKmsConfigModel - encryptionAtRestRSConfig.GoogleCloudKmsConfig.ElementsAs(ctx, &gcpConfigs, false) - - gcpConfigsNew[0].ServiceAccountKey = gcpConfigs[0].ServiceAccountKey - } else { - var gcpConfigs []tfGcpKmsConfigModel - encryptionAtRestRS.GoogleCloudKmsConfig.ElementsAs(ctx, &gcpConfigs, false) - - gcpConfigsNew[0].ServiceAccountKey = gcpConfigs[0].ServiceAccountKey - } - encryptionAtRestRSNew.GoogleCloudKmsConfig, _ = types.ListValueFrom(ctx, tfGcpKmsObjectType, gcpConfigsNew) - - } -} - func (r *EncryptionAtRestRS) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var encryptionAtRestState tfEncryptionAtRestRSModel @@ -370,7 +314,6 @@ func (r *EncryptionAtRestRS) Read(ctx context.Context, req resource.ReadRequest, return } - // get resource from API conn := r.client.Atlas projectID := encryptionAtRestState.ProjectID.ValueString() encryptionResp, _, err := conn.EncryptionsAtRest.Get(context.Background(), projectID) @@ -381,8 +324,7 @@ func (r *EncryptionAtRestRS) Read(ctx context.Context, req resource.ReadRequest, } encryptionAtRestStateNew := toTFEncryptionAtRestRSModel(ctx, projectID, encryptionResp) - resetDefaults(ctx, &encryptionAtRestState, encryptionAtRestStateNew, nil) - // resetDefaultsForRead(&encryptionAtRestState, encryptionAtRestStateNew) + resetDefaultsFromConfig(ctx, &encryptionAtRestState, encryptionAtRestStateNew, nil) // save read data into Terraform state resp.Diagnostics.Append(resp.State.Set(ctx, &encryptionAtRestStateNew)...) @@ -453,24 +395,12 @@ func (r *EncryptionAtRestRS) Update(ctx context.Context, req resource.UpdateRequ } encryptionAtRestStateNew := toTFEncryptionAtRestRSModel(ctx, projectID, encryptionResp) - resetDefaults(ctx, encryptionAtRestState, encryptionAtRestStateNew, encryptionAtRestConfig) + resetDefaultsFromConfig(ctx, encryptionAtRestState, encryptionAtRestStateNew, encryptionAtRestConfig) // save updated data into Terraform state resp.Diagnostics.Append(resp.State.Set(ctx, &encryptionAtRestStateNew)...) } -func hasGcpKmsConfigChanged(gcpKmsConfigsPlan, gcpKmsConfigsState basetypes.ListValue) bool { - return !reflect.DeepEqual(gcpKmsConfigsPlan, gcpKmsConfigsState) -} - -func hasAzureKeyVaultConfigChanged(azureKeyVaultConfigPlan, azureKeyVaultConfigState basetypes.ListValue) bool { - return !reflect.DeepEqual(azureKeyVaultConfigPlan, azureKeyVaultConfigState) -} - -func hasAwsKmsConfigChanged(awsKmsConfigPlan, awsKmsConfigState basetypes.ListValue) bool { - return !reflect.DeepEqual(awsKmsConfigPlan, awsKmsConfigState) -} - func (r *EncryptionAtRestRS) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { var encryptionAtRestState *tfEncryptionAtRestRSModel @@ -494,6 +424,99 @@ func (r *EncryptionAtRestRS) ImportState(ctx context.Context, req resource.Impor resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) } +func hasGcpKmsConfigChanged(gcpKmsConfigsPlan, gcpKmsConfigsState basetypes.ListValue) bool { + return !reflect.DeepEqual(gcpKmsConfigsPlan, gcpKmsConfigsState) +} + +func hasAzureKeyVaultConfigChanged(azureKeyVaultConfigPlan, azureKeyVaultConfigState basetypes.ListValue) bool { + return !reflect.DeepEqual(azureKeyVaultConfigPlan, azureKeyVaultConfigState) +} + +func hasAwsKmsConfigChanged(awsKmsConfigPlan, awsKmsConfigState basetypes.ListValue) bool { + return !reflect.DeepEqual(awsKmsConfigPlan, awsKmsConfigState) +} + +func resetDefaultsFromConfig(ctx context.Context, encryptionAtRestRSCurrent, encryptionAtRestRSNew, encryptionAtRestRSConfig *tfEncryptionAtRestRSModel) { + handleAwsKmsConfigDefaults(ctx, encryptionAtRestRSCurrent, encryptionAtRestRSNew, encryptionAtRestRSConfig) + handleAzureKeyVaultConfigDefaults(ctx, encryptionAtRestRSCurrent, encryptionAtRestRSNew, encryptionAtRestRSConfig) + handleGcpKmsConfig(ctx, encryptionAtRestRSCurrent, encryptionAtRestRSNew, encryptionAtRestRSConfig) +} + +func handleGcpKmsConfig(ctx context.Context, earRSCurrent, earRSNew, earRSConfig *tfEncryptionAtRestRSModel) { + var gcpConfigsNew []tfGcpKmsConfigModel + var gcpConfigsTemp []tfGcpKmsConfigModel + + // this is required to avoid unnecessary change detection during plan after migration to Plugin Framework if user didn't set this block + if earRSCurrent.GoogleCloudKmsConfig.IsNull() { + gcpConfigsNew = make([]tfGcpKmsConfigModel, 0) + earRSNew.GoogleCloudKmsConfig, _ = types.ListValueFrom(ctx, tfGcpKmsObjectType, gcpConfigsNew) + return + } + + // handling sensitive values that are not returned in the API response, so we sync them from the config + // that user provided. encryptionAtRestRSConfig is nil during Read(), so we use the current plan + earRSNew.GoogleCloudKmsConfig.ElementsAs(ctx, &gcpConfigsNew, false) + + if earRSConfig != nil { + earRSConfig.GoogleCloudKmsConfig.ElementsAs(ctx, &gcpConfigsTemp, false) + } else { + earRSCurrent.GoogleCloudKmsConfig.ElementsAs(ctx, &gcpConfigsTemp, false) + } + gcpConfigsNew[0].ServiceAccountKey = gcpConfigsTemp[0].ServiceAccountKey + + earRSNew.GoogleCloudKmsConfig, _ = types.ListValueFrom(ctx, tfGcpKmsObjectType, gcpConfigsNew) +} + +func handleAwsKmsConfigDefaults(ctx context.Context, earRSCurrent, earRSNew, earRSConfig *tfEncryptionAtRestRSModel) { + var awsKmsConfigsNew []tfAwsKmsConfigModel + var awsKmsConfigsTemp []tfAwsKmsConfigModel + + // this is required to avoid unnecessary change detection during plan after migration to Plugin Framework if user didn't set this block + if earRSCurrent.AwsKmsConfig.IsNull() { + awsKmsConfigsNew = make([]tfAwsKmsConfigModel, 0) + earRSNew.AwsKmsConfig, _ = types.ListValueFrom(ctx, tfAwsKmsObjectType, awsKmsConfigsNew) + return + } + + // handling sensitive values that are not returned in the API response, so we sync them from the config + // that user provided. encryptionAtRestRSConfig is nil during Read(), so we use the current plan + earRSNew.AwsKmsConfig.ElementsAs(ctx, &awsKmsConfigsNew, false) + + if earRSConfig != nil { + earRSConfig.AwsKmsConfig.ElementsAs(ctx, &awsKmsConfigsTemp, false) + } else { + earRSCurrent.AwsKmsConfig.ElementsAs(ctx, &awsKmsConfigsTemp, false) + } + awsKmsConfigsNew[0].Region = awsKmsConfigsTemp[0].Region + + earRSNew.AwsKmsConfig, _ = types.ListValueFrom(ctx, tfAwsKmsObjectType, awsKmsConfigsNew) +} + +func handleAzureKeyVaultConfigDefaults(ctx context.Context, earRSCurrent, earRSNew, earRSConfig *tfEncryptionAtRestRSModel) { + var azConfigsNew []tfAzureKeyVaultConfigModel + var azConfigsTemp []tfAzureKeyVaultConfigModel + + // this is required to avoid unnecessary change detection during plan after migration to Plugin Framework if user didn't set this block + if earRSCurrent.AzureKeyVaultConfig.IsNull() { + azConfigsNew = make([]tfAzureKeyVaultConfigModel, 0) + earRSNew.AzureKeyVaultConfig, _ = types.ListValueFrom(ctx, tfAzureKeyVaultObjectType, azConfigsNew) + return + } + + // handling sensitive values that are not returned in the API response, so we sync them from the config + // that user provided. encryptionAtRestRSConfig is nil during Read(), so we use the current plan + earRSNew.AzureKeyVaultConfig.ElementsAs(ctx, &azConfigsNew, false) + + if earRSConfig != nil { + earRSConfig.AzureKeyVaultConfig.ElementsAs(ctx, &azConfigsTemp, false) + } else { + earRSCurrent.AzureKeyVaultConfig.ElementsAs(ctx, &azConfigsTemp, false) + } + azConfigsNew[0].Secret = azConfigsTemp[0].Secret + + earRSNew.AzureKeyVaultConfig, _ = types.ListValueFrom(ctx, tfAzureKeyVaultObjectType, azConfigsNew) +} + func toTFEncryptionAtRestRSModel(ctx context.Context, projectID string, encryptionResp *matlas.EncryptionAtRest) *tfEncryptionAtRestRSModel { encryptionAtRest := tfEncryptionAtRestRSModel{ ID: types.StringValue(projectID), @@ -512,27 +535,9 @@ func toTFAwsKmsConfig(ctx context.Context, awsKms *matlas.AwsKms) types.List { tfAwsKmsConfigs[0].Enabled = types.BoolPointerValue(awsKms.Enabled) tfAwsKmsConfigs[0].CustomerMasterKeyID = types.StringValue(awsKms.CustomerMasterKeyID) tfAwsKmsConfigs[0].Region = types.StringValue(awsKms.Region) - - if accessKeyID := awsKms.AccessKeyID; accessKeyID == "" { - tfAwsKmsConfigs[0].AccessKeyID = types.StringNull() - } else { - tfAwsKmsConfigs[0].AccessKeyID = types.StringValue(accessKeyID) - } - // tfAwsKmsConfigs[0].AccessKeyID = types.StringValue(awsKms.AccessKeyID) - - if secretAccessKey := awsKms.SecretAccessKey; secretAccessKey == "" { - tfAwsKmsConfigs[0].SecretAccessKey = types.StringNull() - } else { - tfAwsKmsConfigs[0].SecretAccessKey = types.StringValue(secretAccessKey) - } - // tfAwsKmsConfigs[0].SecretAccessKey = types.StringValue(awsKms.SecretAccessKey) - - if roleID := awsKms.RoleID; roleID == "" { - tfAwsKmsConfigs[0].RoleID = types.StringNull() - } else { - tfAwsKmsConfigs[0].RoleID = types.StringValue(roleID) - } - // tfAwsKmsConfigs[0].RoleID = types.StringValue(awsKms.RoleID) + tfAwsKmsConfigs[0].AccessKeyID = conversion.StringNullIfEmpty(awsKms.AccessKeyID) + tfAwsKmsConfigs[0].SecretAccessKey = conversion.StringNullIfEmpty(awsKms.SecretAccessKey) + tfAwsKmsConfigs[0].RoleID = conversion.StringNullIfEmpty(awsKms.RoleID) } list, _ := types.ListValueFrom(ctx, tfAwsKmsObjectType, tfAwsKmsConfigs) @@ -550,13 +555,7 @@ func toTFAzureKeyVaultConfig(ctx context.Context, az *matlas.AzureKeyVault) type tfAzKeyVaultConfigs[0].KeyVaultName = types.StringValue(az.KeyVaultName) tfAzKeyVaultConfigs[0].KeyIdentifier = types.StringValue(az.KeyIdentifier) tfAzKeyVaultConfigs[0].TenantID = types.StringValue(az.TenantID) - - if secret := az.Secret; secret == "" { - tfAzKeyVaultConfigs[0].Secret = types.StringNull() - } else { - tfAzKeyVaultConfigs[0].Secret = types.StringValue(secret) - } - // tfAzKeyVaultConfigs[0].Secret = types.StringValue(az.Secret) + tfAzKeyVaultConfigs[0].Secret = conversion.StringNullIfEmpty(az.Secret) list, _ := types.ListValueFrom(ctx, tfAzureKeyVaultObjectType, tfAzKeyVaultConfigs) return list @@ -566,14 +565,8 @@ func toTFGcpKmsConfig(ctx context.Context, gcpKms *matlas.GoogleCloudKms) types. tfGcpKmsConfigs := make([]tfGcpKmsConfigModel, 1) tfGcpKmsConfigs[0].Enabled = types.BoolPointerValue(gcpKms.Enabled) - // tfGcpKmsConfigs[0].ServiceAccountKey = types.StringValue(gcpKms.ServiceAccountKey) tfGcpKmsConfigs[0].KeyVersionResourceID = types.StringValue(gcpKms.KeyVersionResourceID) - - if serviceAccountKey := gcpKms.ServiceAccountKey; serviceAccountKey == "" { - tfGcpKmsConfigs[0].ServiceAccountKey = types.StringNull() - } else { - tfGcpKmsConfigs[0].ServiceAccountKey = types.StringValue(serviceAccountKey) - } + tfGcpKmsConfigs[0].ServiceAccountKey = conversion.StringNullIfEmpty(gcpKms.ServiceAccountKey) list, _ := types.ListValueFrom(ctx, tfGcpKmsObjectType, tfGcpKmsConfigs) return list From 1458b149c8eccbdf411e3e21267eefb8f13a2d01 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Wed, 23 Aug 2023 09:11:33 +0100 Subject: [PATCH 12/19] import --- ...esource_mongodbatlas_encryption_at_rest.go | 52 +++++++++++-------- ...ce_mongodbatlas_encryption_at_rest_test.go | 18 +++++++ 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go index 31bbef27b4..f1136c8a72 100644 --- a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go @@ -254,13 +254,13 @@ func (r *EncryptionAtRestRS) Create(ctx context.Context, req resource.CreateRequ } if !encryptionAtRestPlan.AwsKmsConfig.IsNull() { - encryptionAtRestReq.AwsKms = *toAtlasAwsKms(ctx, encryptionAtRestPlan.AwsKmsConfig) + encryptionAtRestReq.AwsKms = *newAtlasAwsKms(ctx, encryptionAtRestPlan.AwsKmsConfig) } if !encryptionAtRestPlan.AzureKeyVaultConfig.IsNull() { - encryptionAtRestReq.AzureKeyVault = *toAtlasAzureKeyVault(ctx, encryptionAtRestPlan.AzureKeyVaultConfig) + encryptionAtRestReq.AzureKeyVault = *newAtlasAzureKeyVault(ctx, encryptionAtRestPlan.AzureKeyVaultConfig) } if !encryptionAtRestPlan.GoogleCloudKmsConfig.IsNull() { - encryptionAtRestReq.GoogleCloudKms = *toAtlasGcpKms(ctx, encryptionAtRestPlan.GoogleCloudKmsConfig) + encryptionAtRestReq.GoogleCloudKms = *newAtlasGcpKms(ctx, encryptionAtRestPlan.GoogleCloudKmsConfig) } for i := 0; i < 5; i++ { @@ -294,7 +294,7 @@ func (r *EncryptionAtRestRS) Create(ctx context.Context, req resource.CreateRequ return } - encryptionAtRestPlanNew := toTFEncryptionAtRestRSModel(ctx, projectID, encryptionResp) + encryptionAtRestPlanNew := newTFEncryptionAtRestRSModel(ctx, projectID, encryptionResp) resetDefaultsFromConfig(ctx, encryptionAtRestPlan, encryptionAtRestPlanNew, encryptionAtRestConfig) // set state to fully populated data @@ -307,15 +307,23 @@ func (r *EncryptionAtRestRS) Create(ctx context.Context, req resource.CreateRequ func (r *EncryptionAtRestRS) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var encryptionAtRestState tfEncryptionAtRestRSModel + var isImport bool // get current state resp.Diagnostics.Append(req.State.Get(ctx, &encryptionAtRestState)...) if resp.Diagnostics.HasError() { return } + projectID := encryptionAtRestState.ProjectID.ValueString() + + // Use the ID only with the IMPORT operation + if encryptionAtRestState.ID.ValueString() != "" && (projectID == "") { + projectID = encryptionAtRestState.ID.ValueString() + isImport = true + } conn := r.client.Atlas - projectID := encryptionAtRestState.ProjectID.ValueString() + encryptionResp, _, err := conn.EncryptionsAtRest.Get(context.Background(), projectID) tflog.Debug(ctx, fmt.Sprintf("encryptionResp from api: %v", encryptionResp)) if err != nil { @@ -323,8 +331,10 @@ func (r *EncryptionAtRestRS) Read(ctx context.Context, req resource.ReadRequest, return } - encryptionAtRestStateNew := toTFEncryptionAtRestRSModel(ctx, projectID, encryptionResp) - resetDefaultsFromConfig(ctx, &encryptionAtRestState, encryptionAtRestStateNew, nil) + encryptionAtRestStateNew := newTFEncryptionAtRestRSModel(ctx, projectID, encryptionResp) + if !isImport { + resetDefaultsFromConfig(ctx, &encryptionAtRestState, encryptionAtRestStateNew, nil) + } // save read data into Terraform state resp.Diagnostics.Append(resp.State.Set(ctx, &encryptionAtRestStateNew)...) @@ -366,13 +376,13 @@ func (r *EncryptionAtRestRS) Update(ctx context.Context, req resource.UpdateRequ } if hasAwsKmsConfigChanged(encryptionAtRestPlan.AwsKmsConfig, encryptionAtRestState.AwsKmsConfig) { - atlasEncryptionAtRest.AwsKms = *toAtlasAwsKms(ctx, encryptionAtRestPlan.AwsKmsConfig) + atlasEncryptionAtRest.AwsKms = *newAtlasAwsKms(ctx, encryptionAtRestPlan.AwsKmsConfig) } if hasAzureKeyVaultConfigChanged(encryptionAtRestPlan.AzureKeyVaultConfig, encryptionAtRestState.AzureKeyVaultConfig) { - atlasEncryptionAtRest.AzureKeyVault = *toAtlasAzureKeyVault(ctx, encryptionAtRestPlan.AzureKeyVaultConfig) + atlasEncryptionAtRest.AzureKeyVault = *newAtlasAzureKeyVault(ctx, encryptionAtRestPlan.AzureKeyVaultConfig) } if hasGcpKmsConfigChanged(encryptionAtRestPlan.GoogleCloudKmsConfig, encryptionAtRestState.GoogleCloudKmsConfig) { - atlasEncryptionAtRest.GoogleCloudKms = *toAtlasGcpKms(ctx, encryptionAtRestPlan.GoogleCloudKmsConfig) + atlasEncryptionAtRest.GoogleCloudKms = *newAtlasGcpKms(ctx, encryptionAtRestPlan.GoogleCloudKmsConfig) } atlasEncryptionAtRest.GroupID = projectID @@ -394,7 +404,7 @@ func (r *EncryptionAtRestRS) Update(ctx context.Context, req resource.UpdateRequ return } - encryptionAtRestStateNew := toTFEncryptionAtRestRSModel(ctx, projectID, encryptionResp) + encryptionAtRestStateNew := newTFEncryptionAtRestRSModel(ctx, projectID, encryptionResp) resetDefaultsFromConfig(ctx, encryptionAtRestState, encryptionAtRestStateNew, encryptionAtRestConfig) // save updated data into Terraform state @@ -517,18 +527,18 @@ func handleAzureKeyVaultConfigDefaults(ctx context.Context, earRSCurrent, earRSN earRSNew.AzureKeyVaultConfig, _ = types.ListValueFrom(ctx, tfAzureKeyVaultObjectType, azConfigsNew) } -func toTFEncryptionAtRestRSModel(ctx context.Context, projectID string, encryptionResp *matlas.EncryptionAtRest) *tfEncryptionAtRestRSModel { +func newTFEncryptionAtRestRSModel(ctx context.Context, projectID string, encryptionResp *matlas.EncryptionAtRest) *tfEncryptionAtRestRSModel { encryptionAtRest := tfEncryptionAtRestRSModel{ ID: types.StringValue(projectID), ProjectID: types.StringValue(projectID), - AwsKmsConfig: toTFAwsKmsConfig(ctx, &encryptionResp.AwsKms), - AzureKeyVaultConfig: toTFAzureKeyVaultConfig(ctx, &encryptionResp.AzureKeyVault), - GoogleCloudKmsConfig: toTFGcpKmsConfig(ctx, &encryptionResp.GoogleCloudKms), + AwsKmsConfig: newTFAwsKmsConfig(ctx, &encryptionResp.AwsKms), + AzureKeyVaultConfig: newTFAzureKeyVaultConfig(ctx, &encryptionResp.AzureKeyVault), + GoogleCloudKmsConfig: newTFGcpKmsConfig(ctx, &encryptionResp.GoogleCloudKms), } return &encryptionAtRest } -func toTFAwsKmsConfig(ctx context.Context, awsKms *matlas.AwsKms) types.List { +func newTFAwsKmsConfig(ctx context.Context, awsKms *matlas.AwsKms) types.List { tfAwsKmsConfigs := make([]tfAwsKmsConfigModel, 1) if awsKms != nil { @@ -544,7 +554,7 @@ func toTFAwsKmsConfig(ctx context.Context, awsKms *matlas.AwsKms) types.List { return list } -func toTFAzureKeyVaultConfig(ctx context.Context, az *matlas.AzureKeyVault) types.List { +func newTFAzureKeyVaultConfig(ctx context.Context, az *matlas.AzureKeyVault) types.List { tfAzKeyVaultConfigs := make([]tfAzureKeyVaultConfigModel, 1) tfAzKeyVaultConfigs[0].Enabled = types.BoolPointerValue(az.Enabled) @@ -561,7 +571,7 @@ func toTFAzureKeyVaultConfig(ctx context.Context, az *matlas.AzureKeyVault) type return list } -func toTFGcpKmsConfig(ctx context.Context, gcpKms *matlas.GoogleCloudKms) types.List { +func newTFGcpKmsConfig(ctx context.Context, gcpKms *matlas.GoogleCloudKms) types.List { tfGcpKmsConfigs := make([]tfGcpKmsConfigModel, 1) tfGcpKmsConfigs[0].Enabled = types.BoolPointerValue(gcpKms.Enabled) @@ -572,7 +582,7 @@ func toTFGcpKmsConfig(ctx context.Context, gcpKms *matlas.GoogleCloudKms) types. return list } -func toAtlasAwsKms(ctx context.Context, tfAwsKmsConfigList basetypes.ListValue) *matlas.AwsKms { +func newAtlasAwsKms(ctx context.Context, tfAwsKmsConfigList basetypes.ListValue) *matlas.AwsKms { if len(tfAwsKmsConfigList.Elements()) == 0 { return &matlas.AwsKms{} } @@ -591,7 +601,7 @@ func toAtlasAwsKms(ctx context.Context, tfAwsKmsConfigList basetypes.ListValue) } } -func toAtlasGcpKms(ctx context.Context, tfGcpKmsConfigList basetypes.ListValue) *matlas.GoogleCloudKms { +func newAtlasGcpKms(ctx context.Context, tfGcpKmsConfigList basetypes.ListValue) *matlas.GoogleCloudKms { if len(tfGcpKmsConfigList.Elements()) == 0 { return &matlas.GoogleCloudKms{} } @@ -605,7 +615,7 @@ func toAtlasGcpKms(ctx context.Context, tfGcpKmsConfigList basetypes.ListValue) } } -func toAtlasAzureKeyVault(ctx context.Context, tfAzureKeyVaultList basetypes.ListValue) *matlas.AzureKeyVault { +func newAtlasAzureKeyVault(ctx context.Context, tfAzureKeyVaultList basetypes.ListValue) *matlas.AzureKeyVault { if len(tfAzureKeyVaultList.Elements()) == 0 { return &matlas.AzureKeyVault{} } diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go index 0f10d181b2..4b636df4f5 100644 --- a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go @@ -249,10 +249,28 @@ func TestAccAdvRSEncryptionAtRest_basicGCP(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "google_cloud_kms_config.0.enabled", "true"), ), }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccCheckMongoDBAtlasEncryptionAtRestImportStateIDFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + // ImportStateVerifyIgnore: []string{"project_id"}, + }, }, }) } +func testAccCheckMongoDBAtlasEncryptionAtRestImportStateIDFunc(resourceName string) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return "", fmt.Errorf("not found: %s", resourceName) + } + + return rs.Primary.ID, nil + } +} + func TestAccAdvRSEncryptionAtRestWithRole_basicAWS(t *testing.T) { // SkipTest(t) // For now it will skipped because of aws errors reasons, already made another test using terratest. // SkipTestExtCred(t) From 43f4508c86060dbac4609e67c2ac8b34c31de19f Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Wed, 23 Aug 2023 12:09:34 +0100 Subject: [PATCH 13/19] cleanup --- ...esource_mongodbatlas_encryption_at_rest.go | 264 +++++++----------- ...ce_mongodbatlas_encryption_at_rest_test.go | 90 ++---- 2 files changed, 131 insertions(+), 223 deletions(-) diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go index f1136c8a72..9a761fd84f 100644 --- a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go @@ -12,7 +12,6 @@ import ( matlas "go.mongodb.org/atlas/mongodbatlas" "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" - "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" @@ -21,7 +20,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/mongodb/terraform-provider-mongodbatlas/mongodbatlas/framework/conversion" @@ -48,11 +46,11 @@ type EncryptionAtRestRS struct { } type tfEncryptionAtRestRSModel struct { - ID types.String `tfsdk:"id"` - ProjectID types.String `tfsdk:"project_id"` - AwsKmsConfig types.List `tfsdk:"aws_kms_config"` - AzureKeyVaultConfig types.List `tfsdk:"azure_key_vault_config"` - GoogleCloudKmsConfig types.List `tfsdk:"google_cloud_kms_config"` + ID types.String `tfsdk:"id"` + ProjectID types.String `tfsdk:"project_id"` + AwsKmsConfig []tfAwsKmsConfigModel `tfsdk:"aws_kms_config"` + AzureKeyVaultConfig []tfAzureKeyVaultConfigModel `tfsdk:"azure_key_vault_config"` + GoogleCloudKmsConfig []tfGcpKmsConfigModel `tfsdk:"google_cloud_kms_config"` } type tfAwsKmsConfigModel struct { @@ -80,31 +78,6 @@ type tfGcpKmsConfigModel struct { Enabled types.Bool `tfsdk:"enabled"` } -var tfAwsKmsObjectType = types.ObjectType{AttrTypes: map[string]attr.Type{ - "enabled": types.BoolType, - "access_key_id": types.StringType, - "secret_access_key": types.StringType, - "customer_master_key_id": types.StringType, - "region": types.StringType, - "role_id": types.StringType, -}} -var tfAzureKeyVaultObjectType = types.ObjectType{AttrTypes: map[string]attr.Type{ - "enabled": types.BoolType, - "client_id": types.StringType, - "azure_environment": types.StringType, - "subscription_id": types.StringType, - "resource_group_name": types.StringType, - "key_vault_name": types.StringType, - "key_identifier": types.StringType, - "secret": types.StringType, - "tenant_id": types.StringType, -}} -var tfGcpKmsObjectType = types.ObjectType{AttrTypes: map[string]attr.Type{ - "enabled": types.BoolType, - "service_account_key": types.StringType, - "key_version_resource_id": types.StringType, -}} - func (r *EncryptionAtRestRS) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = fmt.Sprintf("%s_%s", req.ProviderTypeName, encryptionAtRestResourceName) } @@ -250,17 +223,10 @@ func (r *EncryptionAtRestRS) Create(ctx context.Context, req resource.CreateRequ projectID := encryptionAtRestPlan.ProjectID.ValueString() encryptionAtRestReq := &matlas.EncryptionAtRest{ - GroupID: projectID, - } - - if !encryptionAtRestPlan.AwsKmsConfig.IsNull() { - encryptionAtRestReq.AwsKms = *newAtlasAwsKms(ctx, encryptionAtRestPlan.AwsKmsConfig) - } - if !encryptionAtRestPlan.AzureKeyVaultConfig.IsNull() { - encryptionAtRestReq.AzureKeyVault = *newAtlasAzureKeyVault(ctx, encryptionAtRestPlan.AzureKeyVaultConfig) - } - if !encryptionAtRestPlan.GoogleCloudKmsConfig.IsNull() { - encryptionAtRestReq.GoogleCloudKms = *newAtlasGcpKms(ctx, encryptionAtRestPlan.GoogleCloudKmsConfig) + GroupID: projectID, + AwsKms: *newAtlasAwsKms(encryptionAtRestPlan.AwsKmsConfig), + AzureKeyVault: *newAtlasAzureKeyVault(encryptionAtRestPlan.AzureKeyVaultConfig), + GoogleCloudKms: *newAtlasGcpKms(encryptionAtRestPlan.GoogleCloudKmsConfig), } for i := 0; i < 5; i++ { @@ -294,7 +260,7 @@ func (r *EncryptionAtRestRS) Create(ctx context.Context, req resource.CreateRequ return } - encryptionAtRestPlanNew := newTFEncryptionAtRestRSModel(ctx, projectID, encryptionResp) + encryptionAtRestPlanNew := newTFEncryptionAtRestRSModel(ctx, projectID, encryptionResp, encryptionAtRestPlan) resetDefaultsFromConfig(ctx, encryptionAtRestPlan, encryptionAtRestPlanNew, encryptionAtRestConfig) // set state to fully populated data @@ -331,7 +297,7 @@ func (r *EncryptionAtRestRS) Read(ctx context.Context, req resource.ReadRequest, return } - encryptionAtRestStateNew := newTFEncryptionAtRestRSModel(ctx, projectID, encryptionResp) + encryptionAtRestStateNew := newTFEncryptionAtRestRSModel(ctx, projectID, encryptionResp, &encryptionAtRestState) if !isImport { resetDefaultsFromConfig(ctx, &encryptionAtRestState, encryptionAtRestStateNew, nil) } @@ -376,13 +342,13 @@ func (r *EncryptionAtRestRS) Update(ctx context.Context, req resource.UpdateRequ } if hasAwsKmsConfigChanged(encryptionAtRestPlan.AwsKmsConfig, encryptionAtRestState.AwsKmsConfig) { - atlasEncryptionAtRest.AwsKms = *newAtlasAwsKms(ctx, encryptionAtRestPlan.AwsKmsConfig) + atlasEncryptionAtRest.AwsKms = *newAtlasAwsKms(encryptionAtRestPlan.AwsKmsConfig) } if hasAzureKeyVaultConfigChanged(encryptionAtRestPlan.AzureKeyVaultConfig, encryptionAtRestState.AzureKeyVaultConfig) { - atlasEncryptionAtRest.AzureKeyVault = *newAtlasAzureKeyVault(ctx, encryptionAtRestPlan.AzureKeyVaultConfig) + atlasEncryptionAtRest.AzureKeyVault = *newAtlasAzureKeyVault(encryptionAtRestPlan.AzureKeyVaultConfig) } if hasGcpKmsConfigChanged(encryptionAtRestPlan.GoogleCloudKmsConfig, encryptionAtRestState.GoogleCloudKmsConfig) { - atlasEncryptionAtRest.GoogleCloudKms = *newAtlasGcpKms(ctx, encryptionAtRestPlan.GoogleCloudKmsConfig) + atlasEncryptionAtRest.GoogleCloudKms = *newAtlasGcpKms(encryptionAtRestPlan.GoogleCloudKmsConfig) } atlasEncryptionAtRest.GroupID = projectID @@ -404,7 +370,7 @@ func (r *EncryptionAtRestRS) Update(ctx context.Context, req resource.UpdateRequ return } - encryptionAtRestStateNew := newTFEncryptionAtRestRSModel(ctx, projectID, encryptionResp) + encryptionAtRestStateNew := newTFEncryptionAtRestRSModel(ctx, projectID, encryptionResp, encryptionAtRestPlan) resetDefaultsFromConfig(ctx, encryptionAtRestState, encryptionAtRestStateNew, encryptionAtRestConfig) // save updated data into Terraform state @@ -434,15 +400,15 @@ func (r *EncryptionAtRestRS) ImportState(ctx context.Context, req resource.Impor resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) } -func hasGcpKmsConfigChanged(gcpKmsConfigsPlan, gcpKmsConfigsState basetypes.ListValue) bool { +func hasGcpKmsConfigChanged(gcpKmsConfigsPlan, gcpKmsConfigsState []tfGcpKmsConfigModel) bool { return !reflect.DeepEqual(gcpKmsConfigsPlan, gcpKmsConfigsState) } -func hasAzureKeyVaultConfigChanged(azureKeyVaultConfigPlan, azureKeyVaultConfigState basetypes.ListValue) bool { +func hasAzureKeyVaultConfigChanged(azureKeyVaultConfigPlan, azureKeyVaultConfigState []tfAzureKeyVaultConfigModel) bool { return !reflect.DeepEqual(azureKeyVaultConfigPlan, azureKeyVaultConfigState) } -func hasAwsKmsConfigChanged(awsKmsConfigPlan, awsKmsConfigState basetypes.ListValue) bool { +func hasAwsKmsConfigChanged(awsKmsConfigPlan, awsKmsConfigState []tfAwsKmsConfigModel) bool { return !reflect.DeepEqual(awsKmsConfigPlan, awsKmsConfigState) } @@ -453,184 +419,160 @@ func resetDefaultsFromConfig(ctx context.Context, encryptionAtRestRSCurrent, enc } func handleGcpKmsConfig(ctx context.Context, earRSCurrent, earRSNew, earRSConfig *tfEncryptionAtRestRSModel) { - var gcpConfigsNew []tfGcpKmsConfigModel - var gcpConfigsTemp []tfGcpKmsConfigModel - // this is required to avoid unnecessary change detection during plan after migration to Plugin Framework if user didn't set this block - if earRSCurrent.GoogleCloudKmsConfig.IsNull() { - gcpConfigsNew = make([]tfGcpKmsConfigModel, 0) - earRSNew.GoogleCloudKmsConfig, _ = types.ListValueFrom(ctx, tfGcpKmsObjectType, gcpConfigsNew) + if earRSCurrent.GoogleCloudKmsConfig == nil { + earRSNew.GoogleCloudKmsConfig = []tfGcpKmsConfigModel{} return } // handling sensitive values that are not returned in the API response, so we sync them from the config // that user provided. encryptionAtRestRSConfig is nil during Read(), so we use the current plan - earRSNew.GoogleCloudKmsConfig.ElementsAs(ctx, &gcpConfigsNew, false) - - if earRSConfig != nil { - earRSConfig.GoogleCloudKmsConfig.ElementsAs(ctx, &gcpConfigsTemp, false) + if earRSConfig != nil && len(earRSConfig.GoogleCloudKmsConfig) > 0 { + earRSNew.GoogleCloudKmsConfig[0].ServiceAccountKey = earRSConfig.GoogleCloudKmsConfig[0].ServiceAccountKey } else { - earRSCurrent.GoogleCloudKmsConfig.ElementsAs(ctx, &gcpConfigsTemp, false) + earRSNew.GoogleCloudKmsConfig[0].ServiceAccountKey = earRSCurrent.GoogleCloudKmsConfig[0].ServiceAccountKey } - gcpConfigsNew[0].ServiceAccountKey = gcpConfigsTemp[0].ServiceAccountKey - - earRSNew.GoogleCloudKmsConfig, _ = types.ListValueFrom(ctx, tfGcpKmsObjectType, gcpConfigsNew) } func handleAwsKmsConfigDefaults(ctx context.Context, earRSCurrent, earRSNew, earRSConfig *tfEncryptionAtRestRSModel) { - var awsKmsConfigsNew []tfAwsKmsConfigModel - var awsKmsConfigsTemp []tfAwsKmsConfigModel - // this is required to avoid unnecessary change detection during plan after migration to Plugin Framework if user didn't set this block - if earRSCurrent.AwsKmsConfig.IsNull() { - awsKmsConfigsNew = make([]tfAwsKmsConfigModel, 0) - earRSNew.AwsKmsConfig, _ = types.ListValueFrom(ctx, tfAwsKmsObjectType, awsKmsConfigsNew) + if earRSCurrent.AwsKmsConfig == nil { + earRSNew.AwsKmsConfig = []tfAwsKmsConfigModel{} return } // handling sensitive values that are not returned in the API response, so we sync them from the config // that user provided. encryptionAtRestRSConfig is nil during Read(), so we use the current plan - earRSNew.AwsKmsConfig.ElementsAs(ctx, &awsKmsConfigsNew, false) - - if earRSConfig != nil { - earRSConfig.AwsKmsConfig.ElementsAs(ctx, &awsKmsConfigsTemp, false) + if earRSConfig != nil && len(earRSConfig.AwsKmsConfig) > 0 { + earRSNew.AwsKmsConfig[0].Region = earRSConfig.AwsKmsConfig[0].Region } else { - earRSCurrent.AwsKmsConfig.ElementsAs(ctx, &awsKmsConfigsTemp, false) + earRSNew.AwsKmsConfig[0].Region = earRSCurrent.AwsKmsConfig[0].Region } - awsKmsConfigsNew[0].Region = awsKmsConfigsTemp[0].Region - earRSNew.AwsKmsConfig, _ = types.ListValueFrom(ctx, tfAwsKmsObjectType, awsKmsConfigsNew) } func handleAzureKeyVaultConfigDefaults(ctx context.Context, earRSCurrent, earRSNew, earRSConfig *tfEncryptionAtRestRSModel) { - var azConfigsNew []tfAzureKeyVaultConfigModel - var azConfigsTemp []tfAzureKeyVaultConfigModel - // this is required to avoid unnecessary change detection during plan after migration to Plugin Framework if user didn't set this block - if earRSCurrent.AzureKeyVaultConfig.IsNull() { - azConfigsNew = make([]tfAzureKeyVaultConfigModel, 0) - earRSNew.AzureKeyVaultConfig, _ = types.ListValueFrom(ctx, tfAzureKeyVaultObjectType, azConfigsNew) + if earRSCurrent.AzureKeyVaultConfig == nil { + earRSNew.AzureKeyVaultConfig = []tfAzureKeyVaultConfigModel{} return } // handling sensitive values that are not returned in the API response, so we sync them from the config // that user provided. encryptionAtRestRSConfig is nil during Read(), so we use the current plan - earRSNew.AzureKeyVaultConfig.ElementsAs(ctx, &azConfigsNew, false) - - if earRSConfig != nil { - earRSConfig.AzureKeyVaultConfig.ElementsAs(ctx, &azConfigsTemp, false) + if earRSConfig != nil && len(earRSConfig.AzureKeyVaultConfig) > 0 { + earRSNew.AzureKeyVaultConfig[0].Secret = earRSConfig.AzureKeyVaultConfig[0].Secret } else { - earRSCurrent.AzureKeyVaultConfig.ElementsAs(ctx, &azConfigsTemp, false) + earRSNew.AzureKeyVaultConfig[0].Secret = earRSCurrent.AzureKeyVaultConfig[0].Secret } - azConfigsNew[0].Secret = azConfigsTemp[0].Secret - - earRSNew.AzureKeyVaultConfig, _ = types.ListValueFrom(ctx, tfAzureKeyVaultObjectType, azConfigsNew) } -func newTFEncryptionAtRestRSModel(ctx context.Context, projectID string, encryptionResp *matlas.EncryptionAtRest) *tfEncryptionAtRestRSModel { +func newTFEncryptionAtRestRSModel(ctx context.Context, projectID string, encryptionResp *matlas.EncryptionAtRest, plan *tfEncryptionAtRestRSModel) *tfEncryptionAtRestRSModel { encryptionAtRest := tfEncryptionAtRestRSModel{ ID: types.StringValue(projectID), ProjectID: types.StringValue(projectID), - AwsKmsConfig: newTFAwsKmsConfig(ctx, &encryptionResp.AwsKms), - AzureKeyVaultConfig: newTFAzureKeyVaultConfig(ctx, &encryptionResp.AzureKeyVault), - GoogleCloudKmsConfig: newTFGcpKmsConfig(ctx, &encryptionResp.GoogleCloudKms), + AwsKmsConfig: newTFAwsKmsConfig(ctx, &encryptionResp.AwsKms, plan.AwsKmsConfig), + AzureKeyVaultConfig: newTFAzureKeyVaultConfig(ctx, &encryptionResp.AzureKeyVault, plan.AzureKeyVaultConfig), + GoogleCloudKmsConfig: newTFGcpKmsConfig(ctx, &encryptionResp.GoogleCloudKms, plan.GoogleCloudKmsConfig), } return &encryptionAtRest } -func newTFAwsKmsConfig(ctx context.Context, awsKms *matlas.AwsKms) types.List { - tfAwsKmsConfigs := make([]tfAwsKmsConfigModel, 1) - - if awsKms != nil { - tfAwsKmsConfigs[0].Enabled = types.BoolPointerValue(awsKms.Enabled) - tfAwsKmsConfigs[0].CustomerMasterKeyID = types.StringValue(awsKms.CustomerMasterKeyID) - tfAwsKmsConfigs[0].Region = types.StringValue(awsKms.Region) - tfAwsKmsConfigs[0].AccessKeyID = conversion.StringNullIfEmpty(awsKms.AccessKeyID) - tfAwsKmsConfigs[0].SecretAccessKey = conversion.StringNullIfEmpty(awsKms.SecretAccessKey) - tfAwsKmsConfigs[0].RoleID = conversion.StringNullIfEmpty(awsKms.RoleID) +func newTFAwsKmsConfig(ctx context.Context, awsKms *matlas.AwsKms, currStateSlice []tfAwsKmsConfigModel) []tfAwsKmsConfigModel { + if awsKms == nil { + return []tfAwsKmsConfigModel{} } + newState := tfAwsKmsConfigModel{} + + newState.Enabled = types.BoolPointerValue(awsKms.Enabled) + newState.CustomerMasterKeyID = types.StringValue(awsKms.CustomerMasterKeyID) + newState.Region = types.StringValue(awsKms.Region) + newState.AccessKeyID = conversion.StringNullIfEmpty(awsKms.AccessKeyID) + newState.SecretAccessKey = conversion.StringNullIfEmpty(awsKms.SecretAccessKey) + newState.RoleID = conversion.StringNullIfEmpty(awsKms.RoleID) + + return []tfAwsKmsConfigModel{newState} - list, _ := types.ListValueFrom(ctx, tfAwsKmsObjectType, tfAwsKmsConfigs) - return list } -func newTFAzureKeyVaultConfig(ctx context.Context, az *matlas.AzureKeyVault) types.List { - tfAzKeyVaultConfigs := make([]tfAzureKeyVaultConfigModel, 1) - - tfAzKeyVaultConfigs[0].Enabled = types.BoolPointerValue(az.Enabled) - tfAzKeyVaultConfigs[0].ClientID = types.StringValue(az.ClientID) - tfAzKeyVaultConfigs[0].AzureEnvironment = types.StringValue(az.AzureEnvironment) - tfAzKeyVaultConfigs[0].SubscriptionID = types.StringValue(az.SubscriptionID) - tfAzKeyVaultConfigs[0].ResourceGroupName = types.StringValue(az.ResourceGroupName) - tfAzKeyVaultConfigs[0].KeyVaultName = types.StringValue(az.KeyVaultName) - tfAzKeyVaultConfigs[0].KeyIdentifier = types.StringValue(az.KeyIdentifier) - tfAzKeyVaultConfigs[0].TenantID = types.StringValue(az.TenantID) - tfAzKeyVaultConfigs[0].Secret = conversion.StringNullIfEmpty(az.Secret) - - list, _ := types.ListValueFrom(ctx, tfAzureKeyVaultObjectType, tfAzKeyVaultConfigs) - return list +func newTFAzureKeyVaultConfig(ctx context.Context, az *matlas.AzureKeyVault, currStateSlice []tfAzureKeyVaultConfigModel) []tfAzureKeyVaultConfigModel { + if az == nil { + return []tfAzureKeyVaultConfigModel{} + } + newState := tfAzureKeyVaultConfigModel{} + + newState.Enabled = types.BoolPointerValue(az.Enabled) + newState.ClientID = types.StringValue(az.ClientID) + newState.AzureEnvironment = types.StringValue(az.AzureEnvironment) + newState.SubscriptionID = types.StringValue(az.SubscriptionID) + newState.ResourceGroupName = types.StringValue(az.ResourceGroupName) + newState.KeyVaultName = types.StringValue(az.KeyVaultName) + newState.KeyIdentifier = types.StringValue(az.KeyIdentifier) + newState.TenantID = types.StringValue(az.TenantID) + newState.Secret = conversion.StringNullIfEmpty(az.Secret) + + return []tfAzureKeyVaultConfigModel{newState} } -func newTFGcpKmsConfig(ctx context.Context, gcpKms *matlas.GoogleCloudKms) types.List { - tfGcpKmsConfigs := make([]tfGcpKmsConfigModel, 1) +func newTFGcpKmsConfig(ctx context.Context, gcpKms *matlas.GoogleCloudKms, currStateSlice []tfGcpKmsConfigModel) []tfGcpKmsConfigModel { + if gcpKms == nil { + return []tfGcpKmsConfigModel{} + } + newState := tfGcpKmsConfigModel{} - tfGcpKmsConfigs[0].Enabled = types.BoolPointerValue(gcpKms.Enabled) - tfGcpKmsConfigs[0].KeyVersionResourceID = types.StringValue(gcpKms.KeyVersionResourceID) - tfGcpKmsConfigs[0].ServiceAccountKey = conversion.StringNullIfEmpty(gcpKms.ServiceAccountKey) + newState.Enabled = types.BoolPointerValue(gcpKms.Enabled) + newState.KeyVersionResourceID = types.StringValue(gcpKms.KeyVersionResourceID) + newState.ServiceAccountKey = conversion.StringNullIfEmpty(gcpKms.ServiceAccountKey) - list, _ := types.ListValueFrom(ctx, tfGcpKmsObjectType, tfGcpKmsConfigs) - return list + return []tfGcpKmsConfigModel{newState} } -func newAtlasAwsKms(ctx context.Context, tfAwsKmsConfigList basetypes.ListValue) *matlas.AwsKms { - if len(tfAwsKmsConfigList.Elements()) == 0 { +func newAtlasAwsKms(tfAwsKmsConfigSlice []tfAwsKmsConfigModel) *matlas.AwsKms { + if tfAwsKmsConfigSlice == nil || len(tfAwsKmsConfigSlice) < 1 { return &matlas.AwsKms{} } - var awsKmsConfigs []tfAwsKmsConfigModel - tfAwsKmsConfigList.ElementsAs(ctx, &awsKmsConfigs, false) + v := tfAwsKmsConfigSlice[0] - awsRegion, _ := valRegion(awsKmsConfigs[0].Region.ValueString()) + awsRegion, _ := valRegion(v.Region.ValueString()) return &matlas.AwsKms{ - Enabled: awsKmsConfigs[0].Enabled.ValueBoolPointer(), - AccessKeyID: awsKmsConfigs[0].AccessKeyID.ValueString(), - SecretAccessKey: awsKmsConfigs[0].SecretAccessKey.ValueString(), - CustomerMasterKeyID: awsKmsConfigs[0].CustomerMasterKeyID.ValueString(), + Enabled: v.Enabled.ValueBoolPointer(), + AccessKeyID: v.AccessKeyID.ValueString(), + SecretAccessKey: v.SecretAccessKey.ValueString(), + CustomerMasterKeyID: v.CustomerMasterKeyID.ValueString(), Region: awsRegion, - RoleID: awsKmsConfigs[0].RoleID.ValueString(), + RoleID: v.RoleID.ValueString(), } } -func newAtlasGcpKms(ctx context.Context, tfGcpKmsConfigList basetypes.ListValue) *matlas.GoogleCloudKms { - if len(tfGcpKmsConfigList.Elements()) == 0 { +func newAtlasGcpKms(tfGcpKmsConfigSlice []tfGcpKmsConfigModel) *matlas.GoogleCloudKms { + if tfGcpKmsConfigSlice == nil || len(tfGcpKmsConfigSlice) < 1 { return &matlas.GoogleCloudKms{} } - var gcpKmsConfigs []tfGcpKmsConfigModel - tfGcpKmsConfigList.ElementsAs(ctx, &gcpKmsConfigs, false) + v := tfGcpKmsConfigSlice[0] return &matlas.GoogleCloudKms{ - Enabled: gcpKmsConfigs[0].Enabled.ValueBoolPointer(), - ServiceAccountKey: gcpKmsConfigs[0].ServiceAccountKey.ValueString(), - KeyVersionResourceID: gcpKmsConfigs[0].KeyVersionResourceID.ValueString(), + Enabled: v.Enabled.ValueBoolPointer(), + ServiceAccountKey: v.ServiceAccountKey.ValueString(), + KeyVersionResourceID: v.KeyVersionResourceID.ValueString(), } } -func newAtlasAzureKeyVault(ctx context.Context, tfAzureKeyVaultList basetypes.ListValue) *matlas.AzureKeyVault { - if len(tfAzureKeyVaultList.Elements()) == 0 { +func newAtlasAzureKeyVault(tfAzKeyVaultConfigSlice []tfAzureKeyVaultConfigModel) *matlas.AzureKeyVault { + if tfAzKeyVaultConfigSlice == nil || len(tfAzKeyVaultConfigSlice) < 1 { return &matlas.AzureKeyVault{} } - var azureKeyVaultConfigs []tfAzureKeyVaultConfigModel - tfAzureKeyVaultList.ElementsAs(ctx, &azureKeyVaultConfigs, false) + v := tfAzKeyVaultConfigSlice[0] return &matlas.AzureKeyVault{ - Enabled: azureKeyVaultConfigs[0].Enabled.ValueBoolPointer(), - ClientID: azureKeyVaultConfigs[0].ClientID.ValueString(), - AzureEnvironment: azureKeyVaultConfigs[0].AzureEnvironment.ValueString(), - SubscriptionID: azureKeyVaultConfigs[0].SubscriptionID.ValueString(), - ResourceGroupName: azureKeyVaultConfigs[0].ResourceGroupName.ValueString(), - KeyVaultName: azureKeyVaultConfigs[0].KeyVaultName.ValueString(), - KeyIdentifier: azureKeyVaultConfigs[0].KeyIdentifier.ValueString(), - Secret: azureKeyVaultConfigs[0].Secret.ValueString(), - TenantID: azureKeyVaultConfigs[0].TenantID.ValueString(), + Enabled: v.Enabled.ValueBoolPointer(), + ClientID: v.ClientID.ValueString(), + AzureEnvironment: v.AzureEnvironment.ValueString(), + SubscriptionID: v.SubscriptionID.ValueString(), + ResourceGroupName: v.ResourceGroupName.ValueString(), + KeyVaultName: v.KeyVaultName.ValueString(), + KeyIdentifier: v.KeyIdentifier.ValueString(), + Secret: v.Secret.ValueString(), + TenantID: v.TenantID.ValueString(), } } diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go index 4b636df4f5..7e7b58e620 100644 --- a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go @@ -102,18 +102,18 @@ func TestAccAdvRSEncryptionAtRest_basicAWS(t *testing.T) { projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") awsKms = matlas.AwsKms{ - Enabled: pointy.Bool(true), - // AccessKeyID: os.Getenv("AWS_ACCESS_KEY_ID"), - // SecretAccessKey: os.Getenv("AWS_SECRET_ACCESS_KEY"), + Enabled: pointy.Bool(true), + AccessKeyID: os.Getenv("AWS_ACCESS_KEY_ID"), + SecretAccessKey: os.Getenv("AWS_SECRET_ACCESS_KEY"), CustomerMasterKeyID: os.Getenv("AWS_CUSTOMER_MASTER_KEY_ID"), Region: os.Getenv("AWS_REGION"), RoleID: os.Getenv("AWS_ROLE_ID"), } awsKmsUpdated = matlas.AwsKms{ - Enabled: pointy.Bool(true), - // AccessKeyID: os.Getenv("AWS_ACCESS_KEY_ID_UPDATED"), - // SecretAccessKey: os.Getenv("AWS_SECRET_ACCESS_KEY_UPDATED"), + Enabled: pointy.Bool(true), + AccessKeyID: os.Getenv("AWS_ACCESS_KEY_ID_UPDATED"), + SecretAccessKey: os.Getenv("AWS_SECRET_ACCESS_KEY_UPDATED"), CustomerMasterKeyID: os.Getenv("AWS_CUSTOMER_MASTER_KEY_ID_UPDATED"), Region: os.Getenv("AWS_REGION_UPDATED"), RoleID: os.Getenv("AWS_ROLE_ID"), @@ -145,6 +145,13 @@ func TestAccAdvRSEncryptionAtRest_basicAWS(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "aws_kms_config.0.role_id", awsKmsUpdated.RoleID), ), }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccCheckMongoDBAtlasEncryptionAtRestImportStateIDFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"google_cloud_kms_config", "azure_key_vault_config"}, + }, }, }) } @@ -206,6 +213,14 @@ func TestAccAdvRSEncryptionAtRest_basicAzure(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "azure_key_vault_config.0.key_vault_name", azureKeyVaultUpdated.KeyVaultName), ), }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccCheckMongoDBAtlasEncryptionAtRestImportStateIDFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + // "azure_key_vault_config.0.secret" is a sensitive value not returned by the API + ImportStateVerifyIgnore: []string{"google_cloud_kms_config", "aws_kms_config", "azure_key_vault_config.0.secret"}, + }, }, }) } @@ -254,7 +269,8 @@ func TestAccAdvRSEncryptionAtRest_basicGCP(t *testing.T) { ImportStateIdFunc: testAccCheckMongoDBAtlasEncryptionAtRestImportStateIDFunc(resourceName), ImportState: true, ImportStateVerify: true, - // ImportStateVerifyIgnore: []string{"project_id"}, + // "google_cloud_kms_config.0.service_account_key" is a sensitive value not returned by the API + ImportStateVerifyIgnore: []string{"aws_kms_config", "azure_key_vault_config", "google_cloud_kms_config.0.service_account_key"}, }, }, }) @@ -308,69 +324,19 @@ func TestAccAdvRSEncryptionAtRestWithRole_basicAWS(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName), resource.TestCheckResourceAttr(resourceName, "project_id", projectID), - resource.TestCheckResourceAttr(resourceName, "project_id", projectID), ), }, - }, - }) -} - -func TestAccAdvRSEncryptionAtRest_basicAWS_WithAccessKey(t *testing.T) { - var ( - resourceName = "mongodbatlas_encryption_at_rest.test" - projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") - - awsKms = matlas.AwsKms{ - Enabled: pointy.Bool(true), - AccessKeyID: os.Getenv("AWS_ACCESS_KEY_ID"), - SecretAccessKey: os.Getenv("AWS_SECRET_ACCESS_KEY"), - CustomerMasterKeyID: os.Getenv("AWS_CUSTOMER_MASTER_KEY_ID"), - Region: os.Getenv("AWS_REGION"), - // RoleID: os.Getenv("AWS_ROLE_ID"), - } - - // awsKmsUpdated = matlas.AwsKms{ - // Enabled: pointy.Bool(true), - // AccessKeyID: os.Getenv("AWS_ACCESS_KEY_ID_UPDATED"), - // SecretAccessKey: os.Getenv("AWS_SECRET_ACCESS_KEY_UPDATED"), - // CustomerMasterKeyID: os.Getenv("AWS_CUSTOMER_MASTER_KEY_ID_UPDATED"), - // Region: os.Getenv("AWS_REGION_UPDATED"), - // // RoleID: os.Getenv("AWS_ROLE_ID"), - // } - ) - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testCheckAwsEnv(t) }, - ProtoV6ProviderFactories: testAccProviderV6Factories, - CheckDestroy: testAccCheckMongoDBAtlasEncryptionAtRestDestroy, - Steps: []resource.TestStep{ { - Config: testAccMongoDBAtlasEncryptionAtRestConfigAwsKmsWithAccessKeys(projectID, &awsKms), - Check: resource.ComposeTestCheckFunc( - testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "project_id", projectID), - ), + ResourceName: resourceName, + ImportStateIdFunc: testAccCheckMongoDBAtlasEncryptionAtRestImportStateIDFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"google_cloud_kms_config", "azure_key_vault_config"}, }, }, }) } -func testAccMongoDBAtlasEncryptionAtRestConfigAwsKmsWithAccessKeys(projectID string, aws *matlas.AwsKms) string { - return fmt.Sprintf(` - resource "mongodbatlas_encryption_at_rest" "test" { - project_id = "%s" - - aws_kms_config { - enabled = %t - customer_master_key_id = "%s" - region = "%s" - access_key_id = "%s" - secret_access_key = "%s" - } - } - `, projectID, *aws.Enabled, aws.CustomerMasterKeyID, aws.Region, aws.AccessKeyID, aws.SecretAccessKey) -} - func testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { conn := testMongoDBClient.(*MongoDBClient).Atlas From 57be07daa2ccc1408593cb09f6925a43a89c9eb1 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Wed, 23 Aug 2023 12:52:16 +0100 Subject: [PATCH 14/19] cleanup tests --- ...esource_mongodbatlas_encryption_at_rest.go | 2 -- ...atlas_encryption_at_rest_migration_test.go | 13 ++++--- ...ce_mongodbatlas_encryption_at_rest_test.go | 35 ++++++++++--------- 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go index 9a761fd84f..87f6a4efe1 100644 --- a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go @@ -448,7 +448,6 @@ func handleAwsKmsConfigDefaults(ctx context.Context, earRSCurrent, earRSNew, ear } else { earRSNew.AwsKmsConfig[0].Region = earRSCurrent.AwsKmsConfig[0].Region } - } func handleAzureKeyVaultConfigDefaults(ctx context.Context, earRSCurrent, earRSNew, earRSConfig *tfEncryptionAtRestRSModel) { @@ -492,7 +491,6 @@ func newTFAwsKmsConfig(ctx context.Context, awsKms *matlas.AwsKms, currStateSlic newState.RoleID = conversion.StringNullIfEmpty(awsKms.RoleID) return []tfAwsKmsConfigModel{newState} - } func newTFAzureKeyVaultConfig(ctx context.Context, az *matlas.AzureKeyVault, currStateSlice []tfAzureKeyVaultConfigModel) []tfAzureKeyVaultConfigModel { diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_migration_test.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_migration_test.go index cc3815bb22..5a14f96260 100644 --- a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_migration_test.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_migration_test.go @@ -13,6 +13,7 @@ import ( ) func TestAccAdvRS_Migration_EncryptionAtRest_basicAWS(t *testing.T) { + SkipTestExtCred(t) var ( resourceName = "mongodbatlas_encryption_at_rest.test" projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") @@ -25,7 +26,7 @@ func TestAccAdvRS_Migration_EncryptionAtRest_basicAWS(t *testing.T) { } ) - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testCheckAwsEnv(t) }, CheckDestroy: testAccCheckMongoDBAtlasEncryptionAtRestDestroy, Steps: []resource.TestStep{ @@ -60,8 +61,8 @@ func TestAccAdvRS_Migration_EncryptionAtRest_basicAWS(t *testing.T) { } func TestAccAdvRS_Migration_EncryptionAtRest_WithRole_basicAWS(t *testing.T) { - // SkipTest(t) // For now it will skipped because of aws errors reasons, already made another test using terratest. - // SkipTestExtCred(t) + SkipTest(t) + SkipTestExtCred(t) var ( resourceName = "mongodbatlas_encryption_at_rest.test" projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") @@ -122,6 +123,7 @@ func TestAccAdvRS_Migration_EncryptionAtRest_WithRole_basicAWS(t *testing.T) { } func TestAccAdvRS_Migration_EncryptionAtRest_basicAzure(t *testing.T) { + SkipTestExtCred(t) var ( resourceName = "mongodbatlas_encryption_at_rest.test" projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") @@ -139,7 +141,7 @@ func TestAccAdvRS_Migration_EncryptionAtRest_basicAzure(t *testing.T) { } ) - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testCheckEncryptionAtRestEnvAzure(t) }, CheckDestroy: testAccCheckMongoDBAtlasEncryptionAtRestDestroy, Steps: []resource.TestStep{ @@ -175,6 +177,7 @@ func TestAccAdvRS_Migration_EncryptionAtRest_basicAzure(t *testing.T) { } func TestAccAdvRS_Migration_EncryptionAtRest_basicGCP(t *testing.T) { + SkipTestExtCred(t) var ( resourceName = "mongodbatlas_encryption_at_rest.test" projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") @@ -186,7 +189,7 @@ func TestAccAdvRS_Migration_EncryptionAtRest_basicGCP(t *testing.T) { } ) - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckGPCEnv(t) }, CheckDestroy: testAccCheckMongoDBAtlasEncryptionAtRestDestroy, Steps: []resource.TestStep{ diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go index 7e7b58e620..147e41eb62 100644 --- a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest_test.go @@ -97,6 +97,7 @@ data "aws_iam_role" "test" { ) func TestAccAdvRSEncryptionAtRest_basicAWS(t *testing.T) { + SkipTestExtCred(t) var ( resourceName = "mongodbatlas_encryption_at_rest.test" projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") @@ -120,7 +121,7 @@ func TestAccAdvRSEncryptionAtRest_basicAWS(t *testing.T) { } ) - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testCheckAwsEnv(t) }, ProtoV6ProviderFactories: testAccProviderV6Factories, CheckDestroy: testAccCheckMongoDBAtlasEncryptionAtRestDestroy, @@ -157,6 +158,7 @@ func TestAccAdvRSEncryptionAtRest_basicAWS(t *testing.T) { } func TestAccAdvRSEncryptionAtRest_basicAzure(t *testing.T) { + SkipTestExtCred(t) var ( resourceName = "mongodbatlas_encryption_at_rest.test" projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") @@ -186,7 +188,7 @@ func TestAccAdvRSEncryptionAtRest_basicAzure(t *testing.T) { } ) - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testCheckEncryptionAtRestEnvAzure(t) }, ProtoV6ProviderFactories: testAccProviderV6Factories, CheckDestroy: testAccCheckMongoDBAtlasEncryptionAtRestDestroy, @@ -226,6 +228,7 @@ func TestAccAdvRSEncryptionAtRest_basicAzure(t *testing.T) { } func TestAccAdvRSEncryptionAtRest_basicGCP(t *testing.T) { + SkipTestExtCred(t) var ( resourceName = "mongodbatlas_encryption_at_rest.test" projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") @@ -243,7 +246,7 @@ func TestAccAdvRSEncryptionAtRest_basicGCP(t *testing.T) { } ) - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckGPCEnv(t) }, ProtoV6ProviderFactories: testAccProviderV6Factories, CheckDestroy: testAccCheckMongoDBAtlasEncryptionAtRestDestroy, @@ -276,20 +279,9 @@ func TestAccAdvRSEncryptionAtRest_basicGCP(t *testing.T) { }) } -func testAccCheckMongoDBAtlasEncryptionAtRestImportStateIDFunc(resourceName string) resource.ImportStateIdFunc { - return func(s *terraform.State) (string, error) { - rs, ok := s.RootModule().Resources[resourceName] - if !ok { - return "", fmt.Errorf("not found: %s", resourceName) - } - - return rs.Primary.ID, nil - } -} - func TestAccAdvRSEncryptionAtRestWithRole_basicAWS(t *testing.T) { - // SkipTest(t) // For now it will skipped because of aws errors reasons, already made another test using terratest. - // SkipTestExtCred(t) + SkipTest(t) // For now it will skipped because of aws errors reasons, already made another test using terratest. + SkipTestExtCred(t) var ( resourceName = "mongodbatlas_encryption_at_rest.test" projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") @@ -439,3 +431,14 @@ func testAccMongoDBAtlasEncryptionAtRestConfigAwsKmsWithRole(region, awsAccesKey } return config } + +func testAccCheckMongoDBAtlasEncryptionAtRestImportStateIDFunc(resourceName string) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return "", fmt.Errorf("not found: %s", resourceName) + } + + return rs.Primary.ID, nil + } +} From ff1b3cb4d1dc12aeab3d08f823a835706096c5dc Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Wed, 23 Aug 2023 13:31:00 +0100 Subject: [PATCH 15/19] cleanup tests --- .../framework/validator/aws_kms_config_validator_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mongodbatlas/framework/validator/aws_kms_config_validator_test.go b/mongodbatlas/framework/validator/aws_kms_config_validator_test.go index 5d340cd2e2..4b36be62f7 100644 --- a/mongodbatlas/framework/validator/aws_kms_config_validator_test.go +++ b/mongodbatlas/framework/validator/aws_kms_config_validator_test.go @@ -56,9 +56,9 @@ func TestValidAwsKmsConfig(t *testing.T) { } tests := []struct { - name string awsKmsConfigValue map[string]attr.Value awsKmsConfigType map[string]attr.Type + name string wantErr bool }{ { From 16da0d841aaf4242d6bbf43311fceed627717ff8 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Thu, 24 Aug 2023 12:38:17 +0100 Subject: [PATCH 16/19] Address PR comments --- ...esource_mongodbatlas_encryption_at_rest.go | 62 ++++++++----------- 1 file changed, 26 insertions(+), 36 deletions(-) diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go index 87f6a4efe1..5a6b5127c2 100644 --- a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go @@ -20,7 +20,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/mongodb/terraform-provider-mongodbatlas/mongodbatlas/framework/conversion" validators "github.com/mongodb/terraform-provider-mongodbatlas/mongodbatlas/framework/validator" @@ -223,14 +222,22 @@ func (r *EncryptionAtRestRS) Create(ctx context.Context, req resource.CreateRequ projectID := encryptionAtRestPlan.ProjectID.ValueString() encryptionAtRestReq := &matlas.EncryptionAtRest{ - GroupID: projectID, - AwsKms: *newAtlasAwsKms(encryptionAtRestPlan.AwsKmsConfig), - AzureKeyVault: *newAtlasAzureKeyVault(encryptionAtRestPlan.AzureKeyVaultConfig), - GoogleCloudKms: *newAtlasGcpKms(encryptionAtRestPlan.GoogleCloudKmsConfig), + GroupID: projectID, + } + if encryptionAtRestPlan.AwsKmsConfig != nil { + encryptionAtRestReq.AwsKms = *newAtlasAwsKms(encryptionAtRestPlan.AwsKmsConfig) + } + if encryptionAtRestPlan.AzureKeyVaultConfig != nil { + encryptionAtRestReq.AzureKeyVault = *newAtlasAzureKeyVault(encryptionAtRestPlan.AzureKeyVaultConfig) + } + if encryptionAtRestPlan.GoogleCloudKmsConfig != nil { + encryptionAtRestReq.GoogleCloudKms = *newAtlasGcpKms(encryptionAtRestPlan.GoogleCloudKmsConfig) } + var encryptionResp *matlas.EncryptionAtRest + var err error for i := 0; i < 5; i++ { - _, _, err := conn.EncryptionsAtRest.Create(ctx, encryptionAtRestReq) + encryptionResp, _, err = conn.EncryptionsAtRest.Create(ctx, encryptionAtRestReq) if err != nil { if strings.Contains(err.Error(), "CANNOT_ASSUME_ROLE") || strings.Contains(err.Error(), "INVALID_AWS_CREDENTIALS") || strings.Contains(err.Error(), "CLOUD_PROVIDER_ACCESS_ROLE_NOT_AUTHORIZED") { @@ -248,20 +255,8 @@ func (r *EncryptionAtRestRS) Create(ctx context.Context, req resource.CreateRequ break } - // read - encryptionResp, response, err := conn.EncryptionsAtRest.Get(context.Background(), projectID) - tflog.Debug(ctx, fmt.Sprintf("encryptionResp from api: %v", encryptionResp)) - if err != nil { - if resp != nil && response.StatusCode == http.StatusNotFound { - resp.State.RemoveResource(ctx) - return - } - resp.Diagnostics.AddError("error when getting encryption at rest resource after create", fmt.Sprintf(errorReadEncryptionAtRest, err.Error())) - return - } - encryptionAtRestPlanNew := newTFEncryptionAtRestRSModel(ctx, projectID, encryptionResp, encryptionAtRestPlan) - resetDefaultsFromConfig(ctx, encryptionAtRestPlan, encryptionAtRestPlanNew, encryptionAtRestConfig) + resetDefaultsFromConfigOrState(ctx, encryptionAtRestPlan, encryptionAtRestPlanNew, encryptionAtRestConfig) // set state to fully populated data diags := resp.State.Set(ctx, encryptionAtRestPlanNew) @@ -291,7 +286,6 @@ func (r *EncryptionAtRestRS) Read(ctx context.Context, req resource.ReadRequest, conn := r.client.Atlas encryptionResp, _, err := conn.EncryptionsAtRest.Get(context.Background(), projectID) - tflog.Debug(ctx, fmt.Sprintf("encryptionResp from api: %v", encryptionResp)) if err != nil { resp.Diagnostics.AddError("error when getting encryption at rest resource during read", fmt.Sprintf(errorReadEncryptionAtRest, err.Error())) return @@ -299,7 +293,7 @@ func (r *EncryptionAtRestRS) Read(ctx context.Context, req resource.ReadRequest, encryptionAtRestStateNew := newTFEncryptionAtRestRSModel(ctx, projectID, encryptionResp, &encryptionAtRestState) if !isImport { - resetDefaultsFromConfig(ctx, &encryptionAtRestState, encryptionAtRestStateNew, nil) + resetDefaultsFromConfigOrState(ctx, &encryptionAtRestState, encryptionAtRestStateNew, nil) } // save read data into Terraform state @@ -352,26 +346,15 @@ func (r *EncryptionAtRestRS) Update(ctx context.Context, req resource.UpdateRequ } atlasEncryptionAtRest.GroupID = projectID - _, _, err = conn.EncryptionsAtRest.Create(ctx, atlasEncryptionAtRest) - if err != nil { - resp.Diagnostics.AddError("error updating encryption at rest", fmt.Sprintf(errorUpdateEncryptionAtRest, err.Error())) - return - } - // read - encryptionResp, response, err := conn.EncryptionsAtRest.Get(context.Background(), projectID) - tflog.Debug(ctx, fmt.Sprintf("encryptionResp from api: %v", encryptionResp)) + encryptionResp, _, err := conn.EncryptionsAtRest.Create(ctx, atlasEncryptionAtRest) if err != nil { - if resp != nil && response.StatusCode == http.StatusNotFound { - resp.State.RemoveResource(ctx) - return - } - resp.Diagnostics.AddError("error when getting encryption at rest resource after update", fmt.Sprintf(errorReadEncryptionAtRest, err.Error())) + resp.Diagnostics.AddError("error updating encryption at rest", fmt.Sprintf(errorUpdateEncryptionAtRest, err.Error())) return } encryptionAtRestStateNew := newTFEncryptionAtRestRSModel(ctx, projectID, encryptionResp, encryptionAtRestPlan) - resetDefaultsFromConfig(ctx, encryptionAtRestState, encryptionAtRestStateNew, encryptionAtRestConfig) + resetDefaultsFromConfigOrState(ctx, encryptionAtRestState, encryptionAtRestStateNew, encryptionAtRestConfig) // save updated data into Terraform state resp.Diagnostics.Append(resp.State.Set(ctx, &encryptionAtRestStateNew)...) @@ -412,7 +395,14 @@ func hasAwsKmsConfigChanged(awsKmsConfigPlan, awsKmsConfigState []tfAwsKmsConfig return !reflect.DeepEqual(awsKmsConfigPlan, awsKmsConfigState) } -func resetDefaultsFromConfig(ctx context.Context, encryptionAtRestRSCurrent, encryptionAtRestRSNew, encryptionAtRestRSConfig *tfEncryptionAtRestRSModel) { +// resetDefaultsFromConfigOrState resets certain values that are not returned by the Atlas APIs from the Config +// However, during Read() and ImportState() since there is no access to the Config object, we use the State/Plan +// to achieve the same and encryptionAtRestRSConfig in that case is passed as nil in the calling method. +// +// encryptionAtRestRSCurrent - current State/Plan for this resource +// encryptionAtRestRSNew - final object that will be written in the State once the CRUD operation succeeds +// encryptionAtRestRSConfig - Config object for this resource +func resetDefaultsFromConfigOrState(ctx context.Context, encryptionAtRestRSCurrent, encryptionAtRestRSNew, encryptionAtRestRSConfig *tfEncryptionAtRestRSModel) { handleAwsKmsConfigDefaults(ctx, encryptionAtRestRSCurrent, encryptionAtRestRSNew, encryptionAtRestRSConfig) handleAzureKeyVaultConfigDefaults(ctx, encryptionAtRestRSCurrent, encryptionAtRestRSNew, encryptionAtRestRSConfig) handleGcpKmsConfig(ctx, encryptionAtRestRSCurrent, encryptionAtRestRSNew, encryptionAtRestRSConfig) From c7d09c8f47bd9ff69b75333f277453362d95a557 Mon Sep 17 00:00:00 2001 From: maastha <122359335+maastha@users.noreply.github.com> Date: Fri, 25 Aug 2023 18:11:16 +0100 Subject: [PATCH 17/19] Apply suggestions from code review Co-authored-by: Agustin Bettati Co-authored-by: Andrea Angiolillo --- mongodbatlas/framework/validator/aws_kms_config_validator.go | 2 +- mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/mongodbatlas/framework/validator/aws_kms_config_validator.go b/mongodbatlas/framework/validator/aws_kms_config_validator.go index 3a4a0e8b27..8772cfb010 100644 --- a/mongodbatlas/framework/validator/aws_kms_config_validator.go +++ b/mongodbatlas/framework/validator/aws_kms_config_validator.go @@ -35,7 +35,7 @@ func (v awsKmsConfigValidator) ValidateObject(ctx context.Context, req validator sa, saOk := attrMap["secret_access_key"] r, rOk := attrMap["role_id"] - if ((akOk && !ak.IsNull()) && (saOk && !sa.IsNull()) && (rOk && !r.IsNull())) || + if (accessKeyDefined && secretAccessKeyDefined && roleIdDefined) || ((akOk && !ak.IsNull()) && (rOk && !r.IsNull())) || ((saOk && !sa.IsNull()) && (rOk && !r.IsNull())) { response.Diagnostics.Append(validatordiag.InvalidAttributeValueDiagnostic( diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go index 5a6b5127c2..f448fbdc66 100644 --- a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go @@ -457,14 +457,13 @@ func handleAzureKeyVaultConfigDefaults(ctx context.Context, earRSCurrent, earRSN } func newTFEncryptionAtRestRSModel(ctx context.Context, projectID string, encryptionResp *matlas.EncryptionAtRest, plan *tfEncryptionAtRestRSModel) *tfEncryptionAtRestRSModel { - encryptionAtRest := tfEncryptionAtRestRSModel{ + return &tfEncryptionAtRestRSModel{ ID: types.StringValue(projectID), ProjectID: types.StringValue(projectID), AwsKmsConfig: newTFAwsKmsConfig(ctx, &encryptionResp.AwsKms, plan.AwsKmsConfig), AzureKeyVaultConfig: newTFAzureKeyVaultConfig(ctx, &encryptionResp.AzureKeyVault, plan.AzureKeyVaultConfig), GoogleCloudKmsConfig: newTFGcpKmsConfig(ctx, &encryptionResp.GoogleCloudKms, plan.GoogleCloudKmsConfig), - } - return &encryptionAtRest + } } func newTFAwsKmsConfig(ctx context.Context, awsKms *matlas.AwsKms, currStateSlice []tfAwsKmsConfigModel) []tfAwsKmsConfigModel { From 3faf6d3dfd7191c7bd5fbaa388f629965ad3e5f2 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Fri, 25 Aug 2023 18:24:22 +0100 Subject: [PATCH 18/19] address PR comments --- .../framework/validator/aws_kms_config_validator.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mongodbatlas/framework/validator/aws_kms_config_validator.go b/mongodbatlas/framework/validator/aws_kms_config_validator.go index 8772cfb010..0a9dde91ae 100644 --- a/mongodbatlas/framework/validator/aws_kms_config_validator.go +++ b/mongodbatlas/framework/validator/aws_kms_config_validator.go @@ -34,10 +34,13 @@ func (v awsKmsConfigValidator) ValidateObject(ctx context.Context, req validator ak, akOk := attrMap["access_key_id"] sa, saOk := attrMap["secret_access_key"] r, rOk := attrMap["role_id"] + accessKeyDefined := akOk && !ak.IsNull() + secretAccessKeyDefined := saOk && !sa.IsNull() + roleIDDefined := rOk && !r.IsNull() - if (accessKeyDefined && secretAccessKeyDefined && roleIdDefined) || - ((akOk && !ak.IsNull()) && (rOk && !r.IsNull())) || - ((saOk && !sa.IsNull()) && (rOk && !r.IsNull())) { + if (accessKeyDefined && secretAccessKeyDefined && roleIDDefined) || + (accessKeyDefined && roleIDDefined) || + (secretAccessKeyDefined && roleIDDefined) { response.Diagnostics.Append(validatordiag.InvalidAttributeValueDiagnostic( req.Path, v.Description(ctx), From 68700e4f3eb22d26ae2df93bcb12e3b659bb22a3 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Fri, 25 Aug 2023 18:28:00 +0100 Subject: [PATCH 19/19] address PR comments --- mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go index f448fbdc66..c35279b88f 100644 --- a/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go +++ b/mongodbatlas/fw_resource_mongodbatlas_encryption_at_rest.go @@ -463,7 +463,7 @@ func newTFEncryptionAtRestRSModel(ctx context.Context, projectID string, encrypt AwsKmsConfig: newTFAwsKmsConfig(ctx, &encryptionResp.AwsKms, plan.AwsKmsConfig), AzureKeyVaultConfig: newTFAzureKeyVaultConfig(ctx, &encryptionResp.AzureKeyVault, plan.AzureKeyVaultConfig), GoogleCloudKmsConfig: newTFGcpKmsConfig(ctx, &encryptionResp.GoogleCloudKms, plan.GoogleCloudKmsConfig), - } + } } func newTFAwsKmsConfig(ctx context.Context, awsKms *matlas.AwsKms, currStateSlice []tfAwsKmsConfigModel) []tfAwsKmsConfigModel {