diff --git a/build/terraform b/build/terraform index 5a59f6e18c13..3d3da651f8aa 160000 --- a/build/terraform +++ b/build/terraform @@ -1 +1 @@ -Subproject commit 5a59f6e18c1375fdd78406eb7f00ae0b99a88e2d +Subproject commit 3d3da651f8aa2b413129d55e9d73530d0b824067 diff --git a/build/terraform-beta b/build/terraform-beta index 6bc1b8c1f647..fc1f5186b50c 160000 --- a/build/terraform-beta +++ b/build/terraform-beta @@ -1 +1 @@ -Subproject commit 6bc1b8c1f647c2473ee109b8744e059d24e8f4d7 +Subproject commit fc1f5186b50c00ee2d3f032d35f037002588d035 diff --git a/products/iap/api.yaml b/products/iap/api.yaml index e4b31306ac44..8466a49fd19c 100644 --- a/products/iap/api.yaml +++ b/products/iap/api.yaml @@ -121,3 +121,17 @@ objects: name: 'name' description: Name or self link of a backend service. required: true + # This resource is only used to generate IAM resources. They do not correspond to real + # GCP resources, and should not be used to generate anything other than IAM suppport. + - !ruby/object:Api::Resource + name: 'TunnelInstance' + base_url: 'projects/{{project}}/iap_tunnel/zones/{{zone}}/instances/{{name}}' + self_link: 'projects/{{project}}/iap_tunnel/zones/{{zone}}/instances/{{name}}' + exclude_resource: true + description: | + Only used to generate IAM resources + properties: + - !ruby/object:Api::Type::String + name: 'name' + description: Name of the instance. + required: true diff --git a/products/iap/terraform.yaml b/products/iap/terraform.yaml index f0faae4ce822..073bcd946432 100644 --- a/products/iap/terraform.yaml +++ b/products/iap/terraform.yaml @@ -129,6 +129,27 @@ overrides: !ruby/object:Overrides::ResourceOverrides backend_service_name: "backend-service" http_health_check_name: "health-check" primary_resource_name: "fmt.Sprintf(\"backend-service%s\", context[\"random_suffix\"])" + TunnelInstance: !ruby/object:Overrides::Terraform::ResourceOverride + iam_policy: !ruby/object:Api::Resource::IamPolicy + exclude: false + method_name_separator: ':' + parent_resource_type: 'google_compute_instance' + parent_resource_attribute: 'instance' + fetch_iam_policy_verb: :POST + allowed_iam_role: 'roles/iap.tunnelResourceAccessor' + iam_conditions_request_type: :REQUEST_BODY + id_format: "projects/{{project}}/iap_tunnel/zones/{{zone}}/instances/{{name}}" + import_format: [ + "projects/{{project}}/iap_tunnel/zones/{{zone}}/instances/{{name}}", + "projects/{{project}}/zones/{{zone}}/instances/{{name}}" + ] + examples: + - !ruby/object:Provider::Terraform::Examples + name: "instance_basic" + primary_resource_id: "tunnelvm" + vars: + instance_name: "tf-test-tunnel" + primary_resource_name: "fmt.Sprintf(\"tf-test-tunnel%s\", context[\"random_suffix\"])" # This is for copying files over files: !ruby/object:Provider::Config::Files # These files have templating (ERB) code that will be run. diff --git a/third_party/terraform/tests/resource_iap_tunnel_instance_iam_test.go.erb b/third_party/terraform/tests/resource_iap_tunnel_instance_iam_test.go.erb deleted file mode 100644 index 2bf61568dbd9..000000000000 --- a/third_party/terraform/tests/resource_iap_tunnel_instance_iam_test.go.erb +++ /dev/null @@ -1,224 +0,0 @@ -<% autogen_exception -%> -package google -<% unless version == 'ga' -%> - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" -) - -func TestAccIapTunnelInstanceIamBinding(t *testing.T) { - t.Parallel() - - project := getTestProjectFromEnv() - 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: testAccIapTunnelInstanceIamBinding_basic(zone, instanceName), - }, - { - ResourceName: "google_iap_tunnel_instance_iam_binding.foo", - ImportStateId: fmt.Sprintf("%s/%s/%s roles/iap.tunnelResourceAccessor", project, zone, instanceName), - ImportState: true, - ImportStateVerify: true, - }, - { - // Test Iam Binding update - Config: testAccIapTunnelInstanceIamBinding_update(zone, instanceName), - }, - { - ResourceName: "google_iap_tunnel_instance_iam_binding.foo", - ImportStateId: fmt.Sprintf("%s/%s/%s roles/iap.tunnelResourceAccessor", project, zone, instanceName), - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAccIapTunnelInstanceIamMember(t *testing.T) { - t.Parallel() - - project := getTestProjectFromEnv() - 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: testAccIapTunnelInstanceIamMember_basic(zone, instanceName), - }, - { - ResourceName: "google_iap_tunnel_instance_iam_member.foo", - ImportStateId: fmt.Sprintf("%s/%s/%s roles/iap.tunnelResourceAccessor user:admin@hashicorptest.com", project, zone, instanceName), - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAccIapTunnelInstanceIamPolicy(t *testing.T) { - t.Parallel() - - project := getTestProjectFromEnv() - 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: testAccIapTunnelInstanceIamPolicy_basic(zone, instanceName), - }, - // Test a few import formats - { - ResourceName: "google_iap_tunnel_instance_iam_policy.foo", - ImportStateId: fmt.Sprintf("projects/%s/zones/%s/instances/%s", project, zone, instanceName), - ImportState: true, - ImportStateVerify: true, - }, - { - ResourceName: "google_iap_tunnel_instance_iam_policy.foo", - ImportStateId: fmt.Sprintf("%s/%s/%s", project, zone, instanceName), - ImportState: true, - ImportStateVerify: true, - }, - { - ResourceName: "google_iap_tunnel_instance_iam_policy.foo", - ImportStateId: fmt.Sprintf("%s/%s", zone, instanceName), - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func testAccIapTunnelInstanceIamBinding_basic(zone, instanceName 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_iap_tunnel_instance_iam_binding" "foo" { - project = google_compute_instance.test_vm.project - zone = google_compute_instance.test_vm.zone - instance = google_compute_instance.test_vm.name - role = "roles/iap.tunnelResourceAccessor" - members = ["user:admin@hashicorptest.com"] -} -`, zone, instanceName) -} - -func testAccIapTunnelInstanceIamBinding_update(zone, instanceName 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_iap_tunnel_instance_iam_binding" "foo" { - project = google_compute_instance.test_vm.project - zone = google_compute_instance.test_vm.zone - instance = google_compute_instance.test_vm.name - role = "roles/iap.tunnelResourceAccessor" - members = [ - "user:admin@hashicorptest.com", - "user:paddy@hashicorp.com", - ] -} -`, zone, instanceName) -} - -func testAccIapTunnelInstanceIamMember_basic(zone, instanceName 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_iap_tunnel_instance_iam_member" "foo" { - project = google_compute_instance.test_vm.project - zone = google_compute_instance.test_vm.zone - instance = google_compute_instance.test_vm.name - role = "roles/iap.tunnelResourceAccessor" - member = "user:admin@hashicorptest.com" -} -`,zone, instanceName) -} - -func testAccIapTunnelInstanceIamPolicy_basic(zone, instanceName 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" - } -} - -data "google_iam_policy" "foo" { - binding { - role = "roles/iap.tunnelResourceAccessor" - members = ["user:admin@hashicorptest.com"] - } -} - -resource "google_iap_tunnel_instance_iam_policy" "foo" { - project = google_compute_instance.test_vm.project - zone = google_compute_instance.test_vm.zone - instance = google_compute_instance.test_vm.name - policy_data = data.google_iam_policy.foo.policy_data -} -`, zone, instanceName) -} - -<% else %> -// Magic Modules doesn't let us remove files - blank out beta-only common-compile files for now. -<% end -%> diff --git a/third_party/terraform/utils/iam_iap_tunnel_instance.go.erb b/third_party/terraform/utils/iam_iap_tunnel_instance.go.erb deleted file mode 100644 index 5d80c1c4fa19..000000000000 --- a/third_party/terraform/utils/iam_iap_tunnel_instance.go.erb +++ /dev/null @@ -1,193 +0,0 @@ -<% autogen_exception -%> -package google -<% unless version == 'ga' -%> -import ( - "fmt" - "strconv" - "strings" - - "github.com/hashicorp/errwrap" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "google.golang.org/api/cloudresourcemanager/v1" - iap "google.golang.org/api/iap/v1beta1" -) - -var IamIapTunnelInstanceSchema = map[string]*schema.Schema{ - "instance": { - 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 IapTunnelInstanceIamUpdater struct { - project string - zone string - instance string - projectNumber string - Config *Config -} - -func NewIapTunnelInstanceIamUpdater(d *schema.ResourceData, config *Config) (ResourceIamUpdater, error) { - project, err := getProject(d, config) - if err != nil { - return nil, err - } - - res, err := config.clientResourceManager.Projects.Get(project).Do() - if err != nil { - return nil, err - } - - //The IAP API currently doesn't work when using a projectId. When hitting the endpoint with a projectId instead - //of a projectNumber, the backend returns a 400 error, saying that it is an invalid argument. We abstract away - //this implementation detail from the consumer, and allow consumers to work with projectIds, which is consistent - //with other resources. However, that means we have to maintain/lookup the projectNumber from the projectID - //inside this provider plugin. - projectNumber := strconv.FormatInt(res.ProjectNumber, 10) - - zone, err := getZone(d, config) - if err != nil { - return nil, err - } - - return &IapTunnelInstanceIamUpdater{ - project: project, - projectNumber: projectNumber, - zone: zone, - instance: d.Get("instance").(string), - Config: config, - }, nil -} - -func IapTunnelInstanceIdParseFunc(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", fv.Name) - - res, err := config.clientResourceManager.Projects.Get(fv.Project).Do() - if err != nil { - return err - } - - projectNumber := strconv.FormatInt(res.ProjectNumber, 10) - - // Explicitly set the id so imported resources have the same ID format as non-imported ones. - d.SetId(fmt.Sprintf("projects/%s/iap_tunnel/zones/%s/instances/%s", projectNumber, fv.Zone, fv.Name)) - return nil -} - -func (u *IapTunnelInstanceIamUpdater) GetResourceIamPolicy() (*cloudresourcemanager.Policy, error) { - req := &iap.GetIamPolicyRequest{} - - p, err := u.Config.clientIAP.V1beta1.GetIamPolicy(fmt.Sprintf("projects/%s/iap_tunnel/zones/%s/instances/%s", u.projectNumber, u.zone, u.instance), req).Do() - - if err != nil { - return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for %s: {{err}}", u.DescribeResource()), err) - } - - cloudResourcePolicy, err := iapToResourceManagerPolicy(p) - - if err != nil { - return nil, errwrap.Wrapf(fmt.Sprintf("Invalid IAM policy for %s: {{err}}", u.DescribeResource()), err) - } - - return cloudResourcePolicy, nil -} - -func (u *IapTunnelInstanceIamUpdater) SetResourceIamPolicy(policy *cloudresourcemanager.Policy) error { - iapPolicy, err := resourceManagerToIapPolicy(policy) - - if err != nil { - return errwrap.Wrapf(fmt.Sprintf("Invalid IAM policy for %s: {{err}}", u.DescribeResource()), err) - } - - req := &iap.SetIamPolicyRequest{ - Policy: iapPolicy, - } - _, err = u.Config.clientIAP.V1beta1.SetIamPolicy(fmt.Sprintf("projects/%s/iap_tunnel/zones/%s/instances/%s", u.projectNumber, u.zone, u.instance), req).Do() - - if err != nil { - return errwrap.Wrapf(fmt.Sprintf("Error setting IAM policy for %s: {{err}}", u.DescribeResource()), err) - } - - return nil -} - -func (u *IapTunnelInstanceIamUpdater) GetResourceId() string { - return fmt.Sprintf("projects/%s/iap_tunnel/zones/%s/instances/%s", u.projectNumber, u.zone, u.instance) -} - -func (u *IapTunnelInstanceIamUpdater) GetMutexKey() string { - return fmt.Sprintf("iap-tunnel-instance-%s-%s-%s", u.projectNumber, u.zone, u.instance) -} - -func (u *IapTunnelInstanceIamUpdater) DescribeResource() string { - return fmt.Sprintf("IAP Tunnel Instance %s/%s/%s", u.projectNumber, u.zone, u.instance) -} - -func resourceManagerToIapPolicy(p *cloudresourcemanager.Policy) (*iap.Policy, error) { - out := &iap.Policy{} - err := Convert(p, out) - if err != nil { - return nil, errwrap.Wrapf("Cannot convert a resourcemanager policy to am IAP policy: {{err}}", err) - } - return out, nil -} - -func iapToResourceManagerPolicy(p *iap.Policy) (*cloudresourcemanager.Policy, error) { - out := &cloudresourcemanager.Policy{} - err := Convert(p, out) - if err != nil { - return nil, errwrap.Wrapf("Cannot convert an IAP policy to a resourcemanager policy: {{err}}", err) - } - return out, nil -} -<% else %> -// Magic Modules doesn't let us remove files - blank out beta-only common-compile files for now. -<% end -%> diff --git a/third_party/terraform/utils/provider.go.erb b/third_party/terraform/utils/provider.go.erb index 6ee2cf829cb7..680bca862326 100644 --- a/third_party/terraform/utils/provider.go.erb +++ b/third_party/terraform/utils/provider.go.erb @@ -337,9 +337,6 @@ end # products.each do "google_healthcare_hl7_v2_store_iam_binding": ResourceIamBindingWithBatching(IamHealthcareHl7V2StoreSchema, NewHealthcareHl7V2StoreIamUpdater, Hl7V2StoreIdParseFunc, IamBatchingEnabled), "google_healthcare_hl7_v2_store_iam_member": ResourceIamMemberWithBatching(IamHealthcareHl7V2StoreSchema, NewHealthcareHl7V2StoreIamUpdater, Hl7V2StoreIdParseFunc, IamBatchingEnabled), "google_healthcare_hl7_v2_store_iam_policy": ResourceIamPolicy(IamHealthcareHl7V2StoreSchema, NewHealthcareHl7V2StoreIamUpdater, Hl7V2StoreIdParseFunc), - "google_iap_tunnel_instance_iam_binding": ResourceIamBinding(IamIapTunnelInstanceSchema, NewIapTunnelInstanceIamUpdater, IapTunnelInstanceIdParseFunc), - "google_iap_tunnel_instance_iam_member": ResourceIamMember(IamIapTunnelInstanceSchema, NewIapTunnelInstanceIamUpdater, IapTunnelInstanceIdParseFunc), - "google_iap_tunnel_instance_iam_policy": ResourceIamPolicy(IamIapTunnelInstanceSchema, NewIapTunnelInstanceIamUpdater, IapTunnelInstanceIdParseFunc), <% end -%> "google_logging_billing_account_sink": resourceLoggingBillingAccountSink(), "google_logging_billing_account_exclusion": ResourceLoggingExclusion(BillingAccountLoggingExclusionSchema, NewBillingAccountLoggingExclusionUpdater, billingAccountLoggingExclusionIdParseFunc), diff --git a/third_party/terraform/website-compiled/google.erb b/third_party/terraform/website-compiled/google.erb index 28b73da845e5..b115e4652a1d 100644 --- a/third_party/terraform/website-compiled/google.erb +++ b/third_party/terraform/website-compiled/google.erb @@ -1069,17 +1069,15 @@