diff --git a/build/terraform b/build/terraform index b61e5ec665fb..1aaf578c3e7c 160000 --- a/build/terraform +++ b/build/terraform @@ -1 +1 @@ -Subproject commit b61e5ec665fb638c73c3bd9ceddaf3d95e3e1288 +Subproject commit 1aaf578c3e7c1d22582fe8e892e9cde5940e7bf1 diff --git a/build/terraform-beta b/build/terraform-beta index b2e9b4c5a5e2..858167e3bf28 160000 --- a/build/terraform-beta +++ b/build/terraform-beta @@ -1 +1 @@ -Subproject commit b2e9b4c5a5e2b80f9fd8ee827327863e0de81c8c +Subproject commit 858167e3bf28e4f2fd111d8cb8b17521ef2156f7 diff --git a/products/compute/terraform.yaml b/products/compute/terraform.yaml index b64dd9fe7654..df5de9c48bac 100644 --- a/products/compute/terraform.yaml +++ b/products/compute/terraform.yaml @@ -857,7 +857,18 @@ overrides: !ruby/object:Overrides::ResourceOverrides insert_minutes: 6 update_minutes: 6 delete_minutes: 6 - exclude: true + iam_policy: !ruby/object:Api::Resource::IamPolicy + allowed_iam_role: 'roles/compute.osLogin' + parent_resource_attribute: 'instance_name' + iam_conditions_request_type: :QUERY_PARAM + exclude_resource: true + examples: + - !ruby/object:Provider::Terraform::Examples + name: "instance_basic" + primary_resource_id: "default" + vars: + instance_name: "my-instance" + primary_resource_name: "fmt.Sprintf(\"my-instance%s\", context[\"random_suffix\"])" InstanceGroup: !ruby/object:Overrides::Terraform::ResourceOverride exclude: true InstanceGroupManager: !ruby/object:Overrides::Terraform::ResourceOverride @@ -1663,6 +1674,9 @@ overrides: !ruby/object:Overrides::ResourceOverrides update_minutes: 6 delete_minutes: 6 id_format: "{{region}}/{{name}}" + iam_policy: !ruby/object:Api::Resource::IamPolicy + allowed_iam_role: 'roles/compute.networkUser' + parent_resource_attribute: 'subnetwork' properties: id: !ruby/object:Overrides::Terraform::PropertyOverride exclude: true @@ -1713,6 +1727,7 @@ overrides: !ruby/object:Overrides::ResourceOverrides vars: subnetwork_name: "test-subnetwork" network_name: "test-network" + primary_resource_name: "fmt.Sprintf(\"test-subnetwork%s\", context[\"random_suffix\"])" - !ruby/object:Provider::Terraform::Examples name: "subnetwork_logging_config" primary_resource_id: "subnet-with-logging" diff --git a/products/iap/terraform.yaml b/products/iap/terraform.yaml index 83f59955116a..919d7b531ad1 100644 --- a/products/iap/terraform.yaml +++ b/products/iap/terraform.yaml @@ -71,7 +71,7 @@ overrides: !ruby/object:Overrides::ResourceOverrides exclude: false method_name_separator: ':' parent_resource_type: 'google_app_engine_standard_app_version' - parent_resource_attribute: 'version' + parent_resource_attribute: 'version_id' fetch_iam_policy_verb: :POST allowed_iam_role: 'roles/iap.httpsResourceAccessor' example_config_body: 'templates/terraform/iam/example_config_body/app_engine_version.tf.erb' diff --git a/templates/terraform/examples/instance_basic.tf.erb b/templates/terraform/examples/instance_basic.tf.erb new file mode 100644 index 000000000000..5708fe6dc217 --- /dev/null +++ b/templates/terraform/examples/instance_basic.tf.erb @@ -0,0 +1,15 @@ +resource "google_compute_instance" "<%= ctx[:primary_resource_id] %>" { + name = "<%= ctx[:vars]['instance_name'] %>" + zone = "<%= ctx[:vars]['zone_name'] %>" + machine_type = "n1-standard-1" + + boot_disk { + initialize_params { + image = "debian-cloud/debian-9" + } + } + + network_interface { + network = "default" + } +} diff --git a/templates/terraform/iam_policy.go.erb b/templates/terraform/iam_policy.go.erb index 12ca3f4b029f..c8686affaba1 100644 --- a/templates/terraform/iam_policy.go.erb +++ b/templates/terraform/iam_policy.go.erb @@ -29,7 +29,8 @@ import ( <% resource_name = product_ns + object.name -%> <% resource_uri = object.self_link_url -resource_params = extract_identifiers(resource_uri.gsub('{{name}}', "{{#{object.name.underscore}}}")) +parent_resource_name = object.iam_policy.parent_resource_attribute || object.name.underscore +resource_params = extract_identifiers(resource_uri.gsub('{{name}}', "{{#{parent_resource_name}}}")) -%> var <%= resource_name -%>IamSchema = map[string]*schema.Schema{ @@ -88,7 +89,7 @@ func <%= resource_name -%>IamUpdaterProducer(d *schema.ResourceData, config *Con <% end # resource_params.each -%> // We may have gotten either a long or short name, so attempt to parse long name if possible - m, err := getImportIdQualifiers([]string{"<%= import_id_formats(object).map{|s| format2regex s}.map{|s| s.gsub('', "<#{object.name.underscore}>")}.join('","') -%>"}, d, config, d.Get("<%= resource_params.last.underscore -%>").(string)) + m, err := getImportIdQualifiers([]string{"<%= import_id_formats(object).map{|s| format2regex s}.map{|s| s.gsub('', "<#{object.name.underscore}>")}.join('","') -%>"}, d, config, d.Get("<%= parent_resource_name -%>").(string)) if err != nil { return nil, err } @@ -112,7 +113,7 @@ func <%= resource_name -%>IamUpdaterProducer(d *schema.ResourceData, config *Con d.Set("project", u.project) <% else -%> <%# Set the last parameter as the long name (unless it is project) -%> - d.Set("<%= resource_params.last.underscore -%>", u.GetResourceId()) + d.Set("<%= parent_resource_name -%>", u.GetResourceId()) <% end -%> <% else -%> d.Set("<%= param.underscore -%>", u.<%= param.camelize(:lower) -%>) @@ -157,7 +158,7 @@ func <%= resource_name -%>IdParseFunc(d *schema.ResourceData, config *Config) er d.Set("project", u.project) <% else -%> <%# Set resource long name in state, this has all the information that we need to identify it -%> - d.Set("<%= resource_params.last.underscore -%>", u.GetResourceId()) + d.Set("<%= parent_resource_name -%>", u.GetResourceId()) <% end -%> d.SetId(u.GetResourceId()) return nil @@ -177,7 +178,7 @@ func (u *<%= resource_name -%>IamUpdater) GetResourceIamPolicy() (*cloudresource <% if object.iam_policy.iam_conditions_request_type == :QUERY_PARAM -%> url, err = addQueryParams(url, map[string]string{"optionsRequestedPolicyVersion": fmt.Sprintf("%d", iamPolicyVersion)}) if err != nil { - return err + return nil, err } <% elsif object.iam_policy.iam_conditions_request_type == :REQUEST_BODY -%> obj = map[string]interface{}{ @@ -236,7 +237,7 @@ func (u *<%= resource_name -%>IamUpdater) qualify<%= object.name -%>Url(methodId } func (u *<%= resource_name -%>IamUpdater) GetResourceId() string { - return fmt.Sprintf("<%= object.id_format.gsub('{{name}}', "{{#{object.name.underscore}}}").gsub(/({{)(\w+)(}})/, '%s') -%>", <%= string_qualifiers -%>) + return fmt.Sprintf("<%= import_url -%>", <%= string_qualifiers -%>) } func (u *<%= resource_name -%>IamUpdater) GetMutexKey() string { diff --git a/templates/terraform/resource_iam.html.markdown.erb b/templates/terraform/resource_iam.html.markdown.erb index 1c36c550143a..bd0fa53bba26 100644 --- a/templates/terraform/resource_iam.html.markdown.erb +++ b/templates/terraform/resource_iam.html.markdown.erb @@ -188,7 +188,11 @@ The following arguments are supported: <% url_properties.each do |param| -%> <% if param.name == "name" -%> -* `<%= object.name.underscore -%>` - (Required) Used to find the parent resource to bind the IAM policy to +* `<%= object.iam_policy.parent_resource_attribute || object.name.underscore -%>` - (Required) Used to find the parent resource to bind the IAM policy to +<% elsif ["region", "zone"].include?(param.name.underscore) -%> +* `<%= param.name.underscore -%>` - (Optional) <%= param.description -%> 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 <%= param.name.underscore -%> is provided in the parent identifier and no + <%= param.name.underscore -%> is specified, it is taken from the provider configuration. <% else -%> * `<%= param.name.underscore -%>` - (Required) <%= param.description -%> Used to find the parent resource to bind the IAM policy to <% end -%> @@ -243,14 +247,29 @@ exported: ## Import -<%= product_ns -%> <%= object.name.downcase -%> IAM resources can be imported using the project, resource identifiers, role and member. +For all import syntaxes, the "resource in question" can take any of the following forms: +<% import_id_formats(object).each do |id_format| -%> +* <%= id_format %> +<% end -%> + +Any variables not passed in the import command will be taken from the provider configuration. + +<%= product_ns -%> <%= object.name.downcase -%> 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 <% if object.min_version.name == 'beta' %>-provider=google-beta <% end -%><%= resource_ns_iam -%>_member.editor "<%= object.id_format.gsub('{{name}}', "{{#{object.name.underscore}}}") -%> <%= object.iam_policy.allowed_iam_role -%> jane@example.com" ``` -$ terraform import <%= resource_ns_iam -%>_policy.editor <%= object.id_format.gsub('{{name}}', "{{#{object.name.underscore}}}") %> +IAM binding imports use space-delimited identifiers: the resource in question and the role, e.g. +``` $ terraform import <%= resource_ns_iam -%>_binding.editor "<%= object.id_format.gsub('{{name}}', "{{#{object.name.underscore}}}") -%> <%= object.iam_policy.allowed_iam_role -%>" +``` -$ terraform import <%= resource_ns_iam -%>_member.editor "<%= object.id_format.gsub('{{name}}', "{{#{object.name.underscore}}}") -%> <%= object.iam_policy.allowed_iam_role -%> jane@example.com" +IAM policy imports use the identifier of the resource in question, e.g. +``` +$ terraform import <% if object.min_version.name == 'beta' %>-provider=google-beta <% end -%><%= resource_ns_iam -%>_policy.editor <%= object.id_format.gsub('{{name}}', "{{#{object.name.underscore}}}") %> ``` -> If you're importing a resource with beta features, make sure to include `-provider=google-beta` diff --git a/third_party/terraform/resources/iam_compute_instance.go b/third_party/terraform/resources/iam_compute_instance.go deleted file mode 100644 index 0a6be8899c98..000000000000 --- a/third_party/terraform/resources/iam_compute_instance.go +++ /dev/null @@ -1,147 +0,0 @@ -package google - -import ( - "fmt" - "strings" - - "github.com/hashicorp/errwrap" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "google.golang.org/api/cloudresourcemanager/v1" - "google.golang.org/api/compute/v1" -) - -var IamComputeInstanceSchema = map[string]*schema.Schema{ - "instance_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - - "project": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - }, - - "zone": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - }, -} - -type ComputeInstanceIamUpdater struct { - project string - zone string - resourceId string - Config *Config -} - -func NewComputeInstanceIamUpdater(d *schema.ResourceData, config *Config) (ResourceIamUpdater, error) { - project, err := getProject(d, config) - if err != nil { - return nil, err - } - - zone, err := getZone(d, config) - if err != nil { - return nil, err - } - - return &ComputeInstanceIamUpdater{ - project: project, - zone: zone, - resourceId: d.Get("instance_name").(string), - Config: config, - }, nil -} - -func ComputeInstanceIdParseFunc(d *schema.ResourceData, config *Config) error { - parts := strings.Split(d.Id(), "/") - var fv *ZonalFieldValue - if len(parts) == 3 { - // {project}/{zone}/{name} syntax - fv = &ZonalFieldValue{ - Project: parts[0], - Zone: parts[1], - Name: parts[2], - resourceType: "instances", - } - } else if len(parts) == 2 { - // /{zone}/{name} syntax - project, err := getProject(d, config) - if err != nil { - return err - } - fv = &ZonalFieldValue{ - Project: project, - Zone: parts[0], - Name: parts[1], - resourceType: "instances", - } - } else { - // We either have a name or a full self link, so use the field helper - var err error - fv, err = ParseInstanceFieldValue(d.Id(), d, config) - if err != nil { - return err - } - } - - d.Set("project", fv.Project) - d.Set("zone", fv.Zone) - d.Set("instance_name", fv.Name) - - // Explicitly set the id so imported resources have the same ID format as non-imported ones. - d.SetId(fv.RelativeLink()) - return nil -} - -func (u *ComputeInstanceIamUpdater) GetResourceIamPolicy() (*cloudresourcemanager.Policy, error) { - p, err := u.Config.clientCompute.Instances.GetIamPolicy(u.project, u.zone, u.resourceId).Do() - - if err != nil { - return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for %s: {{err}}", u.DescribeResource()), err) - } - - cloudResourcePolicy, err := computeToResourceManagerPolicy(p) - - if err != nil { - return nil, errwrap.Wrapf(fmt.Sprintf("Invalid IAM policy for %s: {{err}}", u.DescribeResource()), err) - } - - return cloudResourcePolicy, nil -} - -func (u *ComputeInstanceIamUpdater) SetResourceIamPolicy(policy *cloudresourcemanager.Policy) error { - computePolicy, err := resourceManagerToComputePolicy(policy) - - if err != nil { - return errwrap.Wrapf(fmt.Sprintf("Invalid IAM policy for %s: {{err}}", u.DescribeResource()), err) - } - - req := &compute.ZoneSetPolicyRequest{ - Policy: computePolicy, - } - _, err = u.Config.clientCompute.Instances.SetIamPolicy(u.project, u.zone, u.resourceId, req).Do() - - if err != nil { - return errwrap.Wrapf(fmt.Sprintf("Error setting IAM policy for %s: {{err}}", u.DescribeResource()), err) - } - - return nil -} - -func (u *ComputeInstanceIamUpdater) GetResourceId() string { - return fmt.Sprintf("projects/%s/zones/%s/instances/%s", u.project, u.zone, u.resourceId) -} - -func (u *ComputeInstanceIamUpdater) GetMutexKey() string { - return fmt.Sprintf("iam-compute-Instance-%s-%s-%s", u.project, u.zone, u.resourceId) -} - -func (u *ComputeInstanceIamUpdater) DescribeResource() string { - return fmt.Sprintf("Compute Instance %s/%s/%s", u.project, u.zone, u.resourceId) -} diff --git a/third_party/terraform/resources/resource_compute_instance_iam_test.go b/third_party/terraform/resources/resource_compute_instance_iam_test.go index cadd44c5f31a..98f4002a095e 100644 --- a/third_party/terraform/resources/resource_compute_instance_iam_test.go +++ b/third_party/terraform/resources/resource_compute_instance_iam_test.go @@ -8,67 +8,8 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/resource" ) -func TestAccComputeInstanceIamBinding(t *testing.T) { - t.Parallel() - - project := getTestProjectFromEnv() - role := "roles/compute.osLogin" - zone := getTestZoneFromEnv() - instanceName := fmt.Sprintf("tf-test-instance-%s", acctest.RandString(10)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccComputeInstanceIamBinding_basic(zone, instanceName, role), - }, - { - ResourceName: "google_compute_instance_iam_binding.foo", - ImportStateId: fmt.Sprintf("%s/%s/%s %s", project, zone, instanceName, role), - ImportState: true, - ImportStateVerify: true, - }, - { - // Test Iam Binding update - Config: testAccComputeInstanceIamBinding_update(zone, instanceName, role), - }, - { - ResourceName: "google_compute_instance_iam_binding.foo", - ImportStateId: fmt.Sprintf("%s/%s/%s %s", project, zone, instanceName, role), - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAccComputeInstanceIamMember(t *testing.T) { - t.Parallel() - - project := getTestProjectFromEnv() - role := "roles/compute.osLogin" - zone := getTestZoneFromEnv() - instanceName := fmt.Sprintf("tf-test-instance-%s", acctest.RandString(10)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - // Test Iam Member creation (no update for member, no need to test) - Config: testAccComputeInstanceIamMember_basic(zone, instanceName, role), - }, - { - ResourceName: "google_compute_instance_iam_member.foo", - ImportStateId: fmt.Sprintf("%s/%s/%s %s user:admin@hashicorptest.com", project, zone, instanceName, role), - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - +// Even though the resource has generated tests, keep this one around until we are able to generate +// checking the different import formats func TestAccComputeInstanceIamPolicy(t *testing.T) { t.Parallel() @@ -103,39 +44,16 @@ func TestAccComputeInstanceIamPolicy(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + { + ResourceName: "google_compute_instance_iam_policy.foo", + ImportStateId: fmt.Sprintf("%s", instanceName), + ImportState: true, + ImportStateVerify: true, + }, }, }) } -func testAccComputeInstanceIamMember_basic(zone, instanceName, roleId string) string { - return fmt.Sprintf(` - resource "google_compute_instance" "test_vm" { - zone = "%s" - name = "%s" - machine_type = "n1-standard-1" - - boot_disk { - initialize_params { - image = "debian-cloud/debian-9" - } - } - - network_interface { - network = "default" - } - } - - resource "google_compute_instance_iam_member" "foo" { - project = "${google_compute_instance.test_vm.project}" - zone = "${google_compute_instance.test_vm.zone}" - instance_name = "${google_compute_instance.test_vm.name}" - role = "%s" - member = "user:Admin@hashicorptest.com" - } - -`, zone, instanceName, roleId) -} - func testAccComputeInstanceIamPolicy_basic(zone, instanceName, roleId string) string { return fmt.Sprintf(` resource "google_compute_instance" "test_vm" { @@ -170,61 +88,3 @@ func testAccComputeInstanceIamPolicy_basic(zone, instanceName, roleId string) st `, zone, instanceName, roleId) } - -func testAccComputeInstanceIamBinding_basic(zone, instanceName, roleId string) string { - return fmt.Sprintf(` - resource "google_compute_instance" "test_vm" { - zone = "%s" - name = "%s" - machine_type = "n1-standard-1" - - boot_disk { - initialize_params { - image = "debian-cloud/debian-9" - } - } - - network_interface { - network = "default" - } - } - - resource "google_compute_instance_iam_binding" "foo" { - project = "${google_compute_instance.test_vm.project}" - zone = "${google_compute_instance.test_vm.zone}" - instance_name = "${google_compute_instance.test_vm.name}" - role = "%s" - members = ["user:Admin@hashicorptest.com"] - } - -`, zone, instanceName, roleId) -} - -func testAccComputeInstanceIamBinding_update(zone, instanceName, roleId string) string { - return fmt.Sprintf(` - resource "google_compute_instance" "test_vm" { - zone = "%s" - name = "%s" - machine_type = "n1-standard-1" - - boot_disk { - initialize_params { - image = "debian-cloud/debian-9" - } - } - - network_interface { - network = "default" - } - } - - resource "google_compute_instance_iam_binding" "foo" { - project = "${google_compute_instance.test_vm.project}" - zone = "${google_compute_instance.test_vm.zone}" - instance_name = "${google_compute_instance.test_vm.name}" - role = "%s" - members = ["user:Admin@hashicorptest.com", "user:paddy@hashicorp.com"] - } - -`, zone, instanceName, roleId) -} diff --git a/third_party/terraform/tests/resource_compute_subnetwork_iam_test.go b/third_party/terraform/tests/resource_compute_subnetwork_iam_test.go index 7b63eff893d2..973f39016de6 100644 --- a/third_party/terraform/tests/resource_compute_subnetwork_iam_test.go +++ b/third_party/terraform/tests/resource_compute_subnetwork_iam_test.go @@ -8,68 +8,8 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/resource" ) -func TestAccComputeSubnetworkIamBinding(t *testing.T) { - t.Parallel() - - account := acctest.RandomWithPrefix("tf-test") - role := "roles/compute.networkUser" - region := getTestRegionFromEnv() - subnetwork := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccComputeSubnetworkIamBinding_basic(account, region, subnetwork, role), - }, - { - ResourceName: "google_compute_subnetwork_iam_binding.foo", - ImportStateId: fmt.Sprintf("%s/%s %s", region, subnetwork, role), - ImportState: true, - ImportStateVerify: true, - }, - { - // Test Iam Binding update - Config: testAccComputeSubnetworkIamBinding_update(account, region, subnetwork, role), - }, - { - ResourceName: "google_compute_subnetwork_iam_binding.foo", - ImportStateId: fmt.Sprintf("%s/%s %s", region, subnetwork, role), - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAccComputeSubnetworkIamMember(t *testing.T) { - t.Parallel() - - project := getTestProjectFromEnv() - account := acctest.RandomWithPrefix("tf-test") - role := "roles/compute.networkUser" - region := getTestRegionFromEnv() - subnetwork := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - // Test Iam Member creation (no update for member, no need to test) - Config: testAccComputeSubnetworkIamMember_basic(account, region, subnetwork, role), - }, - { - ResourceName: "google_compute_subnetwork_iam_member.foo", - ImportStateId: fmt.Sprintf("%s/%s %s serviceAccount:%s@%s.iam.gserviceaccount.com", region, subnetwork, role, account, project), - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - +// Even though the resource has generated tests, keep this one around until we are able to generate +// checking the different import formats func TestAccComputeSubnetworkIamPolicy(t *testing.T) { t.Parallel() @@ -115,101 +55,6 @@ func TestAccComputeSubnetworkIamPolicy(t *testing.T) { }) } -func testAccComputeSubnetworkIamBinding_basic(account, region, subnetworkName, roleId string) string { - return fmt.Sprintf(` -resource "google_service_account" "test_account" { - account_id = "%s" - display_name = "Subnetwork Iam Testing Account" -} - -resource "google_compute_network" "network" { - name = "%s" - auto_create_subnetworks = false -} - -resource "google_compute_subnetwork" "subnetwork" { - name = "%s" - region = "%s" - ip_cidr_range = "10.1.0.0/16" - network = "${google_compute_network.network.name}" -} - -resource "google_compute_subnetwork_iam_binding" "foo" { - project = "${google_compute_subnetwork.subnetwork.project}" - region = "${google_compute_subnetwork.subnetwork.region}" - subnetwork = "${google_compute_subnetwork.subnetwork.name}" - role = "%s" - members = ["serviceAccount:${google_service_account.test_account.email}"] -} -`, account, subnetworkName, subnetworkName, region, roleId) -} - -func testAccComputeSubnetworkIamBinding_update(account, region, subnetworkName, roleId string) string { - return fmt.Sprintf(` -resource "google_service_account" "test_account" { - account_id = "%s" - display_name = "Subnetwork Iam Testing Account" -} - -resource "google_service_account" "test_account_2" { - account_id = "%s-2" - display_name = "Subnetwork Iam Testing Account" -} - -resource "google_compute_network" "network" { - name = "%s" - auto_create_subnetworks = false -} - -resource "google_compute_subnetwork" "subnetwork" { - name = "%s" - region = "%s" - ip_cidr_range = "10.1.0.0/16" - network = "${google_compute_network.network.name}" -} - -resource "google_compute_subnetwork_iam_binding" "foo" { - project = "${google_compute_subnetwork.subnetwork.project}" - region = "${google_compute_subnetwork.subnetwork.region}" - subnetwork = "${google_compute_subnetwork.subnetwork.name}" - role = "%s" - members = [ - "serviceAccount:${google_service_account.test_account.email}", - "serviceAccount:${google_service_account.test_account_2.email}" - ] -} -`, account, account, subnetworkName, subnetworkName, region, roleId) -} - -func testAccComputeSubnetworkIamMember_basic(account, region, subnetworkName, roleId string) string { - return fmt.Sprintf(` -resource "google_service_account" "test_account" { - account_id = "%s" - display_name = "Subnetwork Iam Testing Account" -} - -resource "google_compute_network" "network" { - name = "%s" - auto_create_subnetworks = false -} - -resource "google_compute_subnetwork" "subnetwork" { - name = "%s" - region = "%s" - ip_cidr_range = "10.1.0.0/16" - network = "${google_compute_network.network.name}" -} - -resource "google_compute_subnetwork_iam_member" "foo" { - project = "${google_compute_subnetwork.subnetwork.project}" - region = "${google_compute_subnetwork.subnetwork.region}" - subnetwork = "${google_compute_subnetwork.subnetwork.name}" - role = "%s" - member = "serviceAccount:${google_service_account.test_account.email}" -} -`, account, subnetworkName, subnetworkName, region, roleId) -} - func testAccComputeSubnetworkIamPolicy_basic(account, region, subnetworkName, roleId string) string { return fmt.Sprintf(` resource "google_service_account" "test_account" { diff --git a/third_party/terraform/utils/iam_compute_subnetwork.go b/third_party/terraform/utils/iam_compute_subnetwork.go deleted file mode 100644 index 2bbd0a5aeb0f..000000000000 --- a/third_party/terraform/utils/iam_compute_subnetwork.go +++ /dev/null @@ -1,164 +0,0 @@ -package google - -import ( - "fmt" - "strings" - - "github.com/hashicorp/errwrap" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "google.golang.org/api/cloudresourcemanager/v1" - "google.golang.org/api/compute/v1" -) - -var IamComputeSubnetworkSchema = map[string]*schema.Schema{ - "subnetwork": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - - "project": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - }, - - "region": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - }, -} - -type ComputeSubnetworkIamUpdater struct { - project string - region string - resourceId string - Config *Config -} - -func NewComputeSubnetworkIamUpdater(d *schema.ResourceData, config *Config) (ResourceIamUpdater, error) { - project, err := getProject(d, config) - if err != nil { - return nil, err - } - - region, err := getRegion(d, config) - if err != nil { - return nil, err - } - - return &ComputeSubnetworkIamUpdater{ - project: project, - region: region, - resourceId: d.Get("subnetwork").(string), - Config: config, - }, nil -} - -func ComputeSubnetworkIdParseFunc(d *schema.ResourceData, config *Config) error { - parts := strings.Split(d.Id(), "/") - var fv *RegionalFieldValue - if len(parts) == 3 { - // {project}/{region}/{name} syntax - fv = &RegionalFieldValue{ - Project: parts[0], - Region: parts[1], - Name: parts[2], - resourceType: "subnetworks", - } - } else if len(parts) == 2 { - // /{region}/{name} syntax - project, err := getProject(d, config) - if err != nil { - return err - } - fv = &RegionalFieldValue{ - Project: project, - Region: parts[0], - Name: parts[1], - resourceType: "subnetworks", - } - } else { - // We either have a name or a full self link, so use the field helper - var err error - fv, err = ParseSubnetworkFieldValue(d.Id(), d, config) - if err != nil { - return err - } - } - d.Set("subnetwork", fv.Name) - d.Set("project", fv.Project) - d.Set("region", fv.Region) - - // Explicitly set the id so imported resources have the same ID format as non-imported ones. - d.SetId(fv.RelativeLink()) - return nil -} - -func (u *ComputeSubnetworkIamUpdater) GetResourceIamPolicy() (*cloudresourcemanager.Policy, error) { - p, err := u.Config.clientCompute.Subnetworks.GetIamPolicy(u.project, u.region, u.resourceId).Do() - - if err != nil { - return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for %s: {{err}}", u.DescribeResource()), err) - } - - cloudResourcePolicy, err := computeToResourceManagerPolicy(p) - - if err != nil { - return nil, errwrap.Wrapf(fmt.Sprintf("Invalid IAM policy for %s: {{err}}", u.DescribeResource()), err) - } - - return cloudResourcePolicy, nil -} - -func (u *ComputeSubnetworkIamUpdater) SetResourceIamPolicy(policy *cloudresourcemanager.Policy) error { - computePolicy, err := resourceManagerToComputePolicy(policy) - - if err != nil { - return errwrap.Wrapf(fmt.Sprintf("Invalid IAM policy for %s: {{err}}", u.DescribeResource()), err) - } - - req := &compute.RegionSetPolicyRequest{ - Policy: computePolicy, - } - _, err = u.Config.clientCompute.Subnetworks.SetIamPolicy(u.project, u.region, u.resourceId, req).Do() - - if err != nil { - return errwrap.Wrapf(fmt.Sprintf("Error setting IAM policy for %s: {{err}}", u.DescribeResource()), err) - } - - return nil -} - -func (u *ComputeSubnetworkIamUpdater) GetResourceId() string { - return fmt.Sprintf("projects/%s/regions/%s/subnetworks/%s", u.project, u.region, u.resourceId) -} - -func (u *ComputeSubnetworkIamUpdater) GetMutexKey() string { - return fmt.Sprintf("iam-compute-subnetwork-%s-%s-%s", u.project, u.region, u.resourceId) -} - -func (u *ComputeSubnetworkIamUpdater) DescribeResource() string { - return fmt.Sprintf("Compute Subnetwork %s/%s/%s", u.project, u.region, u.resourceId) -} - -func resourceManagerToComputePolicy(p *cloudresourcemanager.Policy) (*compute.Policy, error) { - out := &compute.Policy{} - err := Convert(p, out) - if err != nil { - return nil, errwrap.Wrapf("Cannot convert a resourcemanager policy to a compute policy: {{err}}", err) - } - return out, nil -} - -func computeToResourceManagerPolicy(p *compute.Policy) (*cloudresourcemanager.Policy, error) { - out := &cloudresourcemanager.Policy{} - err := Convert(p, out) - if err != nil { - return nil, errwrap.Wrapf("Cannot convert a compute policy to a resourcemanager policy: {{err}}", err) - } - return out, nil -} diff --git a/third_party/terraform/utils/provider.go.erb b/third_party/terraform/utils/provider.go.erb index fc9fea327572..0e8cea462bdd 100644 --- a/third_party/terraform/utils/provider.go.erb +++ b/third_party/terraform/utils/provider.go.erb @@ -288,9 +288,6 @@ end # products.each do "google_compute_instance_from_template": resourceComputeInstanceFromTemplate(), "google_compute_instance_group": resourceComputeInstanceGroup(), "google_compute_instance_group_manager": resourceComputeInstanceGroupManager(), - "google_compute_instance_iam_binding": ResourceIamBinding(IamComputeInstanceSchema, NewComputeInstanceIamUpdater, ComputeInstanceIdParseFunc), - "google_compute_instance_iam_member": ResourceIamMember(IamComputeInstanceSchema, NewComputeInstanceIamUpdater, ComputeInstanceIdParseFunc), - "google_compute_instance_iam_policy": ResourceIamPolicy(IamComputeInstanceSchema, NewComputeInstanceIamUpdater, ComputeInstanceIdParseFunc), "google_compute_instance_template": resourceComputeInstanceTemplate(), "google_compute_network_peering": resourceComputeNetworkPeering(), "google_compute_project_default_network_tier": resourceComputeProjectDefaultNetworkTier(), @@ -302,9 +299,6 @@ end # products.each do "google_compute_security_policy": resourceComputeSecurityPolicy(), "google_compute_shared_vpc_host_project": resourceComputeSharedVpcHostProject(), "google_compute_shared_vpc_service_project": resourceComputeSharedVpcServiceProject(), - "google_compute_subnetwork_iam_binding": ResourceIamBinding(IamComputeSubnetworkSchema, NewComputeSubnetworkIamUpdater, ComputeSubnetworkIdParseFunc), - "google_compute_subnetwork_iam_member": ResourceIamMember(IamComputeSubnetworkSchema, NewComputeSubnetworkIamUpdater, ComputeSubnetworkIdParseFunc), - "google_compute_subnetwork_iam_policy": ResourceIamPolicy(IamComputeSubnetworkSchema, NewComputeSubnetworkIamUpdater, ComputeSubnetworkIdParseFunc), "google_compute_target_pool": resourceComputeTargetPool(), "google_container_cluster": resourceContainerCluster(), "google_container_node_pool": resourceContainerNodePool(), diff --git a/third_party/terraform/website/docs/r/compute_instance_iam.html.markdown b/third_party/terraform/website/docs/r/compute_instance_iam.html.markdown deleted file mode 100644 index 9e30d21f7856..000000000000 --- a/third_party/terraform/website/docs/r/compute_instance_iam.html.markdown +++ /dev/null @@ -1,124 +0,0 @@ ---- -subcategory: "Compute Engine" -layout: "google" -page_title: "Google: google_compute_instance_iam" -sidebar_current: "docs-google-compute-instance-iam" -description: |- - Collection of resources to manage IAM policy for a GCE instance. ---- - -# IAM policy for GCE instance - -Three different resources help you manage your IAM policy for GCE instance. Each of these resources serves a different use case: - -* `google_compute_instance_iam_policy`: Authoritative. Sets the IAM policy for the instance and replaces any existing policy already attached. -* `google_compute_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_compute_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. - -~> **Note:** `google_compute_instance_iam_policy` **cannot** be used in conjunction with `google_compute_instance_iam_binding` and `google_compute_instance_iam_member` or they will fight over what your policy should be. - -~> **Note:** `google_compute_instance_iam_binding` resources **can be** used in conjunction with `google_compute_instance_iam_member` resources **only if** they do not grant privilege to the same role. - -## google\_compute\_instance\_iam\_policy - -```hcl -data "google_iam_policy" "admin" { - binding { - role = "roles/compute.osLogin" - - members = [ - "user:jane@example.com", - ] - } -} - -resource "google_compute_instance_iam_policy" "instance" { - instance_name = "your-instance-name" - policy_data = "${data.google_iam_policy.admin.policy_data}" -} -``` - -## google\_compute\_instance\_iam\_binding - -```hcl -resource "google_compute_instance_iam_binding" "instance" { - instance_name = "your-instance-name" - role = "roles/compute.osLogin" - - members = [ - "user:jane@example.com", - ] -} -``` - -## google\_compute\_instance\_iam\_member - -```hcl -resource "google_compute_instance_iam_member" "instance" { - instance_name = "your-instance-name" - role = "roles/compute.osLogin" - member = "user:jane@example.com" -} -``` - -## Argument Reference - -The following arguments are supported: - -* `instance_name` - (Required) The name of the instance. - -* `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. - -* `role` - (Required) The role that should be applied. Only one - `google_compute_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_compute_instance_iam_policy`) The policy data generated by - a `google_iam_policy` data source. - -* `project` - (Optional) The ID of the project in which the resource belongs. If it - is not provided, the provider project is used. - -* `zone` - (Optional) The zone of the instance. If - unspecified, this defaults to the zone configured in the provider. - -## Attributes Reference - -In addition to the arguments listed above, the following computed attributes are -exported: - -* `etag` - (Computed) The etag of the instance's IAM policy. - -## Import - -For all import syntaxes, the "resource in question" can take any of the following forms: - -* full self link or relative link (projects/{{project}}/zones/{{zone}}/instances/{{name}}) -* {{project}}/{{zone}}/{{name}} -* {{zone}}/{{name}} (project is taken from provider project) -* {{name}} (project and zone are taken from provider project) - -IAM member imports use space-delimited identifiers; the resource in question, the role, and the member identity, e.g. - -``` -$ terraform import google_compute_instance_iam_member.instance "project-name/zone-name/instance-name roles/compute.osLogin user:foo@example.com" -``` - -IAM binding imports use space-delimited identifiers; the resource in question and the role, e.g. - -``` -$ terraform import google_compute_instance_iam_binding.instance "project-name/zone-name/instance-name roles/compute.osLogin" -``` - -IAM policy imports use the identifier of the resource in question, e.g. - -``` -$ terraform import google_compute_instance_iam_policy.instance project-name/zone-name/instance-name -``` diff --git a/third_party/terraform/website/docs/r/compute_subnetwork_iam.html.markdown b/third_party/terraform/website/docs/r/compute_subnetwork_iam.html.markdown deleted file mode 100644 index 0964035c6c5a..000000000000 --- a/third_party/terraform/website/docs/r/compute_subnetwork_iam.html.markdown +++ /dev/null @@ -1,127 +0,0 @@ ---- -subcategory: "Compute Engine" -layout: "google" -page_title: "Google: google_compute_subnetwork_iam" -sidebar_current: "docs-google-compute-subnetwork-iam" -description: |- - Collection of resources to manage IAM policy for a GCE subnetwork. ---- - -# IAM policy for GCE subnetwork - -~> **Warning:** These resources are in beta, and should be used with the terraform-provider-google-beta provider. -See [Provider Versions](https://terraform.io/docs/providers/google/guides/provider_versions.html) for more details on beta resources. - -Three different resources help you manage your IAM policy for GCE subnetwork. Each of these resources serves a different use case: - -* `google_compute_subnetwork_iam_policy`: Authoritative. Sets the IAM policy for the subnetwork and replaces any existing policy already attached. -* `google_compute_subnetwork_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 subnetwork are preserved. -* `google_compute_subnetwork_iam_member`: Non-authoritative. Updates the IAM policy to grant a role to a new member. Other members for the role for the subnetwork are preserved. - -~> **Note:** `google_compute_subnetwork_iam_policy` **cannot** be used in conjunction with `google_compute_subnetwork_iam_binding` and `google_compute_subnetwork_iam_member` or they will fight over what your policy should be. - -~> **Note:** `google_compute_subnetwork_iam_binding` resources **can be** used in conjunction with `google_compute_subnetwork_iam_member` resources **only if** they do not grant privilege to the same role. - -## google\_compute\_subnetwork\_iam\_policy - -```hcl -data "google_iam_policy" "admin" { - binding { - role = "roles/editor" - - members = [ - "user:jane@example.com", - ] - } -} - -resource "google_compute_subnetwork_iam_policy" "subnet" { - subnetwork = "your-subnetwork-id" - policy_data = "${data.google_iam_policy.admin.policy_data}" -} -``` - -## google\_compute\_subnetwork\_iam\_binding - -```hcl -resource "google_compute_subnetwork_iam_binding" "subnet" { - subnetwork = "your-subnetwork-id" - role = "roles/compute.networkUser" - - members = [ - "user:jane@example.com", - ] -} -``` - -## google\_compute\_subnetwork\_iam\_member - -```hcl -resource "google_compute_subnetwork_iam_member" "subnet" { - subnetwork = "your-subnetwork-id" - role = "roles/compute.networkUser" - member = "user:jane@example.com" -} -``` - -## Argument Reference - -The following arguments are supported: - -* `subnetwork` - (Required) The name of the subnetwork. - -* `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. - -* `role` - (Required) The role that should be applied. Only one - `google_compute_subnetwork_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_compute_subnetwork_iam_policy`) The policy data generated by - a `google_iam_policy` data source. - -* `project` - (Optional) The ID of the project in which the resource belongs. If it - is not provided, the provider project is used. - -* `region` - (Optional) The region of the subnetwork. If - unspecified, this defaults to the region configured in the provider. - -## Attributes Reference - -In addition to the arguments listed above, the following computed attributes are -exported: - -* `etag` - (Computed) The etag of the subnetwork's IAM policy. - -## Import - -For all import syntaxes, the "resource in question" can take any of the following forms: - -* full self link or relative link (projects/{{project}}/region/{{region}}/subnetworks/{{name}}) -* {{project}}/{{region}}/{{name}} -* {{region}}/{{name}} (project is taken from provider project) -* {{name}} (project and region are taken from provider project) - -IAM member imports use space-delimited identifiers; the resource in question, the role, and the member identity, e.g. - -``` -$ terraform import google_compute_subnetwork_iam_member.subnet "project-name/region-name/subnetwork-name roles/compute.networkUser user:foo@example.com" -``` - -IAM binding imports use space-delimited identifiers; the resource in question and the role, e.g. - -``` -$ terraform import google_compute_subnetwork_iam_binding.subnet "project-name/region-name/subnetwork-name roles/compute.networkUser" -``` - -IAM policy imports use the identifier of the resource in question, e.g. - -``` -$ terraform import google_compute_subnetwork_iam_policy.subnet project-name/region-name/subnetwork-name -```