diff --git a/build/terraform b/build/terraform index 05c0ec1b7f4a..80bd51e5c004 160000 --- a/build/terraform +++ b/build/terraform @@ -1 +1 @@ -Subproject commit 05c0ec1b7f4afa9c70e2f26d9486c1197aeef1c7 +Subproject commit 80bd51e5c0047894fdcf44cdb29e6eab7601a539 diff --git a/provider/terraform/common~copy.yaml b/provider/terraform/common~copy.yaml index 0e7cdeff4ae0..2dd94ffec987 100644 --- a/provider/terraform/common~copy.yaml +++ b/provider/terraform/common~copy.yaml @@ -17,26 +17,26 @@ -%> # Handwritten acceptance tests for autogenerated resources. # Adding them here allows updating the tests as part of a MM pull request. -<% Dir["provider/terraform/tests/*#{api.prefix[1..-1]}*"].each do |file_path| +<% Dir["provider/terraform/tests/*.go"].each do |file_path| fname = file_path.split('/')[-1] -%> '<%= dir -%>/<%= fname -%>': 'provider/terraform/tests/<%= fname -%>' <% end -%> # Copy all of the terraform resources that are still hand written <% - Dir["provider/terraform/resources/*#{api.prefix[1..-1]}*"].each do |file_path| + Dir["provider/terraform/resources/*.go"].each do |file_path| fname = file_path.split('/')[-1] -%> '<%= dir -%>/<%= fname -%>': 'provider/terraform/resources/<%= fname -%>' <% end -%> <% - Dir["provider/terraform/data_sources/*#{api.prefix[1..-1]}*"].each do |file_path| + Dir["provider/terraform/data_sources/*.go"].each do |file_path| fname = file_path.split('/')[-1] -%> '<%= dir -%>/<%= fname -%>': 'provider/terraform/data_sources/<%= fname -%>' <% end -%> <% - Dir["provider/terraform/utils/*"].each do |file_path| + Dir["provider/terraform/utils/*.go"].each do |file_path| fname = file_path.split('/')[-1] -%> '<%= dir -%>/<%= fname -%>': 'provider/terraform/utils/<%= fname -%>' diff --git a/provider/terraform/resources/resource_google_service_account.go b/provider/terraform/resources/resource_google_service_account.go index 14cb347a92cb..2c6672d1c23d 100644 --- a/provider/terraform/resources/resource_google_service_account.go +++ b/provider/terraform/resources/resource_google_service_account.go @@ -15,7 +15,7 @@ func resourceGoogleServiceAccount() *schema.Resource { Delete: resourceGoogleServiceAccountDelete, Update: resourceGoogleServiceAccountUpdate, Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, + State: resourceGoogleServiceAccountImport, }, Schema: map[string]*schema.Schema{ "email": &schema.Schema{ @@ -194,3 +194,20 @@ func saMergeBindings(bindings []*iam.Binding) []*iam.Binding { return rb } + +func resourceGoogleServiceAccountImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + parseImportId([]string{ + "projects/(?P[^/]+)/serviceAccounts/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)", + "(?P[^/]+)"}, d, config) + + // Replace import id for the resource id + id, err := replaceVars(d, config, "projects/{{project}}/serviceAccounts/{{email}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} diff --git a/provider/terraform/tests/resource_google_service_account_test.go b/provider/terraform/tests/resource_google_service_account_test.go new file mode 100644 index 000000000000..251b261abc43 --- /dev/null +++ b/provider/terraform/tests/resource_google_service_account_test.go @@ -0,0 +1,128 @@ +package google + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +// Test that a service account resource can be created, updated, and destroyed +func TestAccServiceAccount_basic(t *testing.T) { + t.Parallel() + + accountId := "a" + acctest.RandString(10) + uniqueId := "" + displayName := "Terraform Test" + displayName2 := "Terraform Test Update" + project := getTestProjectFromEnv() + expectedEmail := fmt.Sprintf("%s@%s.iam.gserviceaccount.com", accountId, project) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + // The first step creates a basic service account + resource.TestStep{ + Config: testAccServiceAccountBasic(accountId, displayName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "google_service_account.acceptance", "project", project), + ), + }, + resource.TestStep{ + ResourceName: "google_service_account.acceptance", + ImportStateId: fmt.Sprintf("projects/%s/serviceAccounts/%s", project, expectedEmail), + ImportState: true, + ImportStateVerify: true, + }, + resource.TestStep{ + ResourceName: "google_service_account.acceptance", + ImportStateId: fmt.Sprintf("%s/%s", project, expectedEmail), + ImportState: true, + ImportStateVerify: true, + }, + resource.TestStep{ + ResourceName: "google_service_account.acceptance", + ImportStateId: expectedEmail, + ImportState: true, + ImportStateVerify: true, + }, + // The second step updates the service account + resource.TestStep{ + Config: testAccServiceAccountBasic(accountId, displayName2), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "google_service_account.acceptance", "project", project), + testAccStoreServiceAccountUniqueId(&uniqueId), + ), + }, + resource.TestStep{ + ResourceName: "google_service_account.acceptance", + ImportState: true, + ImportStateVerify: true, + }, + // The third step explicitely adds the same default project to the service account configuration + // and ensure the service account is not recreated by comparing the value of its unique_id with the one from the previous step + resource.TestStep{ + Config: testAccServiceAccountWithProject(project, accountId, displayName2), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "google_service_account.acceptance", "project", project), + resource.TestCheckResourceAttrPtr( + "google_service_account.acceptance", "unique_id", &uniqueId), + ), + }, + resource.TestStep{ + ResourceName: "google_service_account.acceptance", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccStoreServiceAccountUniqueId(uniqueId *string) resource.TestCheckFunc { + return func(s *terraform.State) error { + *uniqueId = s.RootModule().Resources["google_service_account.acceptance"].Primary.Attributes["unique_id"] + return nil + } +} + +func testAccServiceAccountBasic(account, name string) string { + return fmt.Sprintf(` +resource "google_service_account" "acceptance" { + account_id = "%v" + display_name = "%v" +} +`, account, name) +} + +func testAccServiceAccountWithProject(project, account, name string) string { + return fmt.Sprintf(` +resource "google_service_account" "acceptance" { + project = "%v" + account_id = "%v" + display_name = "%v" +} +`, project, account, name) +} + +func testAccServiceAccountPolicy(account, project string) string { + return fmt.Sprintf(` +resource "google_service_account" "acceptance" { + account_id = "%v" + display_name = "%v" +} + +data "google_iam_policy" "service_account" { + binding { + role = "roles/iam.serviceAccountActor" + members = [ + "serviceAccount:%v@%v.iam.gserviceaccount.com", + ] + } +} +`, account, account, account, project) +}