diff --git a/.changelog/10840.txt b/.changelog/10840.txt new file mode 100644 index 00000000000..434876be4f1 --- /dev/null +++ b/.changelog/10840.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +`google_secure_source_manager_repository` +``` \ No newline at end of file diff --git a/google/provider/provider_mmv1_resources.go b/google/provider/provider_mmv1_resources.go index 361d3af3ef5..e18d1ef4151 100644 --- a/google/provider/provider_mmv1_resources.go +++ b/google/provider/provider_mmv1_resources.go @@ -378,6 +378,7 @@ var generatedIAMDatasources = map[string]*schema.Resource{ "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_secure_source_manager_repository_iam_policy": tpgiamresource.DataSourceIamPolicy(securesourcemanager.SecureSourceManagerRepositoryIamSchema, securesourcemanager.SecureSourceManagerRepositoryIamUpdaterProducer), "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), @@ -415,9 +416,9 @@ var handwrittenIAMDatasources = map[string]*schema.Resource{ } // Resources -// Generated resources: 428 -// Generated IAM resources: 249 -// Total generated resources: 677 +// Generated resources: 429 +// Generated IAM resources: 252 +// Total generated resources: 681 var generatedResources = map[string]*schema.Resource{ "google_folder_access_approval_settings": accessapproval.ResourceAccessApprovalFolderSettings(), "google_organization_access_approval_settings": accessapproval.ResourceAccessApprovalOrganizationSettings(), @@ -996,6 +997,10 @@ var generatedResources = map[string]*schema.Resource{ "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_secure_source_manager_repository": securesourcemanager.ResourceSecureSourceManagerRepository(), + "google_secure_source_manager_repository_iam_binding": tpgiamresource.ResourceIamBinding(securesourcemanager.SecureSourceManagerRepositoryIamSchema, securesourcemanager.SecureSourceManagerRepositoryIamUpdaterProducer, securesourcemanager.SecureSourceManagerRepositoryIdParseFunc), + "google_secure_source_manager_repository_iam_member": tpgiamresource.ResourceIamMember(securesourcemanager.SecureSourceManagerRepositoryIamSchema, securesourcemanager.SecureSourceManagerRepositoryIamUpdaterProducer, securesourcemanager.SecureSourceManagerRepositoryIdParseFunc), + "google_secure_source_manager_repository_iam_policy": tpgiamresource.ResourceIamPolicy(securesourcemanager.SecureSourceManagerRepositoryIamSchema, securesourcemanager.SecureSourceManagerRepositoryIamUpdaterProducer, securesourcemanager.SecureSourceManagerRepositoryIdParseFunc), "google_scc_event_threat_detection_custom_module": securitycenter.ResourceSecurityCenterEventThreatDetectionCustomModule(), "google_scc_folder_custom_module": securitycenter.ResourceSecurityCenterFolderCustomModule(), "google_scc_mute_config": securitycenter.ResourceSecurityCenterMuteConfig(), diff --git a/google/services/securesourcemanager/iam_secure_source_manager_repository.go b/google/services/securesourcemanager/iam_secure_source_manager_repository.go new file mode 100644 index 00000000000..a32203fdc1f --- /dev/null +++ b/google/services/securesourcemanager/iam_secure_source_manager_repository.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 SecureSourceManagerRepositoryIamSchema = map[string]*schema.Schema{ + "project": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + }, + "location": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + }, + "repository_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: tpgresource.CompareSelfLinkOrResourceName, + }, +} + +type SecureSourceManagerRepositoryIamUpdater struct { + project string + location string + repositoryId string + d tpgresource.TerraformResourceData + Config *transport_tpg.Config +} + +func SecureSourceManagerRepositoryIamUpdaterProducer(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("repository_id"); ok { + values["repository_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[^/]+)/repositories/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config, d.Get("repository_id").(string)) + if err != nil { + return nil, err + } + + for k, v := range m { + values[k] = v + } + + u := &SecureSourceManagerRepositoryIamUpdater{ + project: values["project"], + location: values["location"], + repositoryId: values["repository_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("repository_id", u.GetResourceId()); err != nil { + return nil, fmt.Errorf("Error setting repository_id: %s", err) + } + + return u, nil +} + +func SecureSourceManagerRepositoryIdParseFunc(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[^/]+)/repositories/(?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 := &SecureSourceManagerRepositoryIamUpdater{ + project: values["project"], + location: values["location"], + repositoryId: values["repository_id"], + d: d, + Config: config, + } + if err := d.Set("repository_id", u.GetResourceId()); err != nil { + return fmt.Errorf("Error setting repository_id: %s", err) + } + d.SetId(u.GetResourceId()) + return nil +} + +func (u *SecureSourceManagerRepositoryIamUpdater) GetResourceIamPolicy() (*cloudresourcemanager.Policy, error) { + url, err := u.qualifyRepositoryUrl("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 *SecureSourceManagerRepositoryIamUpdater) 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.qualifyRepositoryUrl("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 *SecureSourceManagerRepositoryIamUpdater) qualifyRepositoryUrl(methodIdentifier string) (string, error) { + urlTemplate := fmt.Sprintf("{{SecureSourceManagerBasePath}}%s:%s", fmt.Sprintf("projects/%s/locations/%s/repositories/%s", u.project, u.location, u.repositoryId), methodIdentifier) + url, err := tpgresource.ReplaceVars(u.d, u.Config, urlTemplate) + if err != nil { + return "", err + } + return url, nil +} + +func (u *SecureSourceManagerRepositoryIamUpdater) GetResourceId() string { + return fmt.Sprintf("projects/%s/locations/%s/repositories/%s", u.project, u.location, u.repositoryId) +} + +func (u *SecureSourceManagerRepositoryIamUpdater) GetMutexKey() string { + return fmt.Sprintf("iam-securesourcemanager-repository-%s", u.GetResourceId()) +} + +func (u *SecureSourceManagerRepositoryIamUpdater) DescribeResource() string { + return fmt.Sprintf("securesourcemanager repository %q", u.GetResourceId()) +} diff --git a/google/services/securesourcemanager/iam_secure_source_manager_repository_generated_test.go b/google/services/securesourcemanager/iam_secure_source_manager_repository_generated_test.go new file mode 100644 index 00000000000..212a1918e98 --- /dev/null +++ b/google/services/securesourcemanager/iam_secure_source_manager_repository_generated_test.go @@ -0,0 +1,256 @@ +// 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 TestAccSecureSourceManagerRepositoryIamBindingGenerated(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "role": "roles/securesourcemanager.repoAdmin", + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccSecureSourceManagerRepositoryIamBinding_basicGenerated(context), + }, + { + ResourceName: "google_secure_source_manager_repository_iam_binding.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/repositories/%s roles/securesourcemanager.repoAdmin", envvar.GetTestProjectFromEnv(), envvar.GetTestRegionFromEnv(), fmt.Sprintf("tf-test-my-repository%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + { + // Test Iam Binding update + Config: testAccSecureSourceManagerRepositoryIamBinding_updateGenerated(context), + }, + { + ResourceName: "google_secure_source_manager_repository_iam_binding.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/repositories/%s roles/securesourcemanager.repoAdmin", envvar.GetTestProjectFromEnv(), envvar.GetTestRegionFromEnv(), fmt.Sprintf("tf-test-my-repository%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccSecureSourceManagerRepositoryIamMemberGenerated(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "role": "roles/securesourcemanager.repoAdmin", + } + + 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: testAccSecureSourceManagerRepositoryIamMember_basicGenerated(context), + }, + { + ResourceName: "google_secure_source_manager_repository_iam_member.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/repositories/%s roles/securesourcemanager.repoAdmin user:admin@hashicorptest.com", envvar.GetTestProjectFromEnv(), envvar.GetTestRegionFromEnv(), fmt.Sprintf("tf-test-my-repository%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccSecureSourceManagerRepositoryIamPolicyGenerated(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "role": "roles/securesourcemanager.repoAdmin", + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccSecureSourceManagerRepositoryIamPolicy_basicGenerated(context), + Check: resource.TestCheckResourceAttrSet("data.google_secure_source_manager_repository_iam_policy.foo", "policy_data"), + }, + { + ResourceName: "google_secure_source_manager_repository_iam_policy.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/repositories/%s", envvar.GetTestProjectFromEnv(), envvar.GetTestRegionFromEnv(), fmt.Sprintf("tf-test-my-repository%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccSecureSourceManagerRepositoryIamPolicy_emptyBinding(context), + }, + { + ResourceName: "google_secure_source_manager_repository_iam_policy.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/repositories/%s", envvar.GetTestProjectFromEnv(), envvar.GetTestRegionFromEnv(), fmt.Sprintf("tf-test-my-repository%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccSecureSourceManagerRepositoryIamMember_basicGenerated(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_secure_source_manager_instance" "instance" { + location = "us-central1" + instance_id = "tf-test-my-instance%{random_suffix}" +} + +resource "google_secure_source_manager_repository" "default" { + location = "us-central1" + repository_id = "tf-test-my-repository%{random_suffix}" + instance = google_secure_source_manager_instance.instance.name +} + +resource "google_secure_source_manager_repository_iam_member" "foo" { + project = google_secure_source_manager_repository.default.project + location = google_secure_source_manager_repository.default.location + repository_id = google_secure_source_manager_repository.default.repository_id + role = "%{role}" + member = "user:admin@hashicorptest.com" +} +`, context) +} + +func testAccSecureSourceManagerRepositoryIamPolicy_basicGenerated(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_secure_source_manager_instance" "instance" { + location = "us-central1" + instance_id = "tf-test-my-instance%{random_suffix}" +} + +resource "google_secure_source_manager_repository" "default" { + location = "us-central1" + repository_id = "tf-test-my-repository%{random_suffix}" + instance = google_secure_source_manager_instance.instance.name +} + +data "google_iam_policy" "foo" { + binding { + role = "%{role}" + members = ["user:admin@hashicorptest.com"] + } +} + +resource "google_secure_source_manager_repository_iam_policy" "foo" { + project = google_secure_source_manager_repository.default.project + location = google_secure_source_manager_repository.default.location + repository_id = google_secure_source_manager_repository.default.repository_id + policy_data = data.google_iam_policy.foo.policy_data +} + +data "google_secure_source_manager_repository_iam_policy" "foo" { + project = google_secure_source_manager_repository.default.project + location = google_secure_source_manager_repository.default.location + repository_id = google_secure_source_manager_repository.default.repository_id + depends_on = [ + google_secure_source_manager_repository_iam_policy.foo + ] +} +`, context) +} + +func testAccSecureSourceManagerRepositoryIamPolicy_emptyBinding(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_secure_source_manager_instance" "instance" { + location = "us-central1" + instance_id = "tf-test-my-instance%{random_suffix}" +} + +resource "google_secure_source_manager_repository" "default" { + location = "us-central1" + repository_id = "tf-test-my-repository%{random_suffix}" + instance = google_secure_source_manager_instance.instance.name +} + +data "google_iam_policy" "foo" { +} + +resource "google_secure_source_manager_repository_iam_policy" "foo" { + project = google_secure_source_manager_repository.default.project + location = google_secure_source_manager_repository.default.location + repository_id = google_secure_source_manager_repository.default.repository_id + policy_data = data.google_iam_policy.foo.policy_data +} +`, context) +} + +func testAccSecureSourceManagerRepositoryIamBinding_basicGenerated(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_secure_source_manager_instance" "instance" { + location = "us-central1" + instance_id = "tf-test-my-instance%{random_suffix}" +} + +resource "google_secure_source_manager_repository" "default" { + location = "us-central1" + repository_id = "tf-test-my-repository%{random_suffix}" + instance = google_secure_source_manager_instance.instance.name +} + +resource "google_secure_source_manager_repository_iam_binding" "foo" { + project = google_secure_source_manager_repository.default.project + location = google_secure_source_manager_repository.default.location + repository_id = google_secure_source_manager_repository.default.repository_id + role = "%{role}" + members = ["user:admin@hashicorptest.com"] +} +`, context) +} + +func testAccSecureSourceManagerRepositoryIamBinding_updateGenerated(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_secure_source_manager_instance" "instance" { + location = "us-central1" + instance_id = "tf-test-my-instance%{random_suffix}" +} + +resource "google_secure_source_manager_repository" "default" { + location = "us-central1" + repository_id = "tf-test-my-repository%{random_suffix}" + instance = google_secure_source_manager_instance.instance.name +} + +resource "google_secure_source_manager_repository_iam_binding" "foo" { + project = google_secure_source_manager_repository.default.project + location = google_secure_source_manager_repository.default.location + repository_id = google_secure_source_manager_repository.default.repository_id + role = "%{role}" + members = ["user:admin@hashicorptest.com", "user:gterraformtest1@gmail.com"] +} +`, context) +} diff --git a/google/services/securesourcemanager/resource_secure_source_manager_repository.go b/google/services/securesourcemanager/resource_secure_source_manager_repository.go new file mode 100644 index 00000000000..670475829b3 --- /dev/null +++ b/google/services/securesourcemanager/resource_secure_source_manager_repository.go @@ -0,0 +1,517 @@ +// 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" + "net/http" + "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 ResourceSecureSourceManagerRepository() *schema.Resource { + return &schema.Resource{ + Create: resourceSecureSourceManagerRepositoryCreate, + Read: resourceSecureSourceManagerRepositoryRead, + Delete: resourceSecureSourceManagerRepositoryDelete, + + Importer: &schema.ResourceImporter{ + State: resourceSecureSourceManagerRepositoryImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(20 * time.Minute), + Delete: schema.DefaultTimeout(20 * time.Minute), + }, + + CustomizeDiff: customdiff.All( + tpgresource.DefaultProviderProject, + ), + + Schema: map[string]*schema.Schema{ + "instance": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: tpgresource.ProjectNumberDiffSuppress, + Description: `The name of the instance in which the repository is hosted.`, + }, + "location": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The location for the Repository.`, + }, + "repository_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The ID for the Repository.`, + }, + "description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `Description of the repository, which cannot exceed 500 characters.`, + }, + "initial_config": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Description: `Initial configurations for the repository.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "default_branch": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `Default branch name of the repository.`, + }, + "gitignores": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Description: `List of gitignore template names user can choose from. +Valid values can be viewed at https://cloud.google.com/secure-source-manager/docs/reference/rest/v1/projects.locations.repositories#initialconfig.`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "license": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `License template name user can choose from. +Valid values can be viewed at https://cloud.google.com/secure-source-manager/docs/reference/rest/v1/projects.locations.repositories#initialconfig.`, + }, + "readme": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `README template name. +Valid values can be viewed at https://cloud.google.com/secure-source-manager/docs/reference/rest/v1/projects.locations.repositories#initialconfig.`, + }, + }, + }, + }, + "create_time": { + Type: schema.TypeString, + Computed: true, + Description: `Time the repository was created in UTC.`, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: `The resource name for the Repository.`, + }, + "uid": { + Type: schema.TypeString, + Computed: true, + Description: `Unique identifier of the repository.`, + }, + "update_time": { + Type: schema.TypeString, + Computed: true, + Description: `Time the repository was updated in UTC.`, + }, + "uris": { + Type: schema.TypeList, + Computed: true, + Description: `URIs for the repository.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api": { + Type: schema.TypeString, + Computed: true, + Description: `API is the URI for API access.`, + }, + "git_https": { + Type: schema.TypeString, + Computed: true, + Description: `git_https is the git HTTPS URI for git operations.`, + }, + "html": { + Type: schema.TypeString, + Computed: true, + Description: `HTML is the URI for the user to view the repository in a browser.`, + }, + }, + }, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + UseJSONNumber: true, + } +} + +func resourceSecureSourceManagerRepositoryCreate(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{}) + descriptionProp, err := expandSecureSourceManagerRepositoryDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !tpgresource.IsEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + instanceProp, err := expandSecureSourceManagerRepositoryInstance(d.Get("instance"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("instance"); !tpgresource.IsEmptyValue(reflect.ValueOf(instanceProp)) && (ok || !reflect.DeepEqual(v, instanceProp)) { + obj["instance"] = instanceProp + } + initialConfigProp, err := expandSecureSourceManagerRepositoryInitialConfig(d.Get("initial_config"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("initial_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(initialConfigProp)) && (ok || !reflect.DeepEqual(v, initialConfigProp)) { + obj["initialConfig"] = initialConfigProp + } + + url, err := tpgresource.ReplaceVars(d, config, "{{SecureSourceManagerBasePath}}projects/{{project}}/locations/{{location}}/repositories?repository_id={{repository_id}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new Repository: %#v", obj) + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for Repository: %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 + } + + headers := make(http.Header) + 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), + Headers: headers, + }) + if err != nil { + return fmt.Errorf("Error creating Repository: %s", err) + } + + // Store the ID now + id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/locations/{{location}}/repositories/{{repository_id}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + err = SecureSourceManagerOperationWaitTime( + config, res, project, "Creating Repository", userAgent, + d.Timeout(schema.TimeoutCreate)) + + if err != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create Repository: %s", err) + } + + log.Printf("[DEBUG] Finished creating Repository %q: %#v", d.Id(), res) + + return resourceSecureSourceManagerRepositoryRead(d, meta) +} + +func resourceSecureSourceManagerRepositoryRead(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}}/repositories/{{repository_id}}") + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for Repository: %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 + } + + headers := make(http.Header) + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Headers: headers, + }) + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("SecureSourceManagerRepository %q", d.Id())) + } + + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading Repository: %s", err) + } + + if err := d.Set("name", flattenSecureSourceManagerRepositoryName(res["name"], d, config)); err != nil { + return fmt.Errorf("Error reading Repository: %s", err) + } + if err := d.Set("description", flattenSecureSourceManagerRepositoryDescription(res["description"], d, config)); err != nil { + return fmt.Errorf("Error reading Repository: %s", err) + } + if err := d.Set("instance", flattenSecureSourceManagerRepositoryInstance(res["instance"], d, config)); err != nil { + return fmt.Errorf("Error reading Repository: %s", err) + } + if err := d.Set("uid", flattenSecureSourceManagerRepositoryUid(res["uid"], d, config)); err != nil { + return fmt.Errorf("Error reading Repository: %s", err) + } + if err := d.Set("create_time", flattenSecureSourceManagerRepositoryCreateTime(res["createTime"], d, config)); err != nil { + return fmt.Errorf("Error reading Repository: %s", err) + } + if err := d.Set("update_time", flattenSecureSourceManagerRepositoryUpdateTime(res["updateTime"], d, config)); err != nil { + return fmt.Errorf("Error reading Repository: %s", err) + } + if err := d.Set("uris", flattenSecureSourceManagerRepositoryUris(res["uris"], d, config)); err != nil { + return fmt.Errorf("Error reading Repository: %s", err) + } + + return nil +} + +func resourceSecureSourceManagerRepositoryDelete(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 Repository: %s", err) + } + billingProject = project + + url, err := tpgresource.ReplaceVars(d, config, "{{SecureSourceManagerBasePath}}projects/{{project}}/locations/{{location}}/repositories/{{repository_id}}") + if err != nil { + return err + } + + var obj map[string]interface{} + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + headers := make(http.Header) + + log.Printf("[DEBUG] Deleting Repository %q", d.Id()) + 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), + Headers: headers, + }) + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, "Repository") + } + + err = SecureSourceManagerOperationWaitTime( + config, res, project, "Deleting Repository", userAgent, + d.Timeout(schema.TimeoutDelete)) + + if err != nil { + return err + } + + log.Printf("[DEBUG] Finished deleting Repository %q: %#v", d.Id(), res) + return nil +} + +func resourceSecureSourceManagerRepositoryImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*transport_tpg.Config) + if err := tpgresource.ParseImportId([]string{ + "^projects/(?P[^/]+)/locations/(?P[^/]+)/repositories/(?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}}/repositories/{{repository_id}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenSecureSourceManagerRepositoryName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenSecureSourceManagerRepositoryDescription(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenSecureSourceManagerRepositoryInstance(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenSecureSourceManagerRepositoryUid(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenSecureSourceManagerRepositoryCreateTime(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenSecureSourceManagerRepositoryUpdateTime(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenSecureSourceManagerRepositoryUris(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["html"] = + flattenSecureSourceManagerRepositoryUrisHtml(original["html"], d, config) + transformed["git_https"] = + flattenSecureSourceManagerRepositoryUrisGitHttps(original["gitHttps"], d, config) + transformed["api"] = + flattenSecureSourceManagerRepositoryUrisApi(original["api"], d, config) + return []interface{}{transformed} +} +func flattenSecureSourceManagerRepositoryUrisHtml(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenSecureSourceManagerRepositoryUrisGitHttps(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenSecureSourceManagerRepositoryUrisApi(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func expandSecureSourceManagerRepositoryDescription(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandSecureSourceManagerRepositoryInstance(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandSecureSourceManagerRepositoryInitialConfig(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedDefaultBranch, err := expandSecureSourceManagerRepositoryInitialConfigDefaultBranch(original["default_branch"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDefaultBranch); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["defaultBranch"] = transformedDefaultBranch + } + + transformedGitignores, err := expandSecureSourceManagerRepositoryInitialConfigGitignores(original["gitignores"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedGitignores); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["gitignores"] = transformedGitignores + } + + transformedLicense, err := expandSecureSourceManagerRepositoryInitialConfigLicense(original["license"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedLicense); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["license"] = transformedLicense + } + + transformedReadme, err := expandSecureSourceManagerRepositoryInitialConfigReadme(original["readme"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedReadme); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["readme"] = transformedReadme + } + + return transformed, nil +} + +func expandSecureSourceManagerRepositoryInitialConfigDefaultBranch(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandSecureSourceManagerRepositoryInitialConfigGitignores(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandSecureSourceManagerRepositoryInitialConfigLicense(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandSecureSourceManagerRepositoryInitialConfigReadme(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} diff --git a/google/services/securesourcemanager/resource_secure_source_manager_repository_generated_test.go b/google/services/securesourcemanager/resource_secure_source_manager_repository_generated_test.go new file mode 100644 index 00000000000..d476f8b27da --- /dev/null +++ b/google/services/securesourcemanager/resource_secure_source_manager_repository_generated_test.go @@ -0,0 +1,158 @@ +// 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 TestAccSecureSourceManagerRepository_secureSourceManagerRepositoryBasicExample(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: testAccCheckSecureSourceManagerRepositoryDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccSecureSourceManagerRepository_secureSourceManagerRepositoryBasicExample(context), + }, + { + ResourceName: "google_secure_source_manager_repository.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"initial_config", "location", "repository_id"}, + }, + }, + }) +} + +func testAccSecureSourceManagerRepository_secureSourceManagerRepositoryBasicExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_secure_source_manager_instance" "instance" { + location = "us-central1" + instance_id = "tf-test-my-instance%{random_suffix}" +} + +resource "google_secure_source_manager_repository" "default" { + location = "us-central1" + repository_id = "tf-test-my-repository%{random_suffix}" + instance = google_secure_source_manager_instance.instance.name +} +`, context) +} + +func TestAccSecureSourceManagerRepository_secureSourceManagerRepositoryInitialConfigExample(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: testAccCheckSecureSourceManagerRepositoryDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccSecureSourceManagerRepository_secureSourceManagerRepositoryInitialConfigExample(context), + }, + { + ResourceName: "google_secure_source_manager_repository.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"initial_config", "location", "repository_id"}, + }, + }, + }) +} + +func testAccSecureSourceManagerRepository_secureSourceManagerRepositoryInitialConfigExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_secure_source_manager_instance" "instance" { + location = "us-central1" + instance_id = "tf-test-my-instance%{random_suffix}" +} + +resource "google_secure_source_manager_repository" "default" { + location = "us-central1" + repository_id = "tf-test-my-repository%{random_suffix}" + instance = google_secure_source_manager_instance.instance.name + + description = "This is a test repository" + initial_config { + default_branch = "main" + gitignores = ["python"] + license = "mit" + readme = "default" + } +} +`, context) +} + +func testAccCheckSecureSourceManagerRepositoryDestroyProducer(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_repository" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := acctest.GoogleProviderConfig(t) + + url, err := tpgresource.ReplaceVarsForTest(config, rs, "{{SecureSourceManagerBasePath}}projects/{{project}}/locations/{{location}}/repositories/{{repository_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("SecureSourceManagerRepository still exists at %s", url) + } + } + + return nil + } +} diff --git a/google/services/securesourcemanager/resource_secure_source_manager_repository_sweeper.go b/google/services/securesourcemanager/resource_secure_source_manager_repository_sweeper.go new file mode 100644 index 00000000000..edae15d7742 --- /dev/null +++ b/google/services/securesourcemanager/resource_secure_source_manager_repository_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("SecureSourceManagerRepository", testSweepSecureSourceManagerRepository) +} + +// At the time of writing, the CI only passes us-central1 as the region +func testSweepSecureSourceManagerRepository(region string) error { + resourceName := "SecureSourceManagerRepository" + 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}}/repositories?repository_id={{repository_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["repositories"] + 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}}/repositories/{{repository_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/website/docs/d/secure_source_manager_repository_iam_policy.html.markdown b/website/docs/d/secure_source_manager_repository_iam_policy.html.markdown new file mode 100644 index 00000000000..9ac2e075583 --- /dev/null +++ b/website/docs/d/secure_source_manager_repository_iam_policy.html.markdown @@ -0,0 +1,56 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** 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 Repository +--- + + +# `google_secure_source_manager_repository_iam_policy` +Retrieves the current IAM policy data for repository + + +## example + +```hcl +data "google_secure_source_manager_repository_iam_policy" "policy" { + project = google_secure_source_manager_repository.default.project + location = google_secure_source_manager_repository.default.location + repository_id = google_secure_source_manager_repository.default.repository_id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `location` - (Optional) The location for the Repository. + Used to find the parent resource to bind the IAM policy to. If not specified, + the value will be parsed from the identifier of the parent resource. If no location is provided in the parent identifier and no + location is specified, it is taken from the provider configuration. +* `repository_id` - (Required) The ID for the Repository. + 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_repository_iam_policy`) The policy data generated by + a `google_iam_policy` data source. diff --git a/website/docs/r/secure_source_manager_repository.html.markdown b/website/docs/r/secure_source_manager_repository.html.markdown new file mode 100644 index 00000000000..3c14629e474 --- /dev/null +++ b/website/docs/r/secure_source_manager_repository.html.markdown @@ -0,0 +1,210 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** 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: |- + Repositories store source code. +--- + +# google_secure_source_manager_repository + +Repositories store source code. It supports all Git SCM client commands and has built-in pull requests and issue tracking. Both HTTPS and SSH authentication are supported. + + +To get more information about Repository, see: + +* How-to Guides + * [Official Documentation](https://cloud.google.com/secure-source-manager/docs/overview) + + +## Example Usage - Secure Source Manager Repository Basic + + +```hcl +resource "google_secure_source_manager_instance" "instance" { + location = "us-central1" + instance_id = "my-instance" +} + +resource "google_secure_source_manager_repository" "default" { + location = "us-central1" + repository_id = "my-repository" + instance = google_secure_source_manager_instance.instance.name +} +``` + +## Example Usage - Secure Source Manager Repository Initial Config + + +```hcl +resource "google_secure_source_manager_instance" "instance" { + location = "us-central1" + instance_id = "my-instance" +} + +resource "google_secure_source_manager_repository" "default" { + location = "us-central1" + repository_id = "my-repository" + instance = google_secure_source_manager_instance.instance.name + + description = "This is a test repository" + initial_config { + default_branch = "main" + gitignores = ["python"] + license = "mit" + readme = "default" + } +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `instance` - + (Required) + The name of the instance in which the repository is hosted. + +* `location` - + (Required) + The location for the Repository. + +* `repository_id` - + (Required) + The ID for the Repository. + + +- - - + + +* `description` - + (Optional) + Description of the repository, which cannot exceed 500 characters. + +* `initial_config` - + (Optional) + Initial configurations for the repository. + Structure is [documented below](#nested_initial_config). + +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. + + +The `initial_config` block supports: + +* `default_branch` - + (Optional) + Default branch name of the repository. + +* `gitignores` - + (Optional) + List of gitignore template names user can choose from. + Valid values can be viewed at https://cloud.google.com/secure-source-manager/docs/reference/rest/v1/projects.locations.repositories#initialconfig. + +* `license` - + (Optional) + License template name user can choose from. + Valid values can be viewed at https://cloud.google.com/secure-source-manager/docs/reference/rest/v1/projects.locations.repositories#initialconfig. + +* `readme` - + (Optional) + README template name. + Valid values can be viewed at https://cloud.google.com/secure-source-manager/docs/reference/rest/v1/projects.locations.repositories#initialconfig. + +## 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}}/repositories/{{repository_id}}` + +* `name` - + The resource name for the Repository. + +* `uid` - + Unique identifier of the repository. + +* `create_time` - + Time the repository was created in UTC. + +* `update_time` - + Time the repository was updated in UTC. + +* `uris` - + URIs for the repository. + Structure is [documented below](#nested_uris). + + +The `uris` block contains: + +* `html` - + (Output) + HTML is the URI for the user to view the repository in a browser. + +* `git_https` - + (Output) + git_https is the git HTTPS URI for git operations. + +* `api` - + (Output) + API is the URI for API access. + +## Timeouts + +This resource provides the following +[Timeouts](https://developer.hashicorp.com/terraform/plugin/sdkv2/resources/retries-and-customizable-timeouts) configuration options: + +- `create` - Default is 20 minutes. +- `delete` - Default is 20 minutes. + +## Import + + +Repository can be imported using any of these accepted formats: + +* `projects/{{project}}/locations/{{location}}/repositories/{{repository_id}}` +* `{{project}}/{{location}}/{{repository_id}}` +* `{{location}}/{{repository_id}}` +* `{{repository_id}}` + + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import Repository using one of the formats above. For example: + +```tf +import { + id = "projects/{{project}}/locations/{{location}}/repositories/{{repository_id}}" + to = google_secure_source_manager_repository.default +} +``` + +When using the [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import), Repository can be imported using one of the formats above. For example: + +``` +$ terraform import google_secure_source_manager_repository.default projects/{{project}}/locations/{{location}}/repositories/{{repository_id}} +$ terraform import google_secure_source_manager_repository.default {{project}}/{{location}}/{{repository_id}} +$ terraform import google_secure_source_manager_repository.default {{location}}/{{repository_id}} +$ terraform import google_secure_source_manager_repository.default {{repository_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_repository_iam.html.markdown b/website/docs/r/secure_source_manager_repository_iam.html.markdown new file mode 100644 index 00000000000..e6fa1f0efaf --- /dev/null +++ b/website/docs/r/secure_source_manager_repository_iam.html.markdown @@ -0,0 +1,157 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** 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 Repository +--- + +# IAM policy for Secure Source Manager Repository +Three different resources help you manage your IAM policy for Secure Source Manager Repository. Each of these resources serves a different use case: + +* `google_secure_source_manager_repository_iam_policy`: Authoritative. Sets the IAM policy for the repository and replaces any existing policy already attached. +* `google_secure_source_manager_repository_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 repository are preserved. +* `google_secure_source_manager_repository_iam_member`: Non-authoritative. Updates the IAM policy to grant a role to a new member. Other members for the role for the repository are preserved. + +A data source can be used to retrieve policy data in advent you do not need creation + +* `google_secure_source_manager_repository_iam_policy`: Retrieves the IAM policy for the repository + +~> **Note:** `google_secure_source_manager_repository_iam_policy` **cannot** be used in conjunction with `google_secure_source_manager_repository_iam_binding` and `google_secure_source_manager_repository_iam_member` or they will fight over what your policy should be. + +~> **Note:** `google_secure_source_manager_repository_iam_binding` resources **can be** used in conjunction with `google_secure_source_manager_repository_iam_member` resources **only if** they do not grant privilege to the same role. + + + +## google_secure_source_manager_repository_iam_policy + +```hcl +data "google_iam_policy" "admin" { + binding { + role = "roles/securesourcemanager.repoAdmin" + members = [ + "user:jane@example.com", + ] + } +} + +resource "google_secure_source_manager_repository_iam_policy" "policy" { + project = google_secure_source_manager_repository.default.project + location = google_secure_source_manager_repository.default.location + repository_id = google_secure_source_manager_repository.default.repository_id + policy_data = data.google_iam_policy.admin.policy_data +} +``` + +## google_secure_source_manager_repository_iam_binding + +```hcl +resource "google_secure_source_manager_repository_iam_binding" "binding" { + project = google_secure_source_manager_repository.default.project + location = google_secure_source_manager_repository.default.location + repository_id = google_secure_source_manager_repository.default.repository_id + role = "roles/securesourcemanager.repoAdmin" + members = [ + "user:jane@example.com", + ] +} +``` + +## google_secure_source_manager_repository_iam_member + +```hcl +resource "google_secure_source_manager_repository_iam_member" "member" { + project = google_secure_source_manager_repository.default.project + location = google_secure_source_manager_repository.default.location + repository_id = google_secure_source_manager_repository.default.repository_id + role = "roles/securesourcemanager.repoAdmin" + member = "user:jane@example.com" +} +``` + + +## Argument Reference + +The following arguments are supported: + +* `location` - (Optional) The location for the Repository. + Used to find the parent resource to bind the IAM policy to. If not specified, + the value will be parsed from the identifier of the parent resource. If no location is provided in the parent identifier and no + location is specified, it is taken from the provider configuration. +* `repository_id` - (Required) The ID for the Repository. + 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_repository_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_repository_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}}/repositories/{{repository_id}} +* {{project}}/{{location}}/{{repository_id}} +* {{location}}/{{repository_id}} +* {{repository_id}} + +Any variables not passed in the import command will be taken from the provider configuration. + +Secure Source Manager repository 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_repository_iam_member.editor "projects/{{project}}/locations/{{location}}/repositories/{{repository_id}} roles/securesourcemanager.repoAdmin 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_repository_iam_binding.editor "projects/{{project}}/locations/{{location}}/repositories/{{repository_id}} roles/securesourcemanager.repoAdmin" +``` + +IAM policy imports use the identifier of the resource in question, e.g. +``` +$ terraform import google_secure_source_manager_repository_iam_policy.editor projects/{{project}}/locations/{{location}}/repositories/{{repository_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).