Skip to content

Commit 8f0ed3a

Browse files
Add support for Cloud Run functions by adding support to the BuildConfig V2 API field (#12760)
[upstream:b0626743b659bf02db252fc0801e2930da986f65] Signed-off-by: Modular Magician <[email protected]>
1 parent bdb75d7 commit 8f0ed3a

File tree

5 files changed

+461
-0
lines changed

5 files changed

+461
-0
lines changed

.changelog/12760.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
cloudrunv2: added `build_config` to `google_cloud_run_v2_service`
3+
```

google-beta/services/cloudrunv2/resource_cloud_run_v2_service.go

+254
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,62 @@ Please refer to the field 'effective_annotations' for all of the annotations pre
808808
},
809809
},
810810
},
811+
"build_config": {
812+
Type: schema.TypeList,
813+
Optional: true,
814+
Description: `Configuration for building a Cloud Run function.`,
815+
MaxItems: 1,
816+
Elem: &schema.Resource{
817+
Schema: map[string]*schema.Schema{
818+
"base_image": {
819+
Type: schema.TypeString,
820+
Optional: true,
821+
Description: `The base image used to build the function.`,
822+
},
823+
"enable_automatic_updates": {
824+
Type: schema.TypeBool,
825+
Optional: true,
826+
Description: `Sets whether the function will receive automatic base image updates.`,
827+
},
828+
"environment_variables": {
829+
Type: schema.TypeMap,
830+
Optional: true,
831+
Description: `User-provided build-time environment variables for the function.`,
832+
Elem: &schema.Schema{Type: schema.TypeString},
833+
},
834+
"function_target": {
835+
Type: schema.TypeString,
836+
Optional: true,
837+
Description: `The name of the function (as defined in source code) that will be executed. Defaults to the resource name suffix, if not specified. For backward compatibility, if function with given name is not found, then the system will try to use function named "function".`,
838+
},
839+
"image_uri": {
840+
Type: schema.TypeString,
841+
Optional: true,
842+
Description: `Artifact Registry URI to store the built image.`,
843+
},
844+
"service_account": {
845+
Type: schema.TypeString,
846+
Optional: true,
847+
Description: `Service account to be used for building the container. The format of this field is 'projects/{projectId}/serviceAccounts/{serviceAccountEmail}'.`,
848+
},
849+
"source_location": {
850+
Type: schema.TypeString,
851+
Optional: true,
852+
Description: `The Cloud Storage bucket URI where the function source code is located.`,
853+
},
854+
"worker_pool": {
855+
Type: schema.TypeString,
856+
Optional: true,
857+
Description: `Name of the Cloud Build Custom Worker Pool that should be used to build the Cloud Run function. The format of this field is 'projects/{project}/locations/{region}/workerPools/{workerPool}' where {project} and {region} are the project id and region respectively where the worker pool is defined and {workerPool} is the short name of the worker pool.`,
858+
},
859+
"name": {
860+
Type: schema.TypeString,
861+
Computed: true,
862+
Description: `The Cloud Build name of the latest successful deployment of the function.`,
863+
},
864+
},
865+
},
866+
},
811867
"client": {
812868
Type: schema.TypeString,
813869
Optional: true,
@@ -1305,6 +1361,12 @@ func resourceCloudRunV2ServiceCreate(d *schema.ResourceData, meta interface{}) e
13051361
} else if v, ok := d.GetOkExists("invoker_iam_disabled"); !tpgresource.IsEmptyValue(reflect.ValueOf(invokerIamDisabledProp)) && (ok || !reflect.DeepEqual(v, invokerIamDisabledProp)) {
13061362
obj["invokerIamDisabled"] = invokerIamDisabledProp
13071363
}
1364+
buildConfigProp, err := expandCloudRunV2ServiceBuildConfig(d.Get("build_config"), d, config)
1365+
if err != nil {
1366+
return err
1367+
} else if v, ok := d.GetOkExists("build_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(buildConfigProp)) && (ok || !reflect.DeepEqual(v, buildConfigProp)) {
1368+
obj["buildConfig"] = buildConfigProp
1369+
}
13081370
labelsProp, err := expandCloudRunV2ServiceEffectiveLabels(d.Get("effective_labels"), d, config)
13091371
if err != nil {
13101372
return err
@@ -1519,6 +1581,9 @@ func resourceCloudRunV2ServiceRead(d *schema.ResourceData, meta interface{}) err
15191581
if err := d.Set("urls", flattenCloudRunV2ServiceUrls(res["urls"], d, config)); err != nil {
15201582
return fmt.Errorf("Error reading Service: %s", err)
15211583
}
1584+
if err := d.Set("build_config", flattenCloudRunV2ServiceBuildConfig(res["buildConfig"], d, config)); err != nil {
1585+
return fmt.Errorf("Error reading Service: %s", err)
1586+
}
15221587
if err := d.Set("reconciling", flattenCloudRunV2ServiceReconciling(res["reconciling"], d, config)); err != nil {
15231588
return fmt.Errorf("Error reading Service: %s", err)
15241589
}
@@ -1626,6 +1691,12 @@ func resourceCloudRunV2ServiceUpdate(d *schema.ResourceData, meta interface{}) e
16261691
} else if v, ok := d.GetOkExists("invoker_iam_disabled"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, invokerIamDisabledProp)) {
16271692
obj["invokerIamDisabled"] = invokerIamDisabledProp
16281693
}
1694+
buildConfigProp, err := expandCloudRunV2ServiceBuildConfig(d.Get("build_config"), d, config)
1695+
if err != nil {
1696+
return err
1697+
} else if v, ok := d.GetOkExists("build_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, buildConfigProp)) {
1698+
obj["buildConfig"] = buildConfigProp
1699+
}
16291700
labelsProp, err := expandCloudRunV2ServiceEffectiveLabels(d.Get("effective_labels"), d, config)
16301701
if err != nil {
16311702
return err
@@ -3245,6 +3316,71 @@ func flattenCloudRunV2ServiceUrls(v interface{}, d *schema.ResourceData, config
32453316
return v
32463317
}
32473318

3319+
func flattenCloudRunV2ServiceBuildConfig(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
3320+
if v == nil {
3321+
return nil
3322+
}
3323+
original := v.(map[string]interface{})
3324+
if len(original) == 0 {
3325+
return nil
3326+
}
3327+
transformed := make(map[string]interface{})
3328+
transformed["name"] =
3329+
flattenCloudRunV2ServiceBuildConfigName(original["name"], d, config)
3330+
transformed["source_location"] =
3331+
flattenCloudRunV2ServiceBuildConfigSourceLocation(original["sourceLocation"], d, config)
3332+
transformed["function_target"] =
3333+
flattenCloudRunV2ServiceBuildConfigFunctionTarget(original["functionTarget"], d, config)
3334+
transformed["image_uri"] =
3335+
flattenCloudRunV2ServiceBuildConfigImageUri(original["imageUri"], d, config)
3336+
transformed["base_image"] =
3337+
flattenCloudRunV2ServiceBuildConfigBaseImage(original["baseImage"], d, config)
3338+
transformed["enable_automatic_updates"] =
3339+
flattenCloudRunV2ServiceBuildConfigEnableAutomaticUpdates(original["enableAutomaticUpdates"], d, config)
3340+
transformed["worker_pool"] =
3341+
flattenCloudRunV2ServiceBuildConfigWorkerPool(original["workerPool"], d, config)
3342+
transformed["environment_variables"] =
3343+
flattenCloudRunV2ServiceBuildConfigEnvironmentVariables(original["environmentVariables"], d, config)
3344+
transformed["service_account"] =
3345+
flattenCloudRunV2ServiceBuildConfigServiceAccount(original["serviceAccount"], d, config)
3346+
return []interface{}{transformed}
3347+
}
3348+
func flattenCloudRunV2ServiceBuildConfigName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
3349+
return v
3350+
}
3351+
3352+
func flattenCloudRunV2ServiceBuildConfigSourceLocation(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
3353+
return v
3354+
}
3355+
3356+
func flattenCloudRunV2ServiceBuildConfigFunctionTarget(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
3357+
return v
3358+
}
3359+
3360+
func flattenCloudRunV2ServiceBuildConfigImageUri(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
3361+
return v
3362+
}
3363+
3364+
func flattenCloudRunV2ServiceBuildConfigBaseImage(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
3365+
return v
3366+
}
3367+
3368+
func flattenCloudRunV2ServiceBuildConfigEnableAutomaticUpdates(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
3369+
return v
3370+
}
3371+
3372+
func flattenCloudRunV2ServiceBuildConfigWorkerPool(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
3373+
return v
3374+
}
3375+
3376+
func flattenCloudRunV2ServiceBuildConfigEnvironmentVariables(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
3377+
return v
3378+
}
3379+
3380+
func flattenCloudRunV2ServiceBuildConfigServiceAccount(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
3381+
return v
3382+
}
3383+
32483384
func flattenCloudRunV2ServiceReconciling(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
32493385
return v
32503386
}
@@ -4865,6 +5001,124 @@ func expandCloudRunV2ServiceInvokerIamDisabled(v interface{}, d tpgresource.Terr
48655001
return v, nil
48665002
}
48675003

5004+
func expandCloudRunV2ServiceBuildConfig(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
5005+
l := v.([]interface{})
5006+
if len(l) == 0 || l[0] == nil {
5007+
return nil, nil
5008+
}
5009+
raw := l[0]
5010+
original := raw.(map[string]interface{})
5011+
transformed := make(map[string]interface{})
5012+
5013+
transformedName, err := expandCloudRunV2ServiceBuildConfigName(original["name"], d, config)
5014+
if err != nil {
5015+
return nil, err
5016+
} else if val := reflect.ValueOf(transformedName); val.IsValid() && !tpgresource.IsEmptyValue(val) {
5017+
transformed["name"] = transformedName
5018+
}
5019+
5020+
transformedSourceLocation, err := expandCloudRunV2ServiceBuildConfigSourceLocation(original["source_location"], d, config)
5021+
if err != nil {
5022+
return nil, err
5023+
} else if val := reflect.ValueOf(transformedSourceLocation); val.IsValid() && !tpgresource.IsEmptyValue(val) {
5024+
transformed["sourceLocation"] = transformedSourceLocation
5025+
}
5026+
5027+
transformedFunctionTarget, err := expandCloudRunV2ServiceBuildConfigFunctionTarget(original["function_target"], d, config)
5028+
if err != nil {
5029+
return nil, err
5030+
} else if val := reflect.ValueOf(transformedFunctionTarget); val.IsValid() && !tpgresource.IsEmptyValue(val) {
5031+
transformed["functionTarget"] = transformedFunctionTarget
5032+
}
5033+
5034+
transformedImageUri, err := expandCloudRunV2ServiceBuildConfigImageUri(original["image_uri"], d, config)
5035+
if err != nil {
5036+
return nil, err
5037+
} else if val := reflect.ValueOf(transformedImageUri); val.IsValid() && !tpgresource.IsEmptyValue(val) {
5038+
transformed["imageUri"] = transformedImageUri
5039+
}
5040+
5041+
transformedBaseImage, err := expandCloudRunV2ServiceBuildConfigBaseImage(original["base_image"], d, config)
5042+
if err != nil {
5043+
return nil, err
5044+
} else if val := reflect.ValueOf(transformedBaseImage); val.IsValid() && !tpgresource.IsEmptyValue(val) {
5045+
transformed["baseImage"] = transformedBaseImage
5046+
}
5047+
5048+
transformedEnableAutomaticUpdates, err := expandCloudRunV2ServiceBuildConfigEnableAutomaticUpdates(original["enable_automatic_updates"], d, config)
5049+
if err != nil {
5050+
return nil, err
5051+
} else if val := reflect.ValueOf(transformedEnableAutomaticUpdates); val.IsValid() && !tpgresource.IsEmptyValue(val) {
5052+
transformed["enableAutomaticUpdates"] = transformedEnableAutomaticUpdates
5053+
}
5054+
5055+
transformedWorkerPool, err := expandCloudRunV2ServiceBuildConfigWorkerPool(original["worker_pool"], d, config)
5056+
if err != nil {
5057+
return nil, err
5058+
} else if val := reflect.ValueOf(transformedWorkerPool); val.IsValid() && !tpgresource.IsEmptyValue(val) {
5059+
transformed["workerPool"] = transformedWorkerPool
5060+
}
5061+
5062+
transformedEnvironmentVariables, err := expandCloudRunV2ServiceBuildConfigEnvironmentVariables(original["environment_variables"], d, config)
5063+
if err != nil {
5064+
return nil, err
5065+
} else if val := reflect.ValueOf(transformedEnvironmentVariables); val.IsValid() && !tpgresource.IsEmptyValue(val) {
5066+
transformed["environmentVariables"] = transformedEnvironmentVariables
5067+
}
5068+
5069+
transformedServiceAccount, err := expandCloudRunV2ServiceBuildConfigServiceAccount(original["service_account"], d, config)
5070+
if err != nil {
5071+
return nil, err
5072+
} else if val := reflect.ValueOf(transformedServiceAccount); val.IsValid() && !tpgresource.IsEmptyValue(val) {
5073+
transformed["serviceAccount"] = transformedServiceAccount
5074+
}
5075+
5076+
return transformed, nil
5077+
}
5078+
5079+
func expandCloudRunV2ServiceBuildConfigName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
5080+
return v, nil
5081+
}
5082+
5083+
func expandCloudRunV2ServiceBuildConfigSourceLocation(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
5084+
return v, nil
5085+
}
5086+
5087+
func expandCloudRunV2ServiceBuildConfigFunctionTarget(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
5088+
return v, nil
5089+
}
5090+
5091+
func expandCloudRunV2ServiceBuildConfigImageUri(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
5092+
return v, nil
5093+
}
5094+
5095+
func expandCloudRunV2ServiceBuildConfigBaseImage(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
5096+
return v, nil
5097+
}
5098+
5099+
func expandCloudRunV2ServiceBuildConfigEnableAutomaticUpdates(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
5100+
return v, nil
5101+
}
5102+
5103+
func expandCloudRunV2ServiceBuildConfigWorkerPool(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
5104+
return v, nil
5105+
}
5106+
5107+
func expandCloudRunV2ServiceBuildConfigEnvironmentVariables(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) {
5108+
if v == nil {
5109+
return map[string]string{}, nil
5110+
}
5111+
m := make(map[string]string)
5112+
for k, val := range v.(map[string]interface{}) {
5113+
m[k] = val.(string)
5114+
}
5115+
return m, nil
5116+
}
5117+
5118+
func expandCloudRunV2ServiceBuildConfigServiceAccount(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
5119+
return v, nil
5120+
}
5121+
48685122
func expandCloudRunV2ServiceEffectiveLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) {
48695123
if v == nil {
48705124
return map[string]string{}, nil

google-beta/services/cloudrunv2/resource_cloud_run_v2_service_generated_test.go

+91
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,97 @@ resource "google_cloud_run_v2_service" "default" {
858858
`, context)
859859
}
860860

861+
func TestAccCloudRunV2Service_cloudrunv2ServiceFunctionExample(t *testing.T) {
862+
t.Parallel()
863+
864+
context := map[string]interface{}{
865+
"zip_path": "./test-fixtures/function-source.zip",
866+
"random_suffix": acctest.RandString(t, 10),
867+
}
868+
869+
acctest.VcrTest(t, resource.TestCase{
870+
PreCheck: func() { acctest.AccTestPreCheck(t) },
871+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
872+
CheckDestroy: testAccCheckCloudRunV2ServiceDestroyProducer(t),
873+
Steps: []resource.TestStep{
874+
{
875+
Config: testAccCloudRunV2Service_cloudrunv2ServiceFunctionExample(context),
876+
},
877+
{
878+
ResourceName: "google_cloud_run_v2_service.default",
879+
ImportState: true,
880+
ImportStateVerify: true,
881+
ImportStateVerifyIgnore: []string{"annotations", "deletion_protection", "labels", "location", "name", "terraform_labels"},
882+
},
883+
},
884+
})
885+
}
886+
887+
func testAccCloudRunV2Service_cloudrunv2ServiceFunctionExample(context map[string]interface{}) string {
888+
return acctest.Nprintf(`
889+
resource "google_cloud_run_v2_service" "default" {
890+
name = "tf-test-cloudrun-service%{random_suffix}"
891+
location = "us-central1"
892+
deletion_protection = false
893+
ingress = "INGRESS_TRAFFIC_ALL"
894+
895+
template {
896+
containers {
897+
image = "us-docker.pkg.dev/cloudrun/container/hello"
898+
}
899+
}
900+
build_config {
901+
source_location = "gs://${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name}"
902+
function_target = "helloHttp"
903+
image_uri = "us-docker.pkg.dev/cloudrun/container/hello"
904+
base_image = "us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/nodejs22"
905+
enable_automatic_updates = true
906+
worker_pool = "worker-pool"
907+
environment_variables = {
908+
FOO_KEY = "FOO_VALUE"
909+
BAR_KEY = "BAR_VALUE"
910+
}
911+
service_account = google_service_account.cloudbuild_service_account.id
912+
}
913+
depends_on = [
914+
google_project_iam_member.act_as,
915+
google_project_iam_member.logs_writer
916+
]
917+
}
918+
919+
data "google_project" "project" {
920+
}
921+
922+
resource "google_storage_bucket" "bucket" {
923+
name = "${data.google_project.project.project_id}-tf-test-gcf-source%{random_suffix}" # Every bucket name must be globally unique
924+
location = "US"
925+
uniform_bucket_level_access = true
926+
}
927+
928+
resource "google_storage_bucket_object" "object" {
929+
name = "function-source.zip"
930+
bucket = google_storage_bucket.bucket.name
931+
source = "%{zip_path}" # Add path to the zipped function source code
932+
}
933+
934+
resource "google_service_account" "cloudbuild_service_account" {
935+
account_id = "tf-test-build-sa%{random_suffix}"
936+
}
937+
938+
resource "google_project_iam_member" "act_as" {
939+
project = data.google_project.project.project_id
940+
role = "roles/iam.serviceAccountUser"
941+
member = "serviceAccount:${google_service_account.cloudbuild_service_account.email}"
942+
}
943+
944+
resource "google_project_iam_member" "logs_writer" {
945+
project = data.google_project.project.project_id
946+
role = "roles/logging.logWriter"
947+
member = "serviceAccount:${google_service_account.cloudbuild_service_account.email}"
948+
}
949+
`, context)
950+
}
951+
861952
func testAccCheckCloudRunV2ServiceDestroyProducer(t *testing.T) func(s *terraform.State) error {
862953
return func(s *terraform.State) error {
863954
for name, rs := range s.RootModule().Resources {
Binary file not shown.

0 commit comments

Comments
 (0)