Repository: GoogleCloudPlatform/terraform-validator
Pull request #376 (2021-11-10 20:33:06)

add cloud run resources to terraform validator
child to https://github.com/GoogleCloudPlatform/magic-modules/pull/5440

ScottSuarez: I separated out the iam resources.

I will create a sequential pr once this is checked in. 

Patch:
diff --git a/converters/google/resources/cloudrun_domain_mapping.go b/converters/google/resources/cloudrun_domain_mapping.go
index 7f166167..ca509933 100644
--- a/converters/google/resources/cloudrun_domain_mapping.go
+++ b/converters/google/resources/cloudrun_domain_mapping.go
@@ -43,7 +43,7 @@ func domainMappingLabelDiffSuppress(k, old, new string, d *schema.ResourceData)
 	return false
 }
 
-const CloudRunDomainMappingAssetType string = "{{location}}-run.googleapis.com/DomainMapping"
+const CloudRunDomainMappingAssetType string = "run.googleapis.com/DomainMapping"
 
 func resourceConverterCloudRunDomainMapping() ResourceConverter {
 	return ResourceConverter{
@@ -53,7 +53,7 @@ func resourceConverterCloudRunDomainMapping() ResourceConverter {
 }
 
 func GetCloudRunDomainMappingCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
-	name, err := assetName(d, config, "//{{location}}-run.googleapis.com/apis/domains.cloudrun.com/namespaces/{{project}}/domainmappings/{{name}}")
+	name, err := assetName(d, config, "//run.googleapis.com/projects/{{project}}/locations/{{location}}/DomainMappings/{{name}}")
 	if err != nil {
 		return []Asset{}, err
 	}
@@ -63,7 +63,7 @@ func GetCloudRunDomainMappingCaiObject(d TerraformResourceData, config *Config)
 			Type: CloudRunDomainMappingAssetType,
 			Resource: &AssetResource{
 				Version:              "v1",
-				DiscoveryDocumentURI: "https://www.googleapis.com/discovery/v1/apis/{{location}}-run/v1/rest",
+				DiscoveryDocumentURI: "https://www.googleapis.com/discovery/v1/apis/run/v1/rest",
 				DiscoveryName:        "DomainMapping",
 				Data:                 obj,
 			},
diff --git a/converters/google/resources/cloudrun_service.go b/converters/google/resources/cloudrun_service.go
new file mode 100644
index 00000000..12d0d2ff
--- /dev/null
+++ b/converters/google/resources/cloudrun_service.go
@@ -0,0 +1,1111 @@
+// ----------------------------------------------------------------------------
+//
+//     ***     AUTO GENERATED CODE    ***    Type: MMv1     ***
+//
+// ----------------------------------------------------------------------------
+//
+//     This file is automatically generated by Magic Modules and manual
+//     changes will be clobbered when the file is regenerated.
+//
+//     Please read more about how to change this file in
+//     .github/CONTRIBUTING.md.
+//
+// ----------------------------------------------------------------------------
+
+package google
+
+import (
+	"context"
+	"fmt"
+	"reflect"
+	"regexp"
+	"strings"
+
+	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+func revisionNameCustomizeDiff(_ context.Context, diff *schema.ResourceDiff, v interface{}) error {
+	autogen := diff.Get("autogenerate_revision_name").(bool)
+	if autogen && diff.HasChange("template.0.metadata.0.name") {
+		return fmt.Errorf("google_cloud_run_service: `template.metadata.name` cannot be set while `autogenerate_revision_name` is true. Please remove the field or set `autogenerate_revision_name` to false.")
+	}
+
+	return nil
+}
+
+var cloudRunGoogleProvidedAnnotations = regexp.MustCompile(`serving\.knative\.dev/(?:(?:creator)|(?:lastModifier))$|run\.googleapis\.com/(?:(?:ingress-status))$|cloud\.googleapis\.com/(?:(?:location))`)
+
+func cloudrunAnnotationDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
+	// Suppress diffs for the annotations provided by Google
+	if cloudRunGoogleProvidedAnnotations.MatchString(k) && new == "" {
+		return true
+	}
+
+	// Let diff be determined by annotations (above)
+	if strings.Contains(k, "annotations.%") {
+		return true
+	}
+
+	// For other keys, don't suppress diff.
+	return false
+}
+
+var cloudRunGoogleProvidedTemplateAnnotations = regexp.MustCompile(`template\.0\.metadata\.0\.annotations\.run\.googleapis\.com/sandbox`)
+
+func cloudrunTemplateAnnotationDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
+	// Suppress diffs for the annotations provided by API
+	if cloudRunGoogleProvidedTemplateAnnotations.MatchString(k) &&
+		old == "gvisor" && new == "" {
+		return true
+	}
+
+	// For other keys, don't suppress diff.
+	return false
+}
+
+var cloudRunGoogleProvidedLabels = regexp.MustCompile(`cloud\.googleapis\.com/(?:(?:location))`)
+
+func cloudrunLabelDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
+	// Suppress diffs for the labels provided by Google
+	if cloudRunGoogleProvidedLabels.MatchString(k) && new == "" {
+		return true
+	}
+
+	// Let diff be determined by labels (above)
+	if strings.Contains(k, "labels.%") {
+		return true
+	}
+
+	// For other keys, don't suppress diff.
+	return false
+}
+
+const CloudRunServiceAssetType string = "run.googleapis.com/Service"
+
+func resourceConverterCloudRunService() ResourceConverter {
+	return ResourceConverter{
+		AssetType: CloudRunServiceAssetType,
+		Convert:   GetCloudRunServiceCaiObject,
+	}
+}
+
+func GetCloudRunServiceCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
+	name, err := assetName(d, config, "//run.googleapis.com/projects/{{project}}/locations/{{location}}/services/{{name}}")
+	if err != nil {
+		return []Asset{}, err
+	}
+	if obj, err := GetCloudRunServiceApiObject(d, config); err == nil {
+		return []Asset{{
+			Name: name,
+			Type: CloudRunServiceAssetType,
+			Resource: &AssetResource{
+				Version:              "v1",
+				DiscoveryDocumentURI: "https://www.googleapis.com/discovery/v1/apis/run/v1/rest",
+				DiscoveryName:        "Service",
+				Data:                 obj,
+			},
+		}}, nil
+	} else {
+		return []Asset{}, err
+	}
+}
+
+func GetCloudRunServiceApiObject(d TerraformResourceData, config *Config) (map[string]interface{}, error) {
+	obj := make(map[string]interface{})
+	specProp, err := expandCloudRunServiceSpec(nil, d, config)
+	if err != nil {
+		return nil, err
+	} else if v, ok := d.GetOkExists("spec"); !isEmptyValue(reflect.ValueOf(specProp)) && (ok || !reflect.DeepEqual(v, specProp)) {
+		obj["spec"] = specProp
+	}
+	metadataProp, err := expandCloudRunServiceMetadata(d.Get("metadata"), d, config)
+	if err != nil {
+		return nil, err
+	} else if v, ok := d.GetOkExists("metadata"); !isEmptyValue(reflect.ValueOf(metadataProp)) && (ok || !reflect.DeepEqual(v, metadataProp)) {
+		obj["metadata"] = metadataProp
+	}
+
+	return resourceCloudRunServiceEncoder(d, config, obj)
+}
+
+func resourceCloudRunServiceEncoder(d TerraformResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) {
+	name := d.Get("name").(string)
+	if obj["metadata"] == nil {
+		obj["metadata"] = make(map[string]interface{})
+	}
+	metadata := obj["metadata"].(map[string]interface{})
+	metadata["name"] = name
+
+	// The only acceptable version/kind right now
+	obj["apiVersion"] = "serving.knative.dev/v1"
+	obj["kind"] = "Service"
+	return obj, nil
+}
+
+func expandCloudRunServiceSpec(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	transformed := make(map[string]interface{})
+	transformedTraffic, err := expandCloudRunServiceSpecTraffic(d.Get("traffic"), d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedTraffic); val.IsValid() && !isEmptyValue(val) {
+		transformed["traffic"] = transformedTraffic
+	}
+
+	transformedTemplate, err := expandCloudRunServiceSpecTemplate(d.Get("template"), d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedTemplate); val.IsValid() && !isEmptyValue(val) {
+		transformed["template"] = transformedTemplate
+	}
+
+	return transformed, nil
+}
+
+func expandCloudRunServiceSpecTraffic(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	l := v.([]interface{})
+	req := make([]interface{}, 0, len(l))
+	for _, raw := range l {
+		if raw == nil {
+			continue
+		}
+		original := raw.(map[string]interface{})
+		transformed := make(map[string]interface{})
+
+		transformedRevisionName, err := expandCloudRunServiceSpecTrafficRevisionName(original["revision_name"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedRevisionName); val.IsValid() && !isEmptyValue(val) {
+			transformed["revisionName"] = transformedRevisionName
+		}
+
+		transformedPercent, err := expandCloudRunServiceSpecTrafficPercent(original["percent"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedPercent); val.IsValid() && !isEmptyValue(val) {
+			transformed["percent"] = transformedPercent
+		}
+
+		transformedLatestRevision, err := expandCloudRunServiceSpecTrafficLatestRevision(original["latest_revision"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedLatestRevision); val.IsValid() && !isEmptyValue(val) {
+			transformed["latestRevision"] = transformedLatestRevision
+		}
+
+		req = append(req, transformed)
+	}
+	return req, nil
+}
+
+func expandCloudRunServiceSpecTrafficRevisionName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTrafficPercent(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTrafficLatestRevision(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplate(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	l := v.([]interface{})
+	if len(l) == 0 || l[0] == nil {
+		return nil, nil
+	}
+	raw := l[0]
+	original := raw.(map[string]interface{})
+	transformed := make(map[string]interface{})
+
+	transformedMetadata, err := expandCloudRunServiceSpecTemplateMetadata(original["metadata"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedMetadata); val.IsValid() && !isEmptyValue(val) {
+		transformed["metadata"] = transformedMetadata
+	}
+
+	transformedSpec, err := expandCloudRunServiceSpecTemplateSpec(original["spec"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedSpec); val.IsValid() && !isEmptyValue(val) {
+		transformed["spec"] = transformedSpec
+	}
+
+	return transformed, nil
+}
+
+func expandCloudRunServiceSpecTemplateMetadata(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	l := v.([]interface{})
+	if len(l) == 0 || l[0] == nil {
+		return nil, nil
+	}
+	raw := l[0]
+	original := raw.(map[string]interface{})
+	transformed := make(map[string]interface{})
+
+	transformedLabels, err := expandCloudRunServiceSpecTemplateMetadataLabels(original["labels"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedLabels); val.IsValid() && !isEmptyValue(val) {
+		transformed["labels"] = transformedLabels
+	}
+
+	transformedGeneration, err := expandCloudRunServiceSpecTemplateMetadataGeneration(original["generation"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedGeneration); val.IsValid() && !isEmptyValue(val) {
+		transformed["generation"] = transformedGeneration
+	}
+
+	transformedResourceVersion, err := expandCloudRunServiceSpecTemplateMetadataResourceVersion(original["resource_version"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedResourceVersion); val.IsValid() && !isEmptyValue(val) {
+		transformed["resourceVersion"] = transformedResourceVersion
+	}
+
+	transformedSelfLink, err := expandCloudRunServiceSpecTemplateMetadataSelfLink(original["self_link"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedSelfLink); val.IsValid() && !isEmptyValue(val) {
+		transformed["selfLink"] = transformedSelfLink
+	}
+
+	transformedUid, err := expandCloudRunServiceSpecTemplateMetadataUid(original["uid"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedUid); val.IsValid() && !isEmptyValue(val) {
+		transformed["uid"] = transformedUid
+	}
+
+	transformedNamespace, err := expandCloudRunServiceSpecTemplateMetadataNamespace(original["namespace"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedNamespace); val.IsValid() && !isEmptyValue(val) {
+		transformed["namespace"] = transformedNamespace
+	}
+
+	transformedAnnotations, err := expandCloudRunServiceSpecTemplateMetadataAnnotations(original["annotations"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedAnnotations); val.IsValid() && !isEmptyValue(val) {
+		transformed["annotations"] = transformedAnnotations
+	}
+
+	transformedName, err := expandCloudRunServiceSpecTemplateMetadataName(original["name"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedName); val.IsValid() && !isEmptyValue(val) {
+		transformed["name"] = transformedName
+	}
+
+	return transformed, nil
+}
+
+func expandCloudRunServiceSpecTemplateMetadataLabels(v interface{}, d TerraformResourceData, config *Config) (map[string]string, error) {
+	if v == nil {
+		return map[string]string{}, nil
+	}
+	m := make(map[string]string)
+	for k, val := range v.(map[string]interface{}) {
+		m[k] = val.(string)
+	}
+	return m, nil
+}
+
+func expandCloudRunServiceSpecTemplateMetadataGeneration(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateMetadataResourceVersion(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateMetadataSelfLink(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateMetadataUid(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+// If the property hasn't been explicitly set in config use the project defined by the provider or env.
+func expandCloudRunServiceSpecTemplateMetadataNamespace(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	if v == nil {
+		project, err := getProject(d, config)
+		if err != nil {
+			return project, nil
+		}
+	}
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateMetadataAnnotations(v interface{}, d TerraformResourceData, config *Config) (map[string]string, error) {
+	if v == nil {
+		return map[string]string{}, nil
+	}
+	m := make(map[string]string)
+	for k, val := range v.(map[string]interface{}) {
+		m[k] = val.(string)
+	}
+	return m, nil
+}
+
+func expandCloudRunServiceSpecTemplateMetadataName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	if d.Get("autogenerate_revision_name") == true {
+		return nil, nil
+	}
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpec(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	l := v.([]interface{})
+	if len(l) == 0 || l[0] == nil {
+		return nil, nil
+	}
+	raw := l[0]
+	original := raw.(map[string]interface{})
+	transformed := make(map[string]interface{})
+
+	transformedContainers, err := expandCloudRunServiceSpecTemplateSpecContainers(original["containers"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedContainers); val.IsValid() && !isEmptyValue(val) {
+		transformed["containers"] = transformedContainers
+	}
+
+	transformedContainerConcurrency, err := expandCloudRunServiceSpecTemplateSpecContainerConcurrency(original["container_concurrency"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedContainerConcurrency); val.IsValid() && !isEmptyValue(val) {
+		transformed["containerConcurrency"] = transformedContainerConcurrency
+	}
+
+	transformedTimeoutSeconds, err := expandCloudRunServiceSpecTemplateSpecTimeoutSeconds(original["timeout_seconds"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedTimeoutSeconds); val.IsValid() && !isEmptyValue(val) {
+		transformed["timeoutSeconds"] = transformedTimeoutSeconds
+	}
+
+	transformedServiceAccountName, err := expandCloudRunServiceSpecTemplateSpecServiceAccountName(original["service_account_name"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedServiceAccountName); val.IsValid() && !isEmptyValue(val) {
+		transformed["serviceAccountName"] = transformedServiceAccountName
+	}
+
+	transformedVolumes, err := expandCloudRunServiceSpecTemplateSpecVolumes(original["volumes"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedVolumes); val.IsValid() && !isEmptyValue(val) {
+		transformed["volumes"] = transformedVolumes
+	}
+
+	transformedServingState, err := expandCloudRunServiceSpecTemplateSpecServingState(original["serving_state"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedServingState); val.IsValid() && !isEmptyValue(val) {
+		transformed["servingState"] = transformedServingState
+	}
+
+	return transformed, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainers(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	l := v.([]interface{})
+	req := make([]interface{}, 0, len(l))
+	for _, raw := range l {
+		if raw == nil {
+			continue
+		}
+		original := raw.(map[string]interface{})
+		transformed := make(map[string]interface{})
+
+		transformedWorkingDir, err := expandCloudRunServiceSpecTemplateSpecContainersWorkingDir(original["working_dir"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedWorkingDir); val.IsValid() && !isEmptyValue(val) {
+			transformed["workingDir"] = transformedWorkingDir
+		}
+
+		transformedArgs, err := expandCloudRunServiceSpecTemplateSpecContainersArgs(original["args"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedArgs); val.IsValid() && !isEmptyValue(val) {
+			transformed["args"] = transformedArgs
+		}
+
+		transformedEnvFrom, err := expandCloudRunServiceSpecTemplateSpecContainersEnvFrom(original["env_from"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedEnvFrom); val.IsValid() && !isEmptyValue(val) {
+			transformed["envFrom"] = transformedEnvFrom
+		}
+
+		transformedImage, err := expandCloudRunServiceSpecTemplateSpecContainersImage(original["image"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedImage); val.IsValid() && !isEmptyValue(val) {
+			transformed["image"] = transformedImage
+		}
+
+		transformedCommand, err := expandCloudRunServiceSpecTemplateSpecContainersCommand(original["command"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedCommand); val.IsValid() && !isEmptyValue(val) {
+			transformed["command"] = transformedCommand
+		}
+
+		transformedEnv, err := expandCloudRunServiceSpecTemplateSpecContainersEnv(original["env"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedEnv); val.IsValid() && !isEmptyValue(val) {
+			transformed["env"] = transformedEnv
+		}
+
+		transformedPorts, err := expandCloudRunServiceSpecTemplateSpecContainersPorts(original["ports"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedPorts); val.IsValid() && !isEmptyValue(val) {
+			transformed["ports"] = transformedPorts
+		}
+
+		transformedResources, err := expandCloudRunServiceSpecTemplateSpecContainersResources(original["resources"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedResources); val.IsValid() && !isEmptyValue(val) {
+			transformed["resources"] = transformedResources
+		}
+
+		transformedVolumeMounts, err := expandCloudRunServiceSpecTemplateSpecContainersVolumeMounts(original["volume_mounts"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedVolumeMounts); val.IsValid() && !isEmptyValue(val) {
+			transformed["volumeMounts"] = transformedVolumeMounts
+		}
+
+		req = append(req, transformed)
+	}
+	return req, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersWorkingDir(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersArgs(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersEnvFrom(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	l := v.([]interface{})
+	req := make([]interface{}, 0, len(l))
+	for _, raw := range l {
+		if raw == nil {
+			continue
+		}
+		original := raw.(map[string]interface{})
+		transformed := make(map[string]interface{})
+
+		transformedPrefix, err := expandCloudRunServiceSpecTemplateSpecContainersEnvFromPrefix(original["prefix"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedPrefix); val.IsValid() && !isEmptyValue(val) {
+			transformed["prefix"] = transformedPrefix
+		}
+
+		transformedConfigMapRef, err := expandCloudRunServiceSpecTemplateSpecContainersEnvFromConfigMapRef(original["config_map_ref"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedConfigMapRef); val.IsValid() && !isEmptyValue(val) {
+			transformed["configMapRef"] = transformedConfigMapRef
+		}
+
+		transformedSecretRef, err := expandCloudRunServiceSpecTemplateSpecContainersEnvFromSecretRef(original["secret_ref"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedSecretRef); val.IsValid() && !isEmptyValue(val) {
+			transformed["secretRef"] = transformedSecretRef
+		}
+
+		req = append(req, transformed)
+	}
+	return req, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersEnvFromPrefix(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersEnvFromConfigMapRef(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	l := v.([]interface{})
+	if len(l) == 0 || l[0] == nil {
+		return nil, nil
+	}
+	raw := l[0]
+	original := raw.(map[string]interface{})
+	transformed := make(map[string]interface{})
+
+	transformedOptional, err := expandCloudRunServiceSpecTemplateSpecContainersEnvFromConfigMapRefOptional(original["optional"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedOptional); val.IsValid() && !isEmptyValue(val) {
+		transformed["optional"] = transformedOptional
+	}
+
+	transformedLocalObjectReference, err := expandCloudRunServiceSpecTemplateSpecContainersEnvFromConfigMapRefLocalObjectReference(original["local_object_reference"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedLocalObjectReference); val.IsValid() && !isEmptyValue(val) {
+		transformed["localObjectReference"] = transformedLocalObjectReference
+	}
+
+	return transformed, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersEnvFromConfigMapRefOptional(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersEnvFromConfigMapRefLocalObjectReference(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	l := v.([]interface{})
+	if len(l) == 0 || l[0] == nil {
+		return nil, nil
+	}
+	raw := l[0]
+	original := raw.(map[string]interface{})
+	transformed := make(map[string]interface{})
+
+	transformedName, err := expandCloudRunServiceSpecTemplateSpecContainersEnvFromConfigMapRefLocalObjectReferenceName(original["name"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedName); val.IsValid() && !isEmptyValue(val) {
+		transformed["name"] = transformedName
+	}
+
+	return transformed, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersEnvFromConfigMapRefLocalObjectReferenceName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersEnvFromSecretRef(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	l := v.([]interface{})
+	if len(l) == 0 || l[0] == nil {
+		return nil, nil
+	}
+	raw := l[0]
+	original := raw.(map[string]interface{})
+	transformed := make(map[string]interface{})
+
+	transformedLocalObjectReference, err := expandCloudRunServiceSpecTemplateSpecContainersEnvFromSecretRefLocalObjectReference(original["local_object_reference"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedLocalObjectReference); val.IsValid() && !isEmptyValue(val) {
+		transformed["localObjectReference"] = transformedLocalObjectReference
+	}
+
+	transformedOptional, err := expandCloudRunServiceSpecTemplateSpecContainersEnvFromSecretRefOptional(original["optional"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedOptional); val.IsValid() && !isEmptyValue(val) {
+		transformed["optional"] = transformedOptional
+	}
+
+	return transformed, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersEnvFromSecretRefLocalObjectReference(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	l := v.([]interface{})
+	if len(l) == 0 || l[0] == nil {
+		return nil, nil
+	}
+	raw := l[0]
+	original := raw.(map[string]interface{})
+	transformed := make(map[string]interface{})
+
+	transformedName, err := expandCloudRunServiceSpecTemplateSpecContainersEnvFromSecretRefLocalObjectReferenceName(original["name"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedName); val.IsValid() && !isEmptyValue(val) {
+		transformed["name"] = transformedName
+	}
+
+	return transformed, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersEnvFromSecretRefLocalObjectReferenceName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersEnvFromSecretRefOptional(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersImage(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersCommand(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersEnv(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	v = v.(*schema.Set).List()
+	l := v.([]interface{})
+	req := make([]interface{}, 0, len(l))
+	for _, raw := range l {
+		if raw == nil {
+			continue
+		}
+		original := raw.(map[string]interface{})
+		transformed := make(map[string]interface{})
+
+		transformedName, err := expandCloudRunServiceSpecTemplateSpecContainersEnvName(original["name"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedName); val.IsValid() && !isEmptyValue(val) {
+			transformed["name"] = transformedName
+		}
+
+		transformedValue, err := expandCloudRunServiceSpecTemplateSpecContainersEnvValue(original["value"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedValue); val.IsValid() && !isEmptyValue(val) {
+			transformed["value"] = transformedValue
+		}
+
+		transformedValueFrom, err := expandCloudRunServiceSpecTemplateSpecContainersEnvValueFrom(original["value_from"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedValueFrom); val.IsValid() && !isEmptyValue(val) {
+			transformed["valueFrom"] = transformedValueFrom
+		}
+
+		req = append(req, transformed)
+	}
+	return req, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersEnvName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersEnvValue(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersEnvValueFrom(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	l := v.([]interface{})
+	if len(l) == 0 || l[0] == nil {
+		return nil, nil
+	}
+	raw := l[0]
+	original := raw.(map[string]interface{})
+	transformed := make(map[string]interface{})
+
+	transformedSecretKeyRef, err := expandCloudRunServiceSpecTemplateSpecContainersEnvValueFromSecretKeyRef(original["secret_key_ref"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedSecretKeyRef); val.IsValid() && !isEmptyValue(val) {
+		transformed["secretKeyRef"] = transformedSecretKeyRef
+	}
+
+	return transformed, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersEnvValueFromSecretKeyRef(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	l := v.([]interface{})
+	if len(l) == 0 || l[0] == nil {
+		return nil, nil
+	}
+	raw := l[0]
+	original := raw.(map[string]interface{})
+	transformed := make(map[string]interface{})
+
+	transformedKey, err := expandCloudRunServiceSpecTemplateSpecContainersEnvValueFromSecretKeyRefKey(original["key"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedKey); val.IsValid() && !isEmptyValue(val) {
+		transformed["key"] = transformedKey
+	}
+
+	transformedName, err := expandCloudRunServiceSpecTemplateSpecContainersEnvValueFromSecretKeyRefName(original["name"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedName); val.IsValid() && !isEmptyValue(val) {
+		transformed["name"] = transformedName
+	}
+
+	return transformed, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersEnvValueFromSecretKeyRefKey(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersEnvValueFromSecretKeyRefName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersPorts(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	l := v.([]interface{})
+	req := make([]interface{}, 0, len(l))
+	for _, raw := range l {
+		if raw == nil {
+			continue
+		}
+		original := raw.(map[string]interface{})
+		transformed := make(map[string]interface{})
+
+		transformedName, err := expandCloudRunServiceSpecTemplateSpecContainersPortsName(original["name"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedName); val.IsValid() && !isEmptyValue(val) {
+			transformed["name"] = transformedName
+		}
+
+		transformedProtocol, err := expandCloudRunServiceSpecTemplateSpecContainersPortsProtocol(original["protocol"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedProtocol); val.IsValid() && !isEmptyValue(val) {
+			transformed["protocol"] = transformedProtocol
+		}
+
+		transformedContainerPort, err := expandCloudRunServiceSpecTemplateSpecContainersPortsContainerPort(original["container_port"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedContainerPort); val.IsValid() && !isEmptyValue(val) {
+			transformed["containerPort"] = transformedContainerPort
+		}
+
+		req = append(req, transformed)
+	}
+	return req, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersPortsName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersPortsProtocol(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersPortsContainerPort(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersResources(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	l := v.([]interface{})
+	if len(l) == 0 || l[0] == nil {
+		return nil, nil
+	}
+	raw := l[0]
+	original := raw.(map[string]interface{})
+	transformed := make(map[string]interface{})
+
+	transformedLimits, err := expandCloudRunServiceSpecTemplateSpecContainersResourcesLimits(original["limits"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedLimits); val.IsValid() && !isEmptyValue(val) {
+		transformed["limits"] = transformedLimits
+	}
+
+	transformedRequests, err := expandCloudRunServiceSpecTemplateSpecContainersResourcesRequests(original["requests"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedRequests); val.IsValid() && !isEmptyValue(val) {
+		transformed["requests"] = transformedRequests
+	}
+
+	return transformed, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersResourcesLimits(v interface{}, d TerraformResourceData, config *Config) (map[string]string, error) {
+	if v == nil {
+		return map[string]string{}, nil
+	}
+	m := make(map[string]string)
+	for k, val := range v.(map[string]interface{}) {
+		m[k] = val.(string)
+	}
+	return m, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersResourcesRequests(v interface{}, d TerraformResourceData, config *Config) (map[string]string, error) {
+	if v == nil {
+		return map[string]string{}, nil
+	}
+	m := make(map[string]string)
+	for k, val := range v.(map[string]interface{}) {
+		m[k] = val.(string)
+	}
+	return m, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersVolumeMounts(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	l := v.([]interface{})
+	req := make([]interface{}, 0, len(l))
+	for _, raw := range l {
+		if raw == nil {
+			continue
+		}
+		original := raw.(map[string]interface{})
+		transformed := make(map[string]interface{})
+
+		transformedMountPath, err := expandCloudRunServiceSpecTemplateSpecContainersVolumeMountsMountPath(original["mount_path"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedMountPath); val.IsValid() && !isEmptyValue(val) {
+			transformed["mountPath"] = transformedMountPath
+		}
+
+		transformedName, err := expandCloudRunServiceSpecTemplateSpecContainersVolumeMountsName(original["name"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedName); val.IsValid() && !isEmptyValue(val) {
+			transformed["name"] = transformedName
+		}
+
+		req = append(req, transformed)
+	}
+	return req, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersVolumeMountsMountPath(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainersVolumeMountsName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecContainerConcurrency(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecTimeoutSeconds(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecServiceAccountName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecVolumes(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	l := v.([]interface{})
+	req := make([]interface{}, 0, len(l))
+	for _, raw := range l {
+		if raw == nil {
+			continue
+		}
+		original := raw.(map[string]interface{})
+		transformed := make(map[string]interface{})
+
+		transformedName, err := expandCloudRunServiceSpecTemplateSpecVolumesName(original["name"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedName); val.IsValid() && !isEmptyValue(val) {
+			transformed["name"] = transformedName
+		}
+
+		transformedSecret, err := expandCloudRunServiceSpecTemplateSpecVolumesSecret(original["secret"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedSecret); val.IsValid() && !isEmptyValue(val) {
+			transformed["secret"] = transformedSecret
+		}
+
+		req = append(req, transformed)
+	}
+	return req, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecVolumesName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecVolumesSecret(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	l := v.([]interface{})
+	if len(l) == 0 || l[0] == nil {
+		return nil, nil
+	}
+	raw := l[0]
+	original := raw.(map[string]interface{})
+	transformed := make(map[string]interface{})
+
+	transformedSecretName, err := expandCloudRunServiceSpecTemplateSpecVolumesSecretSecretName(original["secret_name"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedSecretName); val.IsValid() && !isEmptyValue(val) {
+		transformed["secretName"] = transformedSecretName
+	}
+
+	transformedItems, err := expandCloudRunServiceSpecTemplateSpecVolumesSecretItems(original["items"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedItems); val.IsValid() && !isEmptyValue(val) {
+		transformed["items"] = transformedItems
+	}
+
+	return transformed, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecVolumesSecretSecretName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecVolumesSecretItems(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	l := v.([]interface{})
+	req := make([]interface{}, 0, len(l))
+	for _, raw := range l {
+		if raw == nil {
+			continue
+		}
+		original := raw.(map[string]interface{})
+		transformed := make(map[string]interface{})
+
+		transformedKey, err := expandCloudRunServiceSpecTemplateSpecVolumesSecretItemsKey(original["key"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedKey); val.IsValid() && !isEmptyValue(val) {
+			transformed["key"] = transformedKey
+		}
+
+		transformedPath, err := expandCloudRunServiceSpecTemplateSpecVolumesSecretItemsPath(original["path"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedPath); val.IsValid() && !isEmptyValue(val) {
+			transformed["path"] = transformedPath
+		}
+
+		req = append(req, transformed)
+	}
+	return req, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecVolumesSecretItemsKey(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecVolumesSecretItemsPath(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceSpecTemplateSpecServingState(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceMetadata(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	l := v.([]interface{})
+	if len(l) == 0 || l[0] == nil {
+		return nil, nil
+	}
+	raw := l[0]
+	original := raw.(map[string]interface{})
+	transformed := make(map[string]interface{})
+
+	transformedLabels, err := expandCloudRunServiceMetadataLabels(original["labels"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedLabels); val.IsValid() && !isEmptyValue(val) {
+		transformed["labels"] = transformedLabels
+	}
+
+	transformedGeneration, err := expandCloudRunServiceMetadataGeneration(original["generation"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedGeneration); val.IsValid() && !isEmptyValue(val) {
+		transformed["generation"] = transformedGeneration
+	}
+
+	transformedResourceVersion, err := expandCloudRunServiceMetadataResourceVersion(original["resource_version"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedResourceVersion); val.IsValid() && !isEmptyValue(val) {
+		transformed["resourceVersion"] = transformedResourceVersion
+	}
+
+	transformedSelfLink, err := expandCloudRunServiceMetadataSelfLink(original["self_link"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedSelfLink); val.IsValid() && !isEmptyValue(val) {
+		transformed["selfLink"] = transformedSelfLink
+	}
+
+	transformedUid, err := expandCloudRunServiceMetadataUid(original["uid"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedUid); val.IsValid() && !isEmptyValue(val) {
+		transformed["uid"] = transformedUid
+	}
+
+	transformedNamespace, err := expandCloudRunServiceMetadataNamespace(original["namespace"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedNamespace); val.IsValid() && !isEmptyValue(val) {
+		transformed["namespace"] = transformedNamespace
+	}
+
+	transformedAnnotations, err := expandCloudRunServiceMetadataAnnotations(original["annotations"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedAnnotations); val.IsValid() && !isEmptyValue(val) {
+		transformed["annotations"] = transformedAnnotations
+	}
+
+	return transformed, nil
+}
+
+func expandCloudRunServiceMetadataLabels(v interface{}, d TerraformResourceData, config *Config) (map[string]string, error) {
+	if v == nil {
+		return map[string]string{}, nil
+	}
+	m := make(map[string]string)
+	for k, val := range v.(map[string]interface{}) {
+		m[k] = val.(string)
+	}
+	return m, nil
+}
+
+func expandCloudRunServiceMetadataGeneration(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceMetadataResourceVersion(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceMetadataSelfLink(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandCloudRunServiceMetadataUid(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+// If the property hasn't been explicitly set in config use the project defined by the provider or env.
+func expandCloudRunServiceMetadataNamespace(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	if v == nil {
+		project, err := getProject(d, config)
+		if err != nil {
+			return project, nil
+		}
+	}
+	return v, nil
+}
+
+func expandCloudRunServiceMetadataAnnotations(v interface{}, d TerraformResourceData, config *Config) (map[string]string, error) {
+	if v == nil {
+		return map[string]string{}, nil
+	}
+	m := make(map[string]string)
+	for k, val := range v.(map[string]interface{}) {
+		m[k] = val.(string)
+	}
+	return m, nil
+}
diff --git a/converters/google/resources/resource_converters.go b/converters/google/resources/resource_converters.go
index c0c8d9dd..9553cce5 100644
--- a/converters/google/resources/resource_converters.go
+++ b/converters/google/resources/resource_converters.go
@@ -48,6 +48,8 @@ func ResourceConverters() map[string][]ResourceConverter {
 		"google_kms_key_ring":                              {resourceConverterKMSKeyRing()},
 		"google_filestore_instance":                        {resourceConverterFilestoreInstance()},
 		"google_access_context_manager_service_perimeter":  {resourceConverterAccessContextManagerServicePerimeter()},
+		"google_cloud_run_service":                         {resourceConverterCloudRunService()},
+		"google_cloud_run_domain_mapping":                  {resourceConverterCloudRunDomainMapping()},
 		"google_bigquery_table_iam_policy":                 {resourceConverterBigQueryTableIamPolicy()},
 		"google_bigquery_table_iam_binding":                {resourceConverterBigQueryTableIamBinding()},
 		"google_bigquery_table_iam_member":                 {resourceConverterBigQueryTableIamMember()},


Test patch:
diff --git a/test/cli_test.go b/test/cli_test.go
index 5ae04558..eeba465e 100644
--- a/test/cli_test.go
+++ b/test/cli_test.go
@@ -65,6 +65,8 @@ func TestCLI(t *testing.T) {
 		{name: "example_bigquery_dataset_iam_binding"},
 		{name: "example_bigquery_dataset_iam_member"},
 		{name: "example_bigtable_instance"},
+		{name: "example_cloud_run_mapping"},
+		{name: "example_cloud_run_service"},
 		{name: "example_compute_disk"},
 		{name: "example_compute_disk_empty_image"},
 		{name: "example_compute_firewall"},
diff --git a/test/read_test.go b/test/read_test.go
index ceafb466..619061d3 100644
--- a/test/read_test.go
+++ b/test/read_test.go
@@ -26,6 +26,8 @@ func TestReadPlannedAssetsCoverage(t *testing.T) {
 		{name: "example_bigquery_dataset_iam_binding"},
 		{name: "example_bigquery_dataset_iam_member"},
 		{name: "example_bigtable_instance"},
+		{name: "example_cloud_run_mapping"},
+		{name: "example_cloud_run_service"},
 		{name: "example_compute_disk"},
 		{name: "example_compute_disk_empty_image"},
 		{name: "example_compute_firewall"},
diff --git a/testdata/templates/example_cloud_run_mapping.json b/testdata/templates/example_cloud_run_mapping.json
new file mode 100644
index 00000000..43729c4f
--- /dev/null
+++ b/testdata/templates/example_cloud_run_mapping.json
@@ -0,0 +1,55 @@
+[
+  {
+    "name": "//run.googleapis.com/projects/{{.Provider.project}}/locations/us-central1/DomainMappings/tf-test-domain-meep.gcp.tfacc.hashicorptest.com",
+    "asset_type": "run.googleapis.com/DomainMapping",
+    "ancestry_path": "organization/{{.OrgID}}/folder/{{.FolderID}}/project/{{.Provider.project}}",
+    "resource": {
+      "version": "v1",
+      "discovery_document_uri": "https://www.googleapis.com/discovery/v1/apis/run/v1/rest",
+      "discovery_name": "DomainMapping",
+      "parent": "//cloudresourcemanager.googleapis.com/projects/{{.Provider.project}}",
+      "data": {
+        "apiVersion": "domains.cloudrun.com/v1",
+        "kind": "DomainMapping",
+        "metadata": {
+          "name": "tf-test-domain-meep.gcp.tfacc.hashicorptest.com",
+          "namespace": "{{.Provider.project}}"
+        },
+        "spec": {
+          "certificateMode": "AUTOMATIC",
+          "routeName": "tf-test-cloudrun-srv-beep"
+        }
+      }
+    }
+  },
+  {
+    "name": "//run.googleapis.com/projects/{{.Provider.project}}/locations/us-central1/services/tf-test-cloudrun-srv-beep",
+    "asset_type": "run.googleapis.com/Service",
+    "ancestry_path": "organization/{{.OrgID}}/folder/{{.FolderID}}/project/{{.Provider.project}}",
+    "resource": {
+      "version": "v1",
+      "discovery_document_uri": "https://www.googleapis.com/discovery/v1/apis/run/v1/rest",
+      "discovery_name": "Service",
+      "parent": "//cloudresourcemanager.googleapis.com/projects/{{.Provider.project}}",
+      "data": {
+        "apiVersion": "serving.knative.dev/v1",
+        "kind": "Service",
+        "metadata": {
+          "name": "tf-test-cloudrun-srv-beep",
+          "namespace": "{{.Provider.project}}"
+        },
+        "spec": {
+          "template": {
+            "spec": {
+              "containers": [
+                {
+                  "image": "us-docker.pkg.dev/cloudrun/container/hello"
+                }
+              ]
+            }
+          }
+        }
+      }
+    }
+  }
+]
diff --git a/testdata/templates/example_cloud_run_mapping.tf b/testdata/templates/example_cloud_run_mapping.tf
new file mode 100644
index 00000000..4c721b01
--- /dev/null
+++ b/testdata/templates/example_cloud_run_mapping.tf
@@ -0,0 +1,61 @@
+/**
+ * Copyright 2021 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+terraform {
+  required_providers {
+    google = {
+      source = "hashicorp/google"
+      version = "~> {{.Provider.version}}"
+    }
+  }
+}
+
+provider "google" {
+  {{if .Provider.credentials }}credentials = "{{.Provider.credentials}}"{{end}}
+}
+
+
+resource "google_cloud_run_service" "default" {
+    name     = "tf-test-cloudrun-srv-beep"
+    location = "us-central1"
+    project  = "{{.Provider.project}}"
+
+    metadata {
+      namespace = "{{.Provider.project}}"
+    }
+
+    template {
+      spec {
+        containers {
+          image = "us-docker.pkg.dev/cloudrun/container/hello"
+        }
+      }
+    }
+  }
+
+resource "google_cloud_run_domain_mapping" "default" {
+  location = "us-central1"
+  name     = "tf-test-domain-meep.gcp.tfacc.hashicorptest.com"
+  project  = "{{.Provider.project}}"
+
+  metadata {
+    namespace = "{{.Provider.project}}"
+  }
+
+  spec {
+    route_name = google_cloud_run_service.default.name
+  }
+}
\ No newline at end of file
diff --git a/testdata/templates/example_cloud_run_mapping.tfplan.json b/testdata/templates/example_cloud_run_mapping.tfplan.json
new file mode 100644
index 00000000..45f71af0
--- /dev/null
+++ b/testdata/templates/example_cloud_run_mapping.tfplan.json
@@ -0,0 +1,286 @@
+{
+  "format_version": "0.1",
+  "terraform_version": "0.13.4",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_cloud_run_domain_mapping.default",
+          "mode": "managed",
+          "type": "google_cloud_run_domain_mapping",
+          "name": "default",
+          "provider_name": "registry.terraform.io/hashicorp/google",
+          "schema_version": 0,
+          "values": {
+            "location": "us-central1",
+            "metadata": [
+              {
+                "namespace": "{{.Provider.project}}"
+              }
+            ],
+            "name": "tf-test-domain-meep.gcp.tfacc.hashicorptest.com",
+            "project": "{{.Provider.project}}",
+            "spec": [
+              {
+                "certificate_mode": "AUTOMATIC",
+                "force_override": null,
+                "route_name": "tf-test-cloudrun-srv-beep"
+              }
+            ],
+            "timeouts": null
+          }
+        },
+        {
+          "address": "google_cloud_run_service.default",
+          "mode": "managed",
+          "type": "google_cloud_run_service",
+          "name": "default",
+          "provider_name": "registry.terraform.io/hashicorp/google",
+          "schema_version": 1,
+          "values": {
+            "autogenerate_revision_name": false,
+            "location": "us-central1",
+            "metadata": [
+              {
+                "namespace": "{{.Provider.project}}"
+              }
+            ],
+            "name": "tf-test-cloudrun-srv-beep",
+            "project": "{{.Provider.project}}",
+            "template": [
+              {
+                "spec": [
+                  {
+                    "containers": [
+                      {
+                        "args": null,
+                        "command": null,
+                        "env": [],
+                        "env_from": [],
+                        "image": "us-docker.pkg.dev/cloudrun/container/hello",
+                        "working_dir": null
+                      }
+                    ],
+                    "service_account_name": null
+                  }
+                ]
+              }
+            ],
+            "timeouts": null
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "google_cloud_run_domain_mapping.default",
+      "mode": "managed",
+      "type": "google_cloud_run_domain_mapping",
+      "name": "default",
+      "provider_name": "registry.terraform.io/hashicorp/google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "location": "us-central1",
+          "metadata": [
+            {
+              "namespace": "{{.Provider.project}}"
+            }
+          ],
+          "name": "tf-test-domain-meep.gcp.tfacc.hashicorptest.com",
+          "project": "{{.Provider.project}}",
+          "spec": [
+            {
+              "certificate_mode": "AUTOMATIC",
+              "force_override": null,
+              "route_name": "tf-test-cloudrun-srv-beep"
+            }
+          ],
+          "timeouts": null
+        },
+        "after_unknown": {
+          "id": true,
+          "metadata": [
+            {
+              "annotations": true,
+              "generation": true,
+              "labels": true,
+              "resource_version": true,
+              "self_link": true,
+              "uid": true
+            }
+          ],
+          "spec": [
+            {}
+          ],
+          "status": true
+        }
+      }
+    },
+    {
+      "address": "google_cloud_run_service.default",
+      "mode": "managed",
+      "type": "google_cloud_run_service",
+      "name": "default",
+      "provider_name": "registry.terraform.io/hashicorp/google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "autogenerate_revision_name": false,
+          "location": "us-central1",
+          "metadata": [
+            {
+              "namespace": "{{.Provider.project}}"
+            }
+          ],
+          "name": "tf-test-cloudrun-srv-beep",
+          "project": "{{.Provider.project}}",
+          "template": [
+            {
+              "spec": [
+                {
+                  "containers": [
+                    {
+                      "args": null,
+                      "command": null,
+                      "env": [],
+                      "env_from": [],
+                      "image": "us-docker.pkg.dev/cloudrun/container/hello",
+                      "working_dir": null
+                    }
+                  ],
+                  "service_account_name": null
+                }
+              ]
+            }
+          ],
+          "timeouts": null
+        },
+        "after_unknown": {
+          "id": true,
+          "metadata": [
+            {
+              "annotations": true,
+              "generation": true,
+              "labels": true,
+              "resource_version": true,
+              "self_link": true,
+              "uid": true
+            }
+          ],
+          "status": true,
+          "template": [
+            {
+              "metadata": true,
+              "spec": [
+                {
+                  "container_concurrency": true,
+                  "containers": [
+                    {
+                      "env": [],
+                      "env_from": [],
+                      "ports": true,
+                      "resources": true
+                    }
+                  ],
+                  "serving_state": true,
+                  "timeout_seconds": true
+                }
+              ]
+            }
+          ],
+          "traffic": true
+        }
+      }
+    }
+  ],
+  "configuration": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_cloud_run_domain_mapping.default",
+          "mode": "managed",
+          "type": "google_cloud_run_domain_mapping",
+          "name": "default",
+          "provider_config_key": "google",
+          "expressions": {
+            "location": {
+              "constant_value": "us-central1"
+            },
+            "metadata": [
+              {
+                "namespace": {
+                  "constant_value": "{{.Provider.project}}"
+                }
+              }
+            ],
+            "name": {
+              "constant_value": "tf-test-domain-meep.gcp.tfacc.hashicorptest.com"
+            },
+            "project": {
+              "constant_value": "{{.Provider.project}}"
+            },
+            "spec": [
+              {
+                "route_name": {
+                  "references": [
+                    "google_cloud_run_service.default"
+                  ]
+                }
+              }
+            ]
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "google_cloud_run_service.default",
+          "mode": "managed",
+          "type": "google_cloud_run_service",
+          "name": "default",
+          "provider_config_key": "google",
+          "expressions": {
+            "location": {
+              "constant_value": "us-central1"
+            },
+            "metadata": [
+              {
+                "namespace": {
+                  "constant_value": "{{.Provider.project}}"
+                }
+              }
+            ],
+            "name": {
+              "constant_value": "tf-test-cloudrun-srv-beep"
+            },
+            "project": {
+              "constant_value": "{{.Provider.project}}"
+            },
+            "template": [
+              {
+                "spec": [
+                  {
+                    "containers": [
+                      {
+                        "image": {
+                          "constant_value": "us-docker.pkg.dev/cloudrun/container/hello"
+                        }
+                      }
+                    ]
+                  }
+                ]
+              }
+            ]
+          },
+          "schema_version": 1
+        }
+      ]
+    }
+  }
+}
diff --git a/testdata/templates/example_cloud_run_service.json b/testdata/templates/example_cloud_run_service.json
new file mode 100644
index 00000000..5a05ed4b
--- /dev/null
+++ b/testdata/templates/example_cloud_run_service.json
@@ -0,0 +1,51 @@
+[
+  {
+    "name": "//run.googleapis.com/projects/{{.Provider.project}}/locations/us-central1/services/cloudrun-to-get-cai",
+    "asset_type": "run.googleapis.com/Service",
+    "ancestry_path": "organization/{{.OrgID}}/folder/{{.FolderID}}/project/{{.Provider.project}}",
+    "resource": {
+      "version": "v1",
+      "discovery_document_uri": "https://www.googleapis.com/discovery/v1/apis/run/v1/rest",
+      "discovery_name": "Service",
+      "parent": "//cloudresourcemanager.googleapis.com/projects/{{.Provider.project}}",
+      "data": {
+        "apiVersion": "serving.knative.dev/v1",
+        "kind": "Service",
+        "metadata": {
+          "annotations": {
+            "generated-by": "magic-modules"
+          },
+          "name": "cloudrun-to-get-cai",
+          "namespace": "{{.Provider.project}}"
+        },
+        "spec": {
+          "template": {
+            "spec": {
+              "containerConcurrency": 10,
+              "containers": [
+                {
+                  "args": [
+                    "arrgs"
+                  ],
+                  "image": "gcr.io/cloudrun/hello",
+                  "ports": [
+                    {
+                      "containerPort": 8080
+                    }
+                  ]
+                }
+              ],
+              "timeoutSeconds": 600
+            }
+          },
+          "traffic": [
+            {
+              "latestRevision": true,
+              "percent": 100
+            }
+          ]
+        }
+      }
+    }
+  }
+]
diff --git a/testdata/templates/example_cloud_run_service.tf b/testdata/templates/example_cloud_run_service.tf
new file mode 100644
index 00000000..aabbaf4f
--- /dev/null
+++ b/testdata/templates/example_cloud_run_service.tf
@@ -0,0 +1,66 @@
+/**
+ * Copyright 2021 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+terraform {
+  required_providers {
+    google = {
+      source = "hashicorp/google"
+      version = "~> {{.Provider.version}}"
+    }
+  }
+}
+
+provider "google" {
+  {{if .Provider.credentials }}credentials = "{{.Provider.credentials}}"{{end}}
+}
+
+resource "google_cloud_run_service" "default" {
+  name     = "cloudrun-to-get-cai"
+  location = "us-central1"
+  project="{{.Provider.project}}"
+
+  metadata {
+  namespace = "{{.Provider.project}}"
+  annotations = {
+      generated-by = "magic-modules"
+    }
+  }
+
+  template {
+    spec {
+      containers {
+        image = "gcr.io/cloudrun/hello"
+        args  = ["arrgs"]
+        ports {
+          container_port = 8080
+        }
+      }
+	  container_concurrency = 10
+	  timeout_seconds = 600
+    }
+  }
+
+  traffic {
+    percent         = 100
+    latest_revision = true
+  }
+
+  lifecycle {
+    ignore_changes = [
+      metadata.0.annotations,
+    ]
+  }
+}
\ No newline at end of file
diff --git a/testdata/templates/example_cloud_run_service.tfplan.json b/testdata/templates/example_cloud_run_service.tfplan.json
new file mode 100644
index 00000000..830211d5
--- /dev/null
+++ b/testdata/templates/example_cloud_run_service.tfplan.json
@@ -0,0 +1,257 @@
+{
+  "format_version": "0.1",
+  "terraform_version": "0.13.4",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_cloud_run_service.default",
+          "mode": "managed",
+          "type": "google_cloud_run_service",
+          "name": "default",
+          "provider_name": "registry.terraform.io/hashicorp/google",
+          "schema_version": 1,
+          "values": {
+            "autogenerate_revision_name": false,
+            "location": "us-central1",
+            "metadata": [
+              {
+                "annotations": {
+                  "generated-by": "magic-modules"
+                },
+                "namespace": "{{.Provider.project}}"
+              }
+            ],
+            "name": "cloudrun-to-get-cai",
+            "project": "{{.Provider.project}}",
+            "template": [
+              {
+                "spec": [
+                  {
+                    "container_concurrency": 10,
+                    "containers": [
+                      {
+                        "args": [
+                          "arrgs"
+                        ],
+                        "command": null,
+                        "env": [],
+                        "env_from": [],
+                        "image": "gcr.io/cloudrun/hello",
+                        "ports": [
+                          {
+                            "container_port": 8080,
+                            "protocol": null
+                          }
+                        ],
+                        "working_dir": null
+                      }
+                    ],
+                    "service_account_name": null,
+                    "timeout_seconds": 600
+                  }
+                ]
+              }
+            ],
+            "timeouts": null,
+            "traffic": [
+              {
+                "latest_revision": true,
+                "percent": 100,
+                "revision_name": null
+              }
+            ]
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "google_cloud_run_service.default",
+      "mode": "managed",
+      "type": "google_cloud_run_service",
+      "name": "default",
+      "provider_name": "registry.terraform.io/hashicorp/google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "autogenerate_revision_name": false,
+          "location": "us-central1",
+          "metadata": [
+            {
+              "annotations": {
+                "generated-by": "magic-modules"
+              },
+              "namespace": "{{.Provider.project}}"
+            }
+          ],
+          "name": "cloudrun-to-get-cai",
+          "project": "{{.Provider.project}}",
+          "template": [
+            {
+              "spec": [
+                {
+                  "container_concurrency": 10,
+                  "containers": [
+                    {
+                      "args": [
+                        "arrgs"
+                      ],
+                      "command": null,
+                      "env": [],
+                      "env_from": [],
+                      "image": "gcr.io/cloudrun/hello",
+                      "ports": [
+                        {
+                          "container_port": 8080,
+                          "protocol": null
+                        }
+                      ],
+                      "working_dir": null
+                    }
+                  ],
+                  "service_account_name": null,
+                  "timeout_seconds": 600
+                }
+              ]
+            }
+          ],
+          "timeouts": null,
+          "traffic": [
+            {
+              "latest_revision": true,
+              "percent": 100,
+              "revision_name": null
+            }
+          ]
+        },
+        "after_unknown": {
+          "id": true,
+          "metadata": [
+            {
+              "annotations": {},
+              "generation": true,
+              "labels": true,
+              "resource_version": true,
+              "self_link": true,
+              "uid": true
+            }
+          ],
+          "status": true,
+          "template": [
+            {
+              "metadata": true,
+              "spec": [
+                {
+                  "containers": [
+                    {
+                      "args": [
+                        false
+                      ],
+                      "env": [],
+                      "env_from": [],
+                      "ports": [
+                        {
+                          "name": true
+                        }
+                      ],
+                      "resources": true
+                    }
+                  ],
+                  "serving_state": true
+                }
+              ]
+            }
+          ],
+          "traffic": [
+            {}
+          ]
+        }
+      }
+    }
+  ],
+  "configuration": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_cloud_run_service.default",
+          "mode": "managed",
+          "type": "google_cloud_run_service",
+          "name": "default",
+          "provider_config_key": "google",
+          "expressions": {
+            "location": {
+              "constant_value": "us-central1"
+            },
+            "metadata": [
+              {
+                "annotations": {
+                  "constant_value": {
+                    "generated-by": "magic-modules"
+                  }
+                },
+                "namespace": {
+                  "constant_value": "{{.Provider.project}}"
+                }
+              }
+            ],
+            "name": {
+              "constant_value": "cloudrun-to-get-cai"
+            },
+            "project": {
+              "constant_value": "{{.Provider.project}}"
+            },
+            "template": [
+              {
+                "spec": [
+                  {
+                    "container_concurrency": {
+                      "constant_value": 10
+                    },
+                    "containers": [
+                      {
+                        "args": {
+                          "constant_value": [
+                            "arrgs"
+                          ]
+                        },
+                        "image": {
+                          "constant_value": "gcr.io/cloudrun/hello"
+                        },
+                        "ports": [
+                          {
+                            "container_port": {
+                              "constant_value": 8080
+                            }
+                          }
+                        ]
+                      }
+                    ],
+                    "timeout_seconds": {
+                      "constant_value": 600
+                    }
+                  }
+                ]
+              }
+            ],
+            "traffic": [
+              {
+                "latest_revision": {
+                  "constant_value": true
+                },
+                "percent": {
+                  "constant_value": 100
+                }
+              }
+            ]
+          },
+          "schema_version": 1
+        }
+      ]
+    }
+  }
+}