diff --git a/.changelog/9415.txt b/.changelog/9415.txt new file mode 100644 index 00000000000..e72e801260c --- /dev/null +++ b/.changelog/9415.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +`google_secure_source_manager_instance` +``` diff --git a/.teamcity/components/generated/services.kt b/.teamcity/components/generated/services.kt index d2c5550c82d..802eb7290a1 100644 --- a/.teamcity/components/generated/services.kt +++ b/.teamcity/components/generated/services.kt @@ -546,6 +546,11 @@ var services = mapOf( "displayName" to "Secretmanager", "path" to "./google/services/secretmanager" ), + "securesourcemanager" to mapOf( + "name" to "securesourcemanager", + "displayName" to "Securesourcemanager", + "path" to "./google/services/securesourcemanager" + ), "securitycenter" to mapOf( "name" to "securitycenter", "displayName" to "Securitycenter", diff --git a/google/fwmodels/provider_model.go b/google/fwmodels/provider_model.go index 91b4b7ba8d1..b2823e9167c 100644 --- a/google/fwmodels/provider_model.go +++ b/google/fwmodels/provider_model.go @@ -115,6 +115,7 @@ type ProviderModel struct { RedisCustomEndpoint types.String `tfsdk:"redis_custom_endpoint"` ResourceManagerCustomEndpoint types.String `tfsdk:"resource_manager_custom_endpoint"` SecretManagerCustomEndpoint types.String `tfsdk:"secret_manager_custom_endpoint"` + SecureSourceManagerCustomEndpoint types.String `tfsdk:"secure_source_manager_custom_endpoint"` SecurityCenterCustomEndpoint types.String `tfsdk:"security_center_custom_endpoint"` ServiceManagementCustomEndpoint types.String `tfsdk:"service_management_custom_endpoint"` ServiceUsageCustomEndpoint types.String `tfsdk:"service_usage_custom_endpoint"` diff --git a/google/fwprovider/framework_provider.go b/google/fwprovider/framework_provider.go index 3f32e2f5d67..c37eaa0ac4a 100644 --- a/google/fwprovider/framework_provider.go +++ b/google/fwprovider/framework_provider.go @@ -670,6 +670,12 @@ func (p *FrameworkProvider) Schema(_ context.Context, _ provider.SchemaRequest, transport_tpg.CustomEndpointValidator(), }, }, + "secure_source_manager_custom_endpoint": &schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + transport_tpg.CustomEndpointValidator(), + }, + }, "security_center_custom_endpoint": &schema.StringAttribute{ Optional: true, Validators: []validator.String{ diff --git a/google/fwtransport/framework_config.go b/google/fwtransport/framework_config.go index 4a360cb4de4..5617458c283 100644 --- a/google/fwtransport/framework_config.go +++ b/google/fwtransport/framework_config.go @@ -140,6 +140,7 @@ type FrameworkProviderConfig struct { RedisBasePath string ResourceManagerBasePath string SecretManagerBasePath string + SecureSourceManagerBasePath string SecurityCenterBasePath string ServiceManagementBasePath string ServiceUsageBasePath string @@ -283,6 +284,7 @@ func (p *FrameworkProviderConfig) LoadAndValidateFramework(ctx context.Context, p.RedisBasePath = data.RedisCustomEndpoint.ValueString() p.ResourceManagerBasePath = data.ResourceManagerCustomEndpoint.ValueString() p.SecretManagerBasePath = data.SecretManagerCustomEndpoint.ValueString() + p.SecureSourceManagerBasePath = data.SecureSourceManagerCustomEndpoint.ValueString() p.SecurityCenterBasePath = data.SecurityCenterCustomEndpoint.ValueString() p.ServiceManagementBasePath = data.ServiceManagementCustomEndpoint.ValueString() p.ServiceUsageBasePath = data.ServiceUsageCustomEndpoint.ValueString() @@ -1137,6 +1139,14 @@ func (p *FrameworkProviderConfig) HandleDefaults(ctx context.Context, data *fwmo data.SecretManagerCustomEndpoint = types.StringValue(customEndpoint.(string)) } } + if data.SecureSourceManagerCustomEndpoint.IsNull() { + customEndpoint := transport_tpg.MultiEnvDefault([]string{ + "GOOGLE_SECURE_SOURCE_MANAGER_CUSTOM_ENDPOINT", + }, transport_tpg.DefaultBasePaths[transport_tpg.SecureSourceManagerBasePathKey]) + if customEndpoint != nil { + data.SecureSourceManagerCustomEndpoint = types.StringValue(customEndpoint.(string)) + } + } if data.SecurityCenterCustomEndpoint.IsNull() { customEndpoint := transport_tpg.MultiEnvDefault([]string{ "GOOGLE_SECURITY_CENTER_CUSTOM_ENDPOINT", diff --git a/google/provider/provider.go b/google/provider/provider.go index 1439a91a829..b73312d40d0 100644 --- a/google/provider/provider.go +++ b/google/provider/provider.go @@ -580,6 +580,11 @@ func Provider() *schema.Provider { Optional: true, ValidateFunc: transport_tpg.ValidateCustomEndpoint, }, + "secure_source_manager_custom_endpoint": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: transport_tpg.ValidateCustomEndpoint, + }, "security_center_custom_endpoint": { Type: schema.TypeString, Optional: true, @@ -944,6 +949,7 @@ func ProviderConfigure(ctx context.Context, d *schema.ResourceData, p *schema.Pr config.RedisBasePath = d.Get("redis_custom_endpoint").(string) config.ResourceManagerBasePath = d.Get("resource_manager_custom_endpoint").(string) config.SecretManagerBasePath = d.Get("secret_manager_custom_endpoint").(string) + config.SecureSourceManagerBasePath = d.Get("secure_source_manager_custom_endpoint").(string) config.SecurityCenterBasePath = d.Get("security_center_custom_endpoint").(string) config.ServiceManagementBasePath = d.Get("service_management_custom_endpoint").(string) config.ServiceUsageBasePath = d.Get("service_usage_custom_endpoint").(string) diff --git a/google/provider/provider_mmv1_resources.go b/google/provider/provider_mmv1_resources.go index 75b4c827be4..f2c0562f066 100644 --- a/google/provider/provider_mmv1_resources.go +++ b/google/provider/provider_mmv1_resources.go @@ -94,6 +94,7 @@ import ( "github.com/hashicorp/terraform-provider-google/google/services/redis" "github.com/hashicorp/terraform-provider-google/google/services/resourcemanager" "github.com/hashicorp/terraform-provider-google/google/services/secretmanager" + "github.com/hashicorp/terraform-provider-google/google/services/securesourcemanager" "github.com/hashicorp/terraform-provider-google/google/services/securitycenter" "github.com/hashicorp/terraform-provider-google/google/services/servicemanagement" "github.com/hashicorp/terraform-provider-google/google/services/sourcerepo" @@ -324,6 +325,7 @@ var generatedIAMDatasources = map[string]*schema.Resource{ "google_pubsub_schema_iam_policy": tpgiamresource.DataSourceIamPolicy(pubsub.PubsubSchemaIamSchema, pubsub.PubsubSchemaIamUpdaterProducer), "google_pubsub_topic_iam_policy": tpgiamresource.DataSourceIamPolicy(pubsub.PubsubTopicIamSchema, pubsub.PubsubTopicIamUpdaterProducer), "google_secret_manager_secret_iam_policy": tpgiamresource.DataSourceIamPolicy(secretmanager.SecretManagerSecretIamSchema, secretmanager.SecretManagerSecretIamUpdaterProducer), + "google_secure_source_manager_instance_iam_policy": tpgiamresource.DataSourceIamPolicy(securesourcemanager.SecureSourceManagerInstanceIamSchema, securesourcemanager.SecureSourceManagerInstanceIamUpdaterProducer), "google_scc_source_iam_policy": tpgiamresource.DataSourceIamPolicy(securitycenter.SecurityCenterSourceIamSchema, securitycenter.SecurityCenterSourceIamUpdaterProducer), "google_endpoints_service_iam_policy": tpgiamresource.DataSourceIamPolicy(servicemanagement.ServiceManagementServiceIamSchema, servicemanagement.ServiceManagementServiceIamUpdaterProducer), "google_endpoints_service_consumers_iam_policy": tpgiamresource.DataSourceIamPolicy(servicemanagement.ServiceManagementServiceConsumersIamSchema, servicemanagement.ServiceManagementServiceConsumersIamUpdaterProducer), @@ -359,9 +361,9 @@ var handwrittenIAMDatasources = map[string]*schema.Resource{ } // Resources -// Generated resources: 344 -// Generated IAM resources: 213 -// Total generated resources: 557 +// Generated resources: 345 +// Generated IAM resources: 216 +// Total generated resources: 561 var generatedResources = map[string]*schema.Resource{ "google_folder_access_approval_settings": accessapproval.ResourceAccessApprovalFolderSettings(), "google_organization_access_approval_settings": accessapproval.ResourceAccessApprovalOrganizationSettings(), @@ -847,6 +849,10 @@ var generatedResources = map[string]*schema.Resource{ "google_secret_manager_secret_iam_member": tpgiamresource.ResourceIamMember(secretmanager.SecretManagerSecretIamSchema, secretmanager.SecretManagerSecretIamUpdaterProducer, secretmanager.SecretManagerSecretIdParseFunc), "google_secret_manager_secret_iam_policy": tpgiamresource.ResourceIamPolicy(secretmanager.SecretManagerSecretIamSchema, secretmanager.SecretManagerSecretIamUpdaterProducer, secretmanager.SecretManagerSecretIdParseFunc), "google_secret_manager_secret_version": secretmanager.ResourceSecretManagerSecretVersion(), + "google_secure_source_manager_instance": securesourcemanager.ResourceSecureSourceManagerInstance(), + "google_secure_source_manager_instance_iam_binding": tpgiamresource.ResourceIamBinding(securesourcemanager.SecureSourceManagerInstanceIamSchema, securesourcemanager.SecureSourceManagerInstanceIamUpdaterProducer, securesourcemanager.SecureSourceManagerInstanceIdParseFunc), + "google_secure_source_manager_instance_iam_member": tpgiamresource.ResourceIamMember(securesourcemanager.SecureSourceManagerInstanceIamSchema, securesourcemanager.SecureSourceManagerInstanceIamUpdaterProducer, securesourcemanager.SecureSourceManagerInstanceIdParseFunc), + "google_secure_source_manager_instance_iam_policy": tpgiamresource.ResourceIamPolicy(securesourcemanager.SecureSourceManagerInstanceIamSchema, securesourcemanager.SecureSourceManagerInstanceIamUpdaterProducer, securesourcemanager.SecureSourceManagerInstanceIdParseFunc), "google_scc_folder_custom_module": securitycenter.ResourceSecurityCenterFolderCustomModule(), "google_scc_mute_config": securitycenter.ResourceSecurityCenterMuteConfig(), "google_scc_notification_config": securitycenter.ResourceSecurityCenterNotificationConfig(), diff --git a/google/services/securesourcemanager/iam_secure_source_manager_instance.go b/google/services/securesourcemanager/iam_secure_source_manager_instance.go new file mode 100644 index 00000000000..40d480a502e --- /dev/null +++ b/google/services/securesourcemanager/iam_secure_source_manager_instance.go @@ -0,0 +1,245 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package securesourcemanager + +import ( + "fmt" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "google.golang.org/api/cloudresourcemanager/v1" + + "github.com/hashicorp/terraform-provider-google/google/tpgiamresource" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +var SecureSourceManagerInstanceIamSchema = map[string]*schema.Schema{ + "project": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + }, + "location": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + }, + "instance_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: tpgresource.CompareSelfLinkOrResourceName, + }, +} + +type SecureSourceManagerInstanceIamUpdater struct { + project string + location string + instanceId string + d tpgresource.TerraformResourceData + Config *transport_tpg.Config +} + +func SecureSourceManagerInstanceIamUpdaterProducer(d tpgresource.TerraformResourceData, config *transport_tpg.Config) (tpgiamresource.ResourceIamUpdater, error) { + values := make(map[string]string) + + project, _ := tpgresource.GetProject(d, config) + if project != "" { + if err := d.Set("project", project); err != nil { + return nil, fmt.Errorf("Error setting project: %s", err) + } + } + values["project"] = project + location, _ := tpgresource.GetLocation(d, config) + if location != "" { + if err := d.Set("location", location); err != nil { + return nil, fmt.Errorf("Error setting location: %s", err) + } + } + values["location"] = location + if v, ok := d.GetOk("instance_id"); ok { + values["instance_id"] = v.(string) + } + + // We may have gotten either a long or short name, so attempt to parse long name if possible + m, err := tpgresource.GetImportIdQualifiers([]string{"projects/(?P[^/]+)/locations/(?P[^/]+)/instances/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config, d.Get("instance_id").(string)) + if err != nil { + return nil, err + } + + for k, v := range m { + values[k] = v + } + + u := &SecureSourceManagerInstanceIamUpdater{ + project: values["project"], + location: values["location"], + instanceId: values["instance_id"], + d: d, + Config: config, + } + + if err := d.Set("project", u.project); err != nil { + return nil, fmt.Errorf("Error setting project: %s", err) + } + if err := d.Set("location", u.location); err != nil { + return nil, fmt.Errorf("Error setting location: %s", err) + } + if err := d.Set("instance_id", u.GetResourceId()); err != nil { + return nil, fmt.Errorf("Error setting instance_id: %s", err) + } + + return u, nil +} + +func SecureSourceManagerInstanceIdParseFunc(d *schema.ResourceData, config *transport_tpg.Config) error { + values := make(map[string]string) + + project, _ := tpgresource.GetProject(d, config) + if project != "" { + values["project"] = project + } + + location, _ := tpgresource.GetLocation(d, config) + if location != "" { + values["location"] = location + } + + m, err := tpgresource.GetImportIdQualifiers([]string{"projects/(?P[^/]+)/locations/(?P[^/]+)/instances/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config, d.Id()) + if err != nil { + return err + } + + for k, v := range m { + values[k] = v + } + + u := &SecureSourceManagerInstanceIamUpdater{ + project: values["project"], + location: values["location"], + instanceId: values["instance_id"], + d: d, + Config: config, + } + if err := d.Set("instance_id", u.GetResourceId()); err != nil { + return fmt.Errorf("Error setting instance_id: %s", err) + } + d.SetId(u.GetResourceId()) + return nil +} + +func (u *SecureSourceManagerInstanceIamUpdater) GetResourceIamPolicy() (*cloudresourcemanager.Policy, error) { + url, err := u.qualifyInstanceUrl("getIamPolicy") + if err != nil { + return nil, err + } + + project, err := tpgresource.GetProject(u.d, u.Config) + if err != nil { + return nil, err + } + var obj map[string]interface{} + + userAgent, err := tpgresource.GenerateUserAgentString(u.d, u.Config.UserAgent) + if err != nil { + return nil, err + } + + policy, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: u.Config, + Method: "GET", + Project: project, + RawURL: url, + UserAgent: userAgent, + Body: obj, + }) + if err != nil { + return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for %s: {{err}}", u.DescribeResource()), err) + } + + out := &cloudresourcemanager.Policy{} + err = tpgresource.Convert(policy, out) + if err != nil { + return nil, errwrap.Wrapf("Cannot convert a policy to a resource manager policy: {{err}}", err) + } + + return out, nil +} + +func (u *SecureSourceManagerInstanceIamUpdater) SetResourceIamPolicy(policy *cloudresourcemanager.Policy) error { + json, err := tpgresource.ConvertToMap(policy) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + obj["policy"] = json + + url, err := u.qualifyInstanceUrl("setIamPolicy") + if err != nil { + return err + } + project, err := tpgresource.GetProject(u.d, u.Config) + if err != nil { + return err + } + + userAgent, err := tpgresource.GenerateUserAgentString(u.d, u.Config.UserAgent) + if err != nil { + return err + } + + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: u.Config, + Method: "POST", + Project: project, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: u.d.Timeout(schema.TimeoutCreate), + }) + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("Error setting IAM policy for %s: {{err}}", u.DescribeResource()), err) + } + + return nil +} + +func (u *SecureSourceManagerInstanceIamUpdater) qualifyInstanceUrl(methodIdentifier string) (string, error) { + urlTemplate := fmt.Sprintf("{{SecureSourceManagerBasePath}}%s:%s", fmt.Sprintf("projects/%s/locations/%s/instances/%s", u.project, u.location, u.instanceId), methodIdentifier) + url, err := tpgresource.ReplaceVars(u.d, u.Config, urlTemplate) + if err != nil { + return "", err + } + return url, nil +} + +func (u *SecureSourceManagerInstanceIamUpdater) GetResourceId() string { + return fmt.Sprintf("projects/%s/locations/%s/instances/%s", u.project, u.location, u.instanceId) +} + +func (u *SecureSourceManagerInstanceIamUpdater) GetMutexKey() string { + return fmt.Sprintf("iam-securesourcemanager-instance-%s", u.GetResourceId()) +} + +func (u *SecureSourceManagerInstanceIamUpdater) DescribeResource() string { + return fmt.Sprintf("securesourcemanager instance %q", u.GetResourceId()) +} diff --git a/google/services/securesourcemanager/iam_secure_source_manager_instance_generated_test.go b/google/services/securesourcemanager/iam_secure_source_manager_instance_generated_test.go new file mode 100644 index 00000000000..ca26810c239 --- /dev/null +++ b/google/services/securesourcemanager/iam_secure_source_manager_instance_generated_test.go @@ -0,0 +1,251 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package securesourcemanager_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +func TestAccSecureSourceManagerInstanceIamBindingGenerated(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "role": "roles/securesourcemanager.instanceManager", + "admin_role": "roles/securesourcemanager.instanceOwner", + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccSecureSourceManagerInstanceIamBinding_basicGenerated(context), + }, + { + ResourceName: "google_secure_source_manager_instance_iam_binding.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/instances/%s roles/securesourcemanager.instanceManager", envvar.GetTestProjectFromEnv(), envvar.GetTestRegionFromEnv(), fmt.Sprintf("tf-test-my-instance%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + { + // Test Iam Binding update + Config: testAccSecureSourceManagerInstanceIamBinding_updateGenerated(context), + }, + { + ResourceName: "google_secure_source_manager_instance_iam_binding.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/instances/%s roles/securesourcemanager.instanceManager", envvar.GetTestProjectFromEnv(), envvar.GetTestRegionFromEnv(), fmt.Sprintf("tf-test-my-instance%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccSecureSourceManagerInstanceIamMemberGenerated(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "role": "roles/securesourcemanager.instanceManager", + "admin_role": "roles/securesourcemanager.instanceOwner", + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + // Test Iam Member creation (no update for member, no need to test) + Config: testAccSecureSourceManagerInstanceIamMember_basicGenerated(context), + }, + { + ResourceName: "google_secure_source_manager_instance_iam_member.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/instances/%s roles/securesourcemanager.instanceManager user:admin@hashicorptest.com", envvar.GetTestProjectFromEnv(), envvar.GetTestRegionFromEnv(), fmt.Sprintf("tf-test-my-instance%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccSecureSourceManagerInstanceIamPolicyGenerated(t *testing.T) { + t.Parallel() + + // This may skip test, so do it first + sa := envvar.GetTestServiceAccountFromEnv(t) + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "role": "roles/securesourcemanager.instanceManager", + "admin_role": "roles/securesourcemanager.instanceOwner", + } + context["service_account"] = sa + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccSecureSourceManagerInstanceIamPolicy_basicGenerated(context), + Check: resource.TestCheckResourceAttrSet("data.google_secure_source_manager_instance_iam_policy.foo", "policy_data"), + }, + { + ResourceName: "google_secure_source_manager_instance_iam_policy.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/instances/%s", envvar.GetTestProjectFromEnv(), envvar.GetTestRegionFromEnv(), fmt.Sprintf("tf-test-my-instance%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccSecureSourceManagerInstanceIamPolicy_emptyBinding(context), + }, + { + ResourceName: "google_secure_source_manager_instance_iam_policy.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/instances/%s", envvar.GetTestProjectFromEnv(), envvar.GetTestRegionFromEnv(), fmt.Sprintf("tf-test-my-instance%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccSecureSourceManagerInstanceIamMember_basicGenerated(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_secure_source_manager_instance" "default" { + location = "us-central1" + instance_id = "tf-test-my-instance%{random_suffix}" + labels = { + "foo" = "bar" + } +} + +resource "google_secure_source_manager_instance_iam_member" "foo" { + project = google_secure_source_manager_instance.default.project + location = google_secure_source_manager_instance.default.location + instance_id = google_secure_source_manager_instance.default.instance_id + role = "%{role}" + member = "user:admin@hashicorptest.com" +} +`, context) +} + +func testAccSecureSourceManagerInstanceIamPolicy_basicGenerated(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_secure_source_manager_instance" "default" { + location = "us-central1" + instance_id = "tf-test-my-instance%{random_suffix}" + labels = { + "foo" = "bar" + } +} + +data "google_iam_policy" "foo" { + binding { + role = "%{role}" + members = ["user:admin@hashicorptest.com"] + } + binding { + role = "%{admin_role}" + members = ["serviceAccount:%{service_account}"] + } +} + +resource "google_secure_source_manager_instance_iam_policy" "foo" { + project = google_secure_source_manager_instance.default.project + location = google_secure_source_manager_instance.default.location + instance_id = google_secure_source_manager_instance.default.instance_id + policy_data = data.google_iam_policy.foo.policy_data +} + +data "google_secure_source_manager_instance_iam_policy" "foo" { + project = google_secure_source_manager_instance.default.project + location = google_secure_source_manager_instance.default.location + instance_id = google_secure_source_manager_instance.default.instance_id + depends_on = [ + google_secure_source_manager_instance_iam_policy.foo + ] +} +`, context) +} + +func testAccSecureSourceManagerInstanceIamPolicy_emptyBinding(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_secure_source_manager_instance" "default" { + location = "us-central1" + instance_id = "tf-test-my-instance%{random_suffix}" + labels = { + "foo" = "bar" + } +} + +data "google_iam_policy" "foo" { +} + +resource "google_secure_source_manager_instance_iam_policy" "foo" { + project = google_secure_source_manager_instance.default.project + location = google_secure_source_manager_instance.default.location + instance_id = google_secure_source_manager_instance.default.instance_id + policy_data = data.google_iam_policy.foo.policy_data +} +`, context) +} + +func testAccSecureSourceManagerInstanceIamBinding_basicGenerated(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_secure_source_manager_instance" "default" { + location = "us-central1" + instance_id = "tf-test-my-instance%{random_suffix}" + labels = { + "foo" = "bar" + } +} + +resource "google_secure_source_manager_instance_iam_binding" "foo" { + project = google_secure_source_manager_instance.default.project + location = google_secure_source_manager_instance.default.location + instance_id = google_secure_source_manager_instance.default.instance_id + role = "%{role}" + members = ["user:admin@hashicorptest.com"] +} +`, context) +} + +func testAccSecureSourceManagerInstanceIamBinding_updateGenerated(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_secure_source_manager_instance" "default" { + location = "us-central1" + instance_id = "tf-test-my-instance%{random_suffix}" + labels = { + "foo" = "bar" + } +} + +resource "google_secure_source_manager_instance_iam_binding" "foo" { + project = google_secure_source_manager_instance.default.project + location = google_secure_source_manager_instance.default.location + instance_id = google_secure_source_manager_instance.default.instance_id + role = "%{role}" + members = ["user:admin@hashicorptest.com", "user:gterraformtest1@gmail.com"] +} +`, context) +} diff --git a/google/services/securesourcemanager/resource_secure_source_manager_instance.go b/google/services/securesourcemanager/resource_secure_source_manager_instance.go new file mode 100644 index 00000000000..089bb49701e --- /dev/null +++ b/google/services/securesourcemanager/resource_secure_source_manager_instance.go @@ -0,0 +1,390 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package securesourcemanager + +import ( + "fmt" + "log" + "reflect" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func ResourceSecureSourceManagerInstance() *schema.Resource { + return &schema.Resource{ + Create: resourceSecureSourceManagerInstanceCreate, + Read: resourceSecureSourceManagerInstanceRead, + Delete: resourceSecureSourceManagerInstanceDelete, + + Importer: &schema.ResourceImporter{ + State: resourceSecureSourceManagerInstanceImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(60 * time.Minute), + Delete: schema.DefaultTimeout(60 * time.Minute), + }, + + CustomizeDiff: customdiff.All( + tpgresource.SetLabelsDiff, + tpgresource.DefaultProviderProject, + ), + + Schema: map[string]*schema.Schema{ + "instance_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The name for the Instance.`, + }, + "location": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The location for the Instance.`, + }, + "labels": { + Type: schema.TypeMap, + Optional: true, + ForceNew: true, + Description: `Labels as key value pairs. + + +**Note**: This field is non-authoritative, and will only manage the labels present in your configuration. +Please refer to the field 'effective_labels' for all of the labels present on the resource.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "create_time": { + Type: schema.TypeString, + Computed: true, + Description: `Time the Instance was created in UTC.`, + }, + "effective_labels": { + Type: schema.TypeMap, + Computed: true, + ForceNew: true, + Description: `All of labels (key/value pairs) present on the resource in GCP, including the labels configured through Terraform, other clients and services.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: `The resource name for the Instance.`, + }, + "state": { + Type: schema.TypeString, + Computed: true, + Description: `The current state of the Instance.`, + }, + "terraform_labels": { + Type: schema.TypeMap, + Computed: true, + ForceNew: true, + Description: `The combination of labels configured directly on the resource + and default labels configured on the provider.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "update_time": { + Type: schema.TypeString, + Computed: true, + Description: `Time the Instance was updated in UTC.`, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + UseJSONNumber: true, + } +} + +func resourceSecureSourceManagerInstanceCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + labelsProp, err := expandSecureSourceManagerInstanceEffectiveLabels(d.Get("effective_labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("effective_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } + + url, err := tpgresource.ReplaceVars(d, config, "{{SecureSourceManagerBasePath}}projects/{{project}}/locations/{{location}}/instances?instance_id={{instance_id}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new Instance: %#v", obj) + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for Instance: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "POST", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutCreate), + }) + if err != nil { + return fmt.Errorf("Error creating Instance: %s", err) + } + + // Store the ID now + id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/locations/{{location}}/instances/{{instance_id}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + err = SecureSourceManagerOperationWaitTime( + config, res, project, "Creating Instance", userAgent, + d.Timeout(schema.TimeoutCreate)) + + if err != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create Instance: %s", err) + } + + log.Printf("[DEBUG] Finished creating Instance %q: %#v", d.Id(), res) + + return resourceSecureSourceManagerInstanceRead(d, meta) +} + +func resourceSecureSourceManagerInstanceRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + url, err := tpgresource.ReplaceVars(d, config, "{{SecureSourceManagerBasePath}}projects/{{project}}/locations/{{location}}/instances/{{instance_id}}") + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for Instance: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + }) + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("SecureSourceManagerInstance %q", d.Id())) + } + + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading Instance: %s", err) + } + + if err := d.Set("name", flattenSecureSourceManagerInstanceName(res["name"], d, config)); err != nil { + return fmt.Errorf("Error reading Instance: %s", err) + } + if err := d.Set("create_time", flattenSecureSourceManagerInstanceCreateTime(res["createTime"], d, config)); err != nil { + return fmt.Errorf("Error reading Instance: %s", err) + } + if err := d.Set("update_time", flattenSecureSourceManagerInstanceUpdateTime(res["updateTime"], d, config)); err != nil { + return fmt.Errorf("Error reading Instance: %s", err) + } + if err := d.Set("labels", flattenSecureSourceManagerInstanceLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading Instance: %s", err) + } + if err := d.Set("state", flattenSecureSourceManagerInstanceState(res["state"], d, config)); err != nil { + return fmt.Errorf("Error reading Instance: %s", err) + } + if err := d.Set("terraform_labels", flattenSecureSourceManagerInstanceTerraformLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading Instance: %s", err) + } + if err := d.Set("effective_labels", flattenSecureSourceManagerInstanceEffectiveLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading Instance: %s", err) + } + + return nil +} + +func resourceSecureSourceManagerInstanceDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for Instance: %s", err) + } + billingProject = project + + url, err := tpgresource.ReplaceVars(d, config, "{{SecureSourceManagerBasePath}}projects/{{project}}/locations/{{location}}/instances/{{instance_id}}") + if err != nil { + return err + } + + var obj map[string]interface{} + log.Printf("[DEBUG] Deleting Instance %q", d.Id()) + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "DELETE", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutDelete), + }) + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, "Instance") + } + + err = SecureSourceManagerOperationWaitTime( + config, res, project, "Deleting Instance", userAgent, + d.Timeout(schema.TimeoutDelete)) + + if err != nil { + return err + } + + log.Printf("[DEBUG] Finished deleting Instance %q: %#v", d.Id(), res) + return nil +} + +func resourceSecureSourceManagerInstanceImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*transport_tpg.Config) + if err := tpgresource.ParseImportId([]string{ + "^projects/(?P[^/]+)/locations/(?P[^/]+)/instances/(?P[^/]+)$", + "^(?P[^/]+)/(?P[^/]+)/(?P[^/]+)$", + "^(?P[^/]+)/(?P[^/]+)$", + "^(?P[^/]+)$", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/locations/{{location}}/instances/{{instance_id}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenSecureSourceManagerInstanceName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenSecureSourceManagerInstanceCreateTime(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenSecureSourceManagerInstanceUpdateTime(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenSecureSourceManagerInstanceLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + + transformed := make(map[string]interface{}) + if l, ok := d.GetOkExists("labels"); ok { + for k := range l.(map[string]interface{}) { + transformed[k] = v.(map[string]interface{})[k] + } + } + + return transformed +} + +func flattenSecureSourceManagerInstanceState(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenSecureSourceManagerInstanceTerraformLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + + transformed := make(map[string]interface{}) + if l, ok := d.GetOkExists("terraform_labels"); ok { + for k := range l.(map[string]interface{}) { + transformed[k] = v.(map[string]interface{})[k] + } + } + + return transformed +} + +func flattenSecureSourceManagerInstanceEffectiveLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func expandSecureSourceManagerInstanceEffectiveLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) { + if v == nil { + return map[string]string{}, nil + } + m := make(map[string]string) + for k, val := range v.(map[string]interface{}) { + m[k] = val.(string) + } + return m, nil +} diff --git a/google/services/securesourcemanager/resource_secure_source_manager_instance_generated_test.go b/google/services/securesourcemanager/resource_secure_source_manager_instance_generated_test.go new file mode 100644 index 00000000000..cdd94e38000 --- /dev/null +++ b/google/services/securesourcemanager/resource_secure_source_manager_instance_generated_test.go @@ -0,0 +1,107 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package securesourcemanager_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func TestAccSecureSourceManagerInstance_secureSourceManagerInstanceBasicExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckSecureSourceManagerInstanceDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccSecureSourceManagerInstance_secureSourceManagerInstanceBasicExample(context), + }, + { + ResourceName: "google_secure_source_manager_instance.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"location", "instance_id", "labels", "terraform_labels"}, + }, + }, + }) +} + +func testAccSecureSourceManagerInstance_secureSourceManagerInstanceBasicExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_secure_source_manager_instance" "default" { + location = "us-central1" + instance_id = "tf-test-my-instance%{random_suffix}" + labels = { + "foo" = "bar" + } +} +`, context) +} + +func testAccCheckSecureSourceManagerInstanceDestroyProducer(t *testing.T) func(s *terraform.State) error { + return func(s *terraform.State) error { + for name, rs := range s.RootModule().Resources { + if rs.Type != "google_secure_source_manager_instance" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := acctest.GoogleProviderConfig(t) + + url, err := tpgresource.ReplaceVarsForTest(config, rs, "{{SecureSourceManagerBasePath}}projects/{{project}}/locations/{{location}}/instances/{{instance_id}}") + if err != nil { + return err + } + + billingProject := "" + + if config.BillingProject != "" { + billingProject = config.BillingProject + } + + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: config.UserAgent, + }) + if err == nil { + return fmt.Errorf("SecureSourceManagerInstance still exists at %s", url) + } + } + + return nil + } +} diff --git a/google/services/securesourcemanager/resource_secure_source_manager_instance_sweeper.go b/google/services/securesourcemanager/resource_secure_source_manager_instance_sweeper.go new file mode 100644 index 00000000000..ff6add35b63 --- /dev/null +++ b/google/services/securesourcemanager/resource_secure_source_manager_instance_sweeper.go @@ -0,0 +1,143 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package securesourcemanager + +import ( + "context" + "log" + "strings" + "testing" + + "github.com/hashicorp/terraform-provider-google/google/envvar" + "github.com/hashicorp/terraform-provider-google/google/sweeper" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func init() { + sweeper.AddTestSweepers("SecureSourceManagerInstance", testSweepSecureSourceManagerInstance) +} + +// At the time of writing, the CI only passes us-central1 as the region +func testSweepSecureSourceManagerInstance(region string) error { + resourceName := "SecureSourceManagerInstance" + log.Printf("[INFO][SWEEPER_LOG] Starting sweeper for %s", resourceName) + + config, err := sweeper.SharedConfigForRegion(region) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error getting shared config for region: %s", err) + return err + } + + err = config.LoadAndValidate(context.Background()) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error loading: %s", err) + return err + } + + t := &testing.T{} + billingId := envvar.GetTestBillingAccountFromEnv(t) + + // Setup variables to replace in list template + d := &tpgresource.ResourceDataMock{ + FieldsInSchema: map[string]interface{}{ + "project": config.Project, + "region": region, + "location": region, + "zone": "-", + "billing_account": billingId, + }, + } + + listTemplate := strings.Split("https://securesourcemanager.googleapis.com/v1/projects/{{project}}/locations/{{location}}/instances?instance_id={{instance_id}}", "?")[0] + listUrl, err := tpgresource.ReplaceVars(d, config, listTemplate) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error preparing sweeper list url: %s", err) + return nil + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: config.Project, + RawURL: listUrl, + UserAgent: config.UserAgent, + }) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error in response from request %s: %s", listUrl, err) + return nil + } + + resourceList, ok := res["instances"] + if !ok { + log.Printf("[INFO][SWEEPER_LOG] Nothing found in response.") + return nil + } + + rl := resourceList.([]interface{}) + + log.Printf("[INFO][SWEEPER_LOG] Found %d items in %s list response.", len(rl), resourceName) + // Keep count of items that aren't sweepable for logging. + nonPrefixCount := 0 + for _, ri := range rl { + obj := ri.(map[string]interface{}) + var name string + // Id detected in the delete URL, attempt to use id. + if obj["id"] != nil { + name = tpgresource.GetResourceNameFromSelfLink(obj["id"].(string)) + } else if obj["name"] != nil { + name = tpgresource.GetResourceNameFromSelfLink(obj["name"].(string)) + } else { + log.Printf("[INFO][SWEEPER_LOG] %s resource name and id were nil", resourceName) + return nil + } + // Skip resources that shouldn't be sweeped + if !sweeper.IsSweepableTestResource(name) { + nonPrefixCount++ + continue + } + + deleteTemplate := "https://securesourcemanager.googleapis.com/v1/projects/{{project}}/locations/{{location}}/instances/{{instance_id}}" + deleteUrl, err := tpgresource.ReplaceVars(d, config, deleteTemplate) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error preparing delete url: %s", err) + return nil + } + deleteUrl = deleteUrl + name + + // Don't wait on operations as we may have a lot to delete + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "DELETE", + Project: config.Project, + RawURL: deleteUrl, + UserAgent: config.UserAgent, + }) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error deleting for url %s : %s", deleteUrl, err) + } else { + log.Printf("[INFO][SWEEPER_LOG] Sent delete request for %s resource: %s", resourceName, name) + } + } + + if nonPrefixCount > 0 { + log.Printf("[INFO][SWEEPER_LOG] %d items were non-sweepable and skipped.", nonPrefixCount) + } + + return nil +} diff --git a/google/services/securesourcemanager/secure_source_manager_operation.go b/google/services/securesourcemanager/secure_source_manager_operation.go new file mode 100644 index 00000000000..dece8637010 --- /dev/null +++ b/google/services/securesourcemanager/secure_source_manager_operation.go @@ -0,0 +1,92 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package securesourcemanager + +import ( + "encoding/json" + "errors" + "fmt" + "time" + + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +type SecureSourceManagerOperationWaiter struct { + Config *transport_tpg.Config + UserAgent string + Project string + tpgresource.CommonOperationWaiter +} + +func (w *SecureSourceManagerOperationWaiter) QueryOp() (interface{}, error) { + if w == nil { + return nil, fmt.Errorf("Cannot query operation, it's unset or nil.") + } + // Returns the proper get. + url := fmt.Sprintf("%s%s", w.Config.SecureSourceManagerBasePath, w.CommonOperationWaiter.Op.Name) + + return transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: w.Config, + Method: "GET", + Project: w.Project, + RawURL: url, + UserAgent: w.UserAgent, + }) +} + +func createSecureSourceManagerWaiter(config *transport_tpg.Config, op map[string]interface{}, project, activity, userAgent string) (*SecureSourceManagerOperationWaiter, error) { + w := &SecureSourceManagerOperationWaiter{ + Config: config, + UserAgent: userAgent, + Project: project, + } + if err := w.CommonOperationWaiter.SetOp(op); err != nil { + return nil, err + } + return w, nil +} + +// nolint: deadcode,unused +func SecureSourceManagerOperationWaitTimeWithResponse(config *transport_tpg.Config, op map[string]interface{}, response *map[string]interface{}, project, activity, userAgent string, timeout time.Duration) error { + w, err := createSecureSourceManagerWaiter(config, op, project, activity, userAgent) + if err != nil { + return err + } + if err := tpgresource.OperationWait(w, activity, timeout, config.PollInterval); err != nil { + return err + } + rawResponse := []byte(w.CommonOperationWaiter.Op.Response) + if len(rawResponse) == 0 { + return errors.New("`resource` not set in operation response") + } + return json.Unmarshal(rawResponse, response) +} + +func SecureSourceManagerOperationWaitTime(config *transport_tpg.Config, op map[string]interface{}, project, activity, userAgent string, timeout time.Duration) error { + if val, ok := op["name"]; !ok || val == "" { + // This was a synchronous call - there is no operation to wait for. + return nil + } + w, err := createSecureSourceManagerWaiter(config, op, project, activity, userAgent) + if err != nil { + // If w is nil, the op was synchronous. + return err + } + return tpgresource.OperationWait(w, activity, timeout, config.PollInterval) +} diff --git a/google/sweeper/gcp_sweeper_test.go b/google/sweeper/gcp_sweeper_test.go index d1b19cd5e4d..aab180dba48 100644 --- a/google/sweeper/gcp_sweeper_test.go +++ b/google/sweeper/gcp_sweeper_test.go @@ -96,6 +96,7 @@ import ( _ "github.com/hashicorp/terraform-provider-google/google/services/redis" _ "github.com/hashicorp/terraform-provider-google/google/services/resourcemanager" _ "github.com/hashicorp/terraform-provider-google/google/services/secretmanager" + _ "github.com/hashicorp/terraform-provider-google/google/services/securesourcemanager" _ "github.com/hashicorp/terraform-provider-google/google/services/securitycenter" _ "github.com/hashicorp/terraform-provider-google/google/services/servicemanagement" _ "github.com/hashicorp/terraform-provider-google/google/services/serviceusage" diff --git a/google/transport/config.go b/google/transport/config.go index 319edddfbea..21311c0b813 100644 --- a/google/transport/config.go +++ b/google/transport/config.go @@ -274,6 +274,7 @@ type Config struct { RedisBasePath string ResourceManagerBasePath string SecretManagerBasePath string + SecureSourceManagerBasePath string SecurityCenterBasePath string ServiceManagementBasePath string ServiceUsageBasePath string @@ -399,6 +400,7 @@ const PubsubLiteBasePathKey = "PubsubLite" const RedisBasePathKey = "Redis" const ResourceManagerBasePathKey = "ResourceManager" const SecretManagerBasePathKey = "SecretManager" +const SecureSourceManagerBasePathKey = "SecureSourceManager" const SecurityCenterBasePathKey = "SecurityCenter" const ServiceManagementBasePathKey = "ServiceManagement" const ServiceUsageBasePathKey = "ServiceUsage" @@ -518,6 +520,7 @@ var DefaultBasePaths = map[string]string{ RedisBasePathKey: "https://redis.googleapis.com/v1/", ResourceManagerBasePathKey: "https://cloudresourcemanager.googleapis.com/v1/", SecretManagerBasePathKey: "https://secretmanager.googleapis.com/v1/", + SecureSourceManagerBasePathKey: "https://securesourcemanager.googleapis.com/v1/", SecurityCenterBasePathKey: "https://securitycenter.googleapis.com/v1/", ServiceManagementBasePathKey: "https://servicemanagement.googleapis.com/v1/", ServiceUsageBasePathKey: "https://serviceusage.googleapis.com/v1/", @@ -1059,6 +1062,11 @@ func SetEndpointDefaults(d *schema.ResourceData) error { "GOOGLE_SECRET_MANAGER_CUSTOM_ENDPOINT", }, DefaultBasePaths[SecretManagerBasePathKey])) } + if d.Get("secure_source_manager_custom_endpoint") == "" { + d.Set("secure_source_manager_custom_endpoint", MultiEnvDefault([]string{ + "GOOGLE_SECURE_SOURCE_MANAGER_CUSTOM_ENDPOINT", + }, DefaultBasePaths[SecureSourceManagerBasePathKey])) + } if d.Get("security_center_custom_endpoint") == "" { d.Set("security_center_custom_endpoint", MultiEnvDefault([]string{ "GOOGLE_SECURITY_CENTER_CUSTOM_ENDPOINT", @@ -2083,6 +2091,7 @@ func ConfigureBasePaths(c *Config) { c.RedisBasePath = DefaultBasePaths[RedisBasePathKey] c.ResourceManagerBasePath = DefaultBasePaths[ResourceManagerBasePathKey] c.SecretManagerBasePath = DefaultBasePaths[SecretManagerBasePathKey] + c.SecureSourceManagerBasePath = DefaultBasePaths[SecureSourceManagerBasePathKey] c.SecurityCenterBasePath = DefaultBasePaths[SecurityCenterBasePathKey] c.ServiceManagementBasePath = DefaultBasePaths[ServiceManagementBasePathKey] c.ServiceUsageBasePath = DefaultBasePaths[ServiceUsageBasePathKey] diff --git a/website/docs/d/secure_source_manager_instance_iam_policy.html.markdown b/website/docs/d/secure_source_manager_instance_iam_policy.html.markdown new file mode 100644 index 00000000000..6178365dbf9 --- /dev/null +++ b/website/docs/d/secure_source_manager_instance_iam_policy.html.markdown @@ -0,0 +1,55 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: MMv1 *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- +subcategory: "Secure Source Manager" +description: |- + A datasource to retrieve the IAM policy state for Secure Source Manager Instance +--- + + +# `google_secure_source_manager_instance_iam_policy` +Retrieves the current IAM policy data for instance + + + +## example + +```hcl +data "google_secure_source_manager_instance_iam_policy" "policy" { + project = google_secure_source_manager_instance.default.project + location = google_secure_source_manager_instance.default.location + instance_id = google_secure_source_manager_instance.default.instance_id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `location` - (Required) The location for the Instance. + Used to find the parent resource to bind the IAM policy to +* `instance_id` - (Required) The name for the Instance. + Used to find the parent resource to bind the IAM policy to + +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the project will be parsed from the identifier of the parent resource. If no project is provided in the parent identifier and no project is specified, the provider project is used. + +## Attributes Reference + +The attributes are exported: + +* `etag` - (Computed) The etag of the IAM policy. + +* `policy_data` - (Required only by `google_secure_source_manager_instance_iam_policy`) The policy data generated by + a `google_iam_policy` data source. diff --git a/website/docs/r/secure_source_manager_instance.html.markdown b/website/docs/r/secure_source_manager_instance.html.markdown new file mode 100644 index 00000000000..a5107ea1595 --- /dev/null +++ b/website/docs/r/secure_source_manager_instance.html.markdown @@ -0,0 +1,141 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: MMv1 *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- +subcategory: "Secure Source Manager" +description: |- + Instances are deployed to an available Google Cloud region and are accessible via their web interface. +--- + +# google\_secure\_source\_manager\_instance + +Instances are deployed to an available Google Cloud region and are accessible via their web interface. + + +To get more information about Instance, see: + +* How-to Guides + * [Official Documentation](https://cloud.google.com/secure-source-manager/overview/overview) + + +## Example Usage - Secure Source Manager Instance Basic + + +```hcl +resource "google_secure_source_manager_instance" "default" { + location = "us-central1" + instance_id = "my-instance" + labels = { + "foo" = "bar" + } +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `location` - + (Required) + The location for the Instance. + +* `instance_id` - + (Required) + The name for the Instance. + + +- - - + + +* `labels` - + (Optional) + Labels as key value pairs. + + **Note**: This field is non-authoritative, and will only manage the labels present in your configuration. + Please refer to the field `effective_labels` for all of the labels present on the resource. + +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. + + +## Attributes Reference + +In addition to the arguments listed above, the following computed attributes are exported: + +* `id` - an identifier for the resource with format `projects/{{project}}/locations/{{location}}/instances/{{instance_id}}` + +* `name` - + The resource name for the Instance. + +* `create_time` - + Time the Instance was created in UTC. + +* `update_time` - + Time the Instance was updated in UTC. + +* `state` - + The current state of the Instance. + +* `terraform_labels` - + The combination of labels configured directly on the resource + and default labels configured on the provider. + +* `effective_labels` - + All of labels (key/value pairs) present on the resource in GCP, including the labels configured through Terraform, other clients and services. + + +## Timeouts + +This resource provides the following +[Timeouts](https://developer.hashicorp.com/terraform/plugin/sdkv2/resources/retries-and-customizable-timeouts) configuration options: + +- `create` - Default is 60 minutes. +- `delete` - Default is 60 minutes. + +## Import + + +Instance can be imported using any of these accepted formats: + +* `projects/{{project}}/locations/{{location}}/instances/{{instance_id}}` +* `{{project}}/{{location}}/{{instance_id}}` +* `{{location}}/{{instance_id}}` +* `{{instance_id}}` + + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import Instance using one of the formats above. For example: + +```tf +import { + id = "projects/{{project}}/locations/{{location}}/instances/{{instance_id}}" + to = google_secure_source_manager_instance.default +} +``` + +When using the [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import), Instance can be imported using one of the formats above. For example: + +``` +$ terraform import google_secure_source_manager_instance.default projects/{{project}}/locations/{{location}}/instances/{{instance_id}} +$ terraform import google_secure_source_manager_instance.default {{project}}/{{location}}/{{instance_id}} +$ terraform import google_secure_source_manager_instance.default {{location}}/{{instance_id}} +$ terraform import google_secure_source_manager_instance.default {{instance_id}} +``` + +## User Project Overrides + +This resource supports [User Project Overrides](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference#user_project_override). diff --git a/website/docs/r/secure_source_manager_instance_iam.html.markdown b/website/docs/r/secure_source_manager_instance_iam.html.markdown new file mode 100644 index 00000000000..9b250520d8a --- /dev/null +++ b/website/docs/r/secure_source_manager_instance_iam.html.markdown @@ -0,0 +1,156 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: MMv1 *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- +subcategory: "Secure Source Manager" +description: |- + Collection of resources to manage IAM policy for Secure Source Manager Instance +--- + +# IAM policy for Secure Source Manager Instance +Three different resources help you manage your IAM policy for Secure Source Manager Instance. Each of these resources serves a different use case: + +* `google_secure_source_manager_instance_iam_policy`: Authoritative. Sets the IAM policy for the instance and replaces any existing policy already attached. +* `google_secure_source_manager_instance_iam_binding`: Authoritative for a given role. Updates the IAM policy to grant a role to a list of members. Other roles within the IAM policy for the instance are preserved. +* `google_secure_source_manager_instance_iam_member`: Non-authoritative. Updates the IAM policy to grant a role to a new member. Other members for the role for the instance are preserved. + +A data source can be used to retrieve policy data in advent you do not need creation + +* `google_secure_source_manager_instance_iam_policy`: Retrieves the IAM policy for the instance + +~> **Note:** `google_secure_source_manager_instance_iam_policy` **cannot** be used in conjunction with `google_secure_source_manager_instance_iam_binding` and `google_secure_source_manager_instance_iam_member` or they will fight over what your policy should be. + +~> **Note:** `google_secure_source_manager_instance_iam_binding` resources **can be** used in conjunction with `google_secure_source_manager_instance_iam_member` resources **only if** they do not grant privilege to the same role. + + + + +## google\_secure\_source\_manager\_instance\_iam\_policy + +```hcl +data "google_iam_policy" "admin" { + binding { + role = "roles/securesourcemanager.instanceOwner" + members = [ + "user:jane@example.com", + ] + } +} + +resource "google_secure_source_manager_instance_iam_policy" "policy" { + project = google_secure_source_manager_instance.default.project + location = google_secure_source_manager_instance.default.location + instance_id = google_secure_source_manager_instance.default.instance_id + policy_data = data.google_iam_policy.admin.policy_data +} +``` + +## google\_secure\_source\_manager\_instance\_iam\_binding + +```hcl +resource "google_secure_source_manager_instance_iam_binding" "binding" { + project = google_secure_source_manager_instance.default.project + location = google_secure_source_manager_instance.default.location + instance_id = google_secure_source_manager_instance.default.instance_id + role = "roles/securesourcemanager.instanceOwner" + members = [ + "user:jane@example.com", + ] +} +``` + +## google\_secure\_source\_manager\_instance\_iam\_member + +```hcl +resource "google_secure_source_manager_instance_iam_member" "member" { + project = google_secure_source_manager_instance.default.project + location = google_secure_source_manager_instance.default.location + instance_id = google_secure_source_manager_instance.default.instance_id + role = "roles/securesourcemanager.instanceOwner" + member = "user:jane@example.com" +} +``` + + +## Argument Reference + +The following arguments are supported: + +* `location` - (Required) The location for the Instance. + Used to find the parent resource to bind the IAM policy to +* `instance_id` - (Required) The name for the Instance. + Used to find the parent resource to bind the IAM policy to + +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the project will be parsed from the identifier of the parent resource. If no project is provided in the parent identifier and no project is specified, the provider project is used. + +* `member/members` - (Required) Identities that will be granted the privilege in `role`. + Each entry can have one of the following values: + * **allUsers**: A special identifier that represents anyone who is on the internet; with or without a Google account. + * **allAuthenticatedUsers**: A special identifier that represents anyone who is authenticated with a Google account or a service account. + * **user:{emailid}**: An email address that represents a specific Google account. For example, alice@gmail.com or joe@example.com. + * **serviceAccount:{emailid}**: An email address that represents a service account. For example, my-other-app@appspot.gserviceaccount.com. + * **group:{emailid}**: An email address that represents a Google group. For example, admins@example.com. + * **domain:{domain}**: A G Suite domain (primary, instead of alias) name that represents all the users of that domain. For example, google.com or example.com. + * **projectOwner:projectid**: Owners of the given project. For example, "projectOwner:my-example-project" + * **projectEditor:projectid**: Editors of the given project. For example, "projectEditor:my-example-project" + * **projectViewer:projectid**: Viewers of the given project. For example, "projectViewer:my-example-project" + +* `role` - (Required) The role that should be applied. Only one + `google_secure_source_manager_instance_iam_binding` can be used per role. Note that custom roles must be of the format + `[projects|organizations]/{parent-name}/roles/{role-name}`. + +* `policy_data` - (Required only by `google_secure_source_manager_instance_iam_policy`) The policy data generated by + a `google_iam_policy` data source. + +## Attributes Reference + +In addition to the arguments listed above, the following computed attributes are +exported: + +* `etag` - (Computed) The etag of the IAM policy. + +## Import + +For all import syntaxes, the "resource in question" can take any of the following forms: + +* projects/{{project}}/locations/{{location}}/instances/{{instance_id}} +* {{project}}/{{location}}/{{instance_id}} +* {{location}}/{{instance_id}} +* {{instance_id}} + +Any variables not passed in the import command will be taken from the provider configuration. + +Secure Source Manager instance IAM resources can be imported using the resource identifiers, role, and member. + +IAM member imports use space-delimited identifiers: the resource in question, the role, and the member identity, e.g. +``` +$ terraform import google_secure_source_manager_instance_iam_member.editor "projects/{{project}}/locations/{{location}}/instances/{{instance_id}} roles/securesourcemanager.instanceManager user:jane@example.com" +``` + +IAM binding imports use space-delimited identifiers: the resource in question and the role, e.g. +``` +$ terraform import google_secure_source_manager_instance_iam_binding.editor "projects/{{project}}/locations/{{location}}/instances/{{instance_id}} roles/securesourcemanager.instanceManager" +``` + +IAM policy imports use the identifier of the resource in question, e.g. +``` +$ terraform import google_secure_source_manager_instance_iam_policy.editor projects/{{project}}/locations/{{location}}/instances/{{instance_id}} +``` + +-> **Custom Roles**: If you're importing a IAM resource with a custom role, make sure to use the + full name of the custom role, e.g. `[projects/my-project|organizations/my-org]/roles/my-custom-role`. + +## User Project Overrides + +This resource supports [User Project Overrides](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference#user_project_override).