Skip to content

Commit

Permalink
Add buildServiceAccount to cloudfunctions
Browse files Browse the repository at this point in the history
  • Loading branch information
nifflets committed Jul 2, 2024
1 parent baa5714 commit 1f27296
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 0 deletions.
4 changes: 4 additions & 0 deletions mmv1/products/cloudfunctions/CloudFunction.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ properties:
name: 'serviceAccountEmail'
output: true
description: 'The email of the service account for this function.'
- !ruby/object:Api::Type::String
name: 'buildServiceAccount'
default_from_api: true
description: 'The fully-qualified name of the service account to be used for the build step of deploying this function'
- !ruby/object:Api::Type::String
name: 'updateTime'
output: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,13 @@ func ResourceCloudFunctionsFunction() *schema.Resource {
Description: ` If provided, the self-provided service account to run the function with.`,
},

"build_service_account": {
Type: schema.TypeString,
Optional: true,
Computed: true,
Description: `The fully-qualified name of the service account to be used for the build step of deploying this function`,
},

"vpc_connector": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -627,6 +634,10 @@ func resourceCloudFunctionsCreate(d *schema.ResourceData, meta interface{}) erro
function.MinInstances = int64(v.(int))
}

if v, ok := d.GetOk("build_service_account"); ok {
function.BuildServiceAccount = v.(string)
}

log.Printf("[DEBUG] Creating cloud function: %s", function.Name)

// We retry the whole create-and-wait because Cloud Functions
Expand Down Expand Up @@ -714,6 +725,9 @@ func resourceCloudFunctionsRead(d *schema.ResourceData, meta interface{}) error
if err := d.Set("service_account_email", function.ServiceAccountEmail); err != nil {
return fmt.Errorf("Error setting service_account_email: %s", err)
}
if err := d.Set("build_service_account", function.BuildServiceAccount); err != nil {
return fmt.Errorf("Error setting build_service_account: %s", err)
}
if err := d.Set("environment_variables", function.EnvironmentVariables); err != nil {
return fmt.Errorf("Error setting environment_variables: %s", err)
}
Expand Down Expand Up @@ -945,6 +959,11 @@ func resourceCloudFunctionsUpdate(d *schema.ResourceData, meta interface{}) erro
updateMaskArr = append(updateMaskArr, "minInstances")
}

if d.HasChange("build_service_account") {
function.BuildServiceAccount = d.Get("build_service_account").(string)
updateMaskArr = append(updateMaskArr, "buildServiceAccount")
}

if len(updateMaskArr) > 0 {
log.Printf("[DEBUG] Send Patch CloudFunction Configuration request: %#v", function)
updateMask := strings.Join(updateMaskArr, ",")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,40 @@ func TestAccCloudFunctionsFunction_secretMount(t *testing.T) {
})
}

func TestAccCloudFunctionsFunction_buildServiceAccount(t *testing.T) {
t.Parallel()

funcResourceName := "google_cloudfunctions_function.function"
functionName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10))
bucketName := fmt.Sprintf("tf-test-bucket-%d", acctest.RandInt(t))
zipFilePath := acctest.CreateZIPArchiveForCloudFunctionSource(t, testHTTPTriggerPath)
proj := envvar.GetTestProjectFromEnv()
serviceAccount := fmt.Sprintf("tf-test-build--%s", acctest.RandString(t, 10))
defer os.Remove(zipFilePath) // clean up

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
ExternalProviders: map[string]resource.ExternalProvider{
"time": {},
},
CheckDestroy: testAccCheckCloudFunctionsFunctionDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccCloudFunctionsFunction_buildServiceAccount(functionName, bucketName, zipFilePath, serviceAccount),
Check: resource.TestCheckResourceAttr(funcResourceName,
"build_service_account", fmt.Sprintf("projects/%[1]s/serviceAccounts/%s@%[1]s.iam.gserviceaccount.com", proj, serviceAccount)),
},
{
ResourceName: funcResourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"build_environment_variables"},
},
},
})
}

func testAccCheckCloudFunctionsFunctionDestroyProducer(t *testing.T) func(s *terraform.State) error {
return func(s *terraform.State) error {
config := acctest.GoogleProviderConfig(t)
Expand Down Expand Up @@ -1292,3 +1326,68 @@ resource "google_cloudfunctions_function" "function" {
}
`, accountId, secretName, versionName, bucketName, zipFilePath, functionName, projectNumber, versionNumber)
}

func testAccCloudFunctionsFunction_buildServiceAccount(functionName, bucketName, zipFilePath, serviceAccount string) string {
return fmt.Sprintf(`
data "google_project" "project" {}

resource "google_storage_bucket" "bucket" {
name = "%s"
location = "US"
uniform_bucket_level_access = true
}

resource "google_storage_bucket_object" "archive" {
name = "index.zip"
bucket = google_storage_bucket.bucket.name
source = "%s"
}

resource "google_service_account" "cloud_function_build_account" {
account_id = "%s"
display_name = "Testing Cloud Function build service account"
}

resource "google_project_iam_member" "storage_object_admin" {
project = data.google_project.project.project_id
role = "roles/storage.objectAdmin"
member = "serviceAccount:${google_service_account.cloud_function_build_account.email}"
}

resource "google_project_iam_member" "artifact_registry_writer" {
project = data.google_project.project.project_id
role = "roles/artifactregistry.writer"
member = "serviceAccount:${google_service_account.cloud_function_build_account.email}"
}

resource "google_project_iam_member" "log_writer" {
project = data.google_project.project.project_id
role = "roles/logging.logWriter"
member = "serviceAccount:${google_service_account.cloud_function_build_account.email}"
}

resource "time_sleep" "wait_iam_roles" {
depends_on = [
google_project_iam_member.storage_object_admin,
google_project_iam_member.artifact_registry_writer,
google_project_iam_member.log_writer,
]
create_duration = "60s"
}

resource "google_cloudfunctions_function" "function" {
depends_on = [time_sleep.wait_iam_roles]
name = "%s"
runtime = "nodejs10"

source_archive_bucket = google_storage_bucket.bucket.name
source_archive_object = google_storage_bucket_object.archive.name

build_service_account = google_service_account.cloud_function_build_account.name

trigger_http = true
entry_point = "helloGET"
}
`, bucketName, zipFilePath, serviceAccount, functionName)
}

0 comments on commit 1f27296

Please sign in to comment.