Repository: GoogleCloudPlatform/terraform-validator
Pull request #383 (2021-11-17 00:23:44)

ci changes to run go-licenses before check-in


Patch:
diff --git a/Makefile b/Makefile
index 7e68bc39..a13b1913 100644
--- a/Makefile
+++ b/Makefile
@@ -13,6 +13,11 @@ test-integration:
 	terraform --version
 	go test -v -run=CLI ./test
 
+test-go-licenses:
+	cd .. && go version && go get github.com/google/go-licenses
+	$$(go env GOPATH)/bin/go-licenses check .
+
+
 build-docker:
 	docker build -f ./Dockerfile -t terraform-validator .
 
diff --git a/README.md b/README.md
index 6743a853..de70863e 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
 # Terraform Validator
 
+_A gcloud integration for Terraform Validator is in [Private Preview](https://cloud.google.com/products#product-launch-stages). If you are working with a dedicated Technical Account Manager / Customer Engineer and are interested in participating in this Private Preview, please [get in touch via this form](https://docs.google.com/forms/d/e/1FAIpQLSfkN3AZtAtajy_-0100Kmwz-sA822DkAI__hPtYjvr2z-T8tw/viewform?usp=sf_link)._
+
 ## Overview
 
 As your business shifts towards an infrastructure-as-code workflow, security and
@@ -29,9 +31,9 @@ governance requirements. You can obtain constraints from the
 ## Table of Contents
 
 - [Install Terraform Validator](./docs/install.md)
-- [User guide](./docs/user_guide.md)
 - [Tutorial](./docs/tutorial.md)
 - [Creating a policy library](./docs/policy_library.md)
+- [Using terraform validator](./docs/user_guide.md)
 - [Supported resources](./docs/supported_resources.md)
 - [Contributing](./docs/contributing/index.md)
   - [Add a new resource](./docs/contributing/add_new_resource.md)
diff --git a/converters/google/resources/apigee_environment_iam.go b/converters/google/resources/apigee_environment_iam.go
new file mode 100644
index 00000000..3e4c128e
--- /dev/null
+++ b/converters/google/resources/apigee_environment_iam.go
@@ -0,0 +1,120 @@
+// ----------------------------------------------------------------------------
+//
+//     ***     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 "fmt"
+
+// Provide a separate asset type constant so we don't have to worry about name conflicts between IAM and non-IAM converter files
+const ApigeeEnvironmentIAMAssetType string = "apigee.googleapis.com/Environment"
+
+func resourceConverterApigeeEnvironmentIamPolicy() ResourceConverter {
+	return ResourceConverter{
+		AssetType:         ApigeeEnvironmentIAMAssetType,
+		Convert:           GetApigeeEnvironmentIamPolicyCaiObject,
+		MergeCreateUpdate: MergeApigeeEnvironmentIamPolicy,
+	}
+}
+
+func resourceConverterApigeeEnvironmentIamBinding() ResourceConverter {
+	return ResourceConverter{
+		AssetType:         ApigeeEnvironmentIAMAssetType,
+		Convert:           GetApigeeEnvironmentIamBindingCaiObject,
+		FetchFullResource: FetchApigeeEnvironmentIamPolicy,
+		MergeCreateUpdate: MergeApigeeEnvironmentIamBinding,
+		MergeDelete:       MergeApigeeEnvironmentIamBindingDelete,
+	}
+}
+
+func resourceConverterApigeeEnvironmentIamMember() ResourceConverter {
+	return ResourceConverter{
+		AssetType:         ApigeeEnvironmentIAMAssetType,
+		Convert:           GetApigeeEnvironmentIamMemberCaiObject,
+		FetchFullResource: FetchApigeeEnvironmentIamPolicy,
+		MergeCreateUpdate: MergeApigeeEnvironmentIamMember,
+		MergeDelete:       MergeApigeeEnvironmentIamMemberDelete,
+	}
+}
+
+func GetApigeeEnvironmentIamPolicyCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
+	return newApigeeEnvironmentIamAsset(d, config, expandIamPolicyBindings)
+}
+
+func GetApigeeEnvironmentIamBindingCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
+	return newApigeeEnvironmentIamAsset(d, config, expandIamRoleBindings)
+}
+
+func GetApigeeEnvironmentIamMemberCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
+	return newApigeeEnvironmentIamAsset(d, config, expandIamMemberBindings)
+}
+
+func MergeApigeeEnvironmentIamPolicy(existing, incoming Asset) Asset {
+	existing.IAMPolicy = incoming.IAMPolicy
+	return existing
+}
+
+func MergeApigeeEnvironmentIamBinding(existing, incoming Asset) Asset {
+	return mergeIamAssets(existing, incoming, mergeAuthoritativeBindings)
+}
+
+func MergeApigeeEnvironmentIamBindingDelete(existing, incoming Asset) Asset {
+	return mergeDeleteIamAssets(existing, incoming, mergeDeleteAuthoritativeBindings)
+}
+
+func MergeApigeeEnvironmentIamMember(existing, incoming Asset) Asset {
+	return mergeIamAssets(existing, incoming, mergeAdditiveBindings)
+}
+
+func MergeApigeeEnvironmentIamMemberDelete(existing, incoming Asset) Asset {
+	return mergeDeleteIamAssets(existing, incoming, mergeDeleteAdditiveBindings)
+}
+
+func newApigeeEnvironmentIamAsset(
+	d TerraformResourceData,
+	config *Config,
+	expandBindings func(d TerraformResourceData) ([]IAMBinding, error),
+) ([]Asset, error) {
+	bindings, err := expandBindings(d)
+	if err != nil {
+		return []Asset{}, fmt.Errorf("expanding bindings: %v", err)
+	}
+
+	name, err := assetName(d, config, "//apigee.googleapis.com/{{environment}}")
+	if err != nil {
+		return []Asset{}, err
+	}
+
+	return []Asset{{
+		Name: name,
+		Type: ApigeeEnvironmentIAMAssetType,
+		IAMPolicy: &IAMPolicy{
+			Bindings: bindings,
+		},
+	}}, nil
+}
+
+func FetchApigeeEnvironmentIamPolicy(d TerraformResourceData, config *Config) (Asset, error) {
+	// Check if the identity field returns a value
+	if _, ok := d.GetOk("{{environment}}"); !ok {
+		return Asset{}, ErrEmptyIdentityField
+	}
+
+	return fetchIamPolicy(
+		ApigeeEnvironmentIamUpdaterProducer,
+		d,
+		config,
+		"//apigee.googleapis.com/{{environment}}",
+		ApigeeEnvironmentIAMAssetType,
+	)
+}
diff --git a/converters/google/resources/bigquery_table.go b/converters/google/resources/bigquery_table.go
index c0a158c2..5eaa6666 100644
--- a/converters/google/resources/bigquery_table.go
+++ b/converters/google/resources/bigquery_table.go
@@ -4,25 +4,34 @@ import (
 	"reflect"
 )
 
-func GetBigQueryTableCaiObject(d TerraformResourceData, config *Config) (Asset, error) {
+const BigQueryTableAssetType string = "bigquery.googleapis.com/Table"
+
+func resourceConverterBigQueryTable() ResourceConverter {
+	return ResourceConverter{
+		AssetType: BigQueryTableAssetType,
+		Convert:   GetBigQueryTableCaiObject,
+	}
+}
+
+func GetBigQueryTableCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
 	name, err := assetName(d, config, "//bigquery.googleapis.com/projects/{{project}}/datasets/{{dataset_id}}/tables/{{table_id}}")
 
 	if err != nil {
-		return Asset{}, err
+		return []Asset{}, err
 	}
 	if obj, err := GetBigQueryTableApiObject(d, config); err == nil {
-		return Asset{
+		return []Asset{{
 			Name: name,
-			Type: "bigquery.googleapis.com/Table",
+			Type: BigQueryTableAssetType,
 			Resource: &AssetResource{
 				Version:              "v2",
 				DiscoveryDocumentURI: "https://www.googleapis.com/discovery/v1/apis/bigquery/v2/rest",
 				DiscoveryName:        "Table",
 				Data:                 obj,
 			},
-		}, nil
+		}}, nil
 	} else {
-		return Asset{}, err
+		return []Asset{}, err
 	}
 }
 
@@ -36,7 +45,7 @@ func GetBigQueryTableApiObject(d TerraformResourceData, config *Config) (map[str
 		obj["tableReference"] = tableReferenceProp
 	}
 
-    descriptionProp, err := expandBigQueryTableDescription(d.Get("description"), d, config)
+	descriptionProp, err := expandBigQueryTableDescription(d.Get("description"), d, config)
 	if err != nil {
 		return nil, err
 	} else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) {
@@ -49,7 +58,7 @@ func GetBigQueryTableApiObject(d TerraformResourceData, config *Config) (map[str
 	} else if v, ok := d.GetOkExists("friendly_name"); !isEmptyValue(reflect.ValueOf(friendlyNameProp)) && (ok || !reflect.DeepEqual(v, friendlyNameProp)) {
 		obj["friendlyName"] = friendlyNameProp
 	}
-	
+
 	labelsProp, err := expandBigQueryTableLabels(d.Get("labels"), d, config)
 	if err != nil {
 		return nil, err
@@ -63,7 +72,7 @@ func GetBigQueryTableApiObject(d TerraformResourceData, config *Config) (map[str
 	} else if v, ok := d.GetOkExists("location"); !isEmptyValue(reflect.ValueOf(locationProp)) && (ok || !reflect.DeepEqual(v, locationProp)) {
 		obj["location"] = locationProp
 	}
-	
+
 	expirationTimeProp, err := expandBigQueryTableExpirationTime(nil, d, config)
 	if err != nil {
 		return nil, err
@@ -90,7 +99,7 @@ func GetBigQueryTableApiObject(d TerraformResourceData, config *Config) (map[str
 
 func expandBigQueryTableTableReference(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
 	transformed := make(map[string]interface{})
-	
+
 	transformedProjectId, err := expandBigQueryTableTableReferenceProjectId(d.Get("project"), d, config)
 	if err != nil {
 		return nil, err
@@ -109,7 +118,7 @@ func expandBigQueryTableTableReference(v interface{}, d TerraformResourceData, c
 	if err != nil {
 		return nil, err
 	} else if val := reflect.ValueOf(transformedTableId); val.IsValid() && !isEmptyValue(val) {
-		transformed["tableId"] = transformedDatasetId
+		transformed["tableId"] = transformedTableId
 	}
 
 	return transformed, nil
@@ -117,7 +126,7 @@ func expandBigQueryTableTableReference(v interface{}, d TerraformResourceData, c
 
 func expandBigQueryTableExpirationTime(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
 	transformed := make(map[string]interface{})
-	
+
 	transformedExpirationTimeValue, err := expandBigQueryTableExpirationTimeValue(d.Get("expiration_time"), d, config)
 
 	if err != nil {
@@ -139,7 +148,7 @@ func expandBigQueryTableEncyptionConfiguration(v interface{}, d TerraformResourc
 	transformed := make(map[string]interface{})
 
 	transformedKmsKeyName, err := expandBigQueryTableEncyptionConfigurationKmsKeyName(original["kms_key_name"], d, config)
-	
+
 	if err != nil {
 		return nil, err
 	} else if val := reflect.ValueOf(transformedKmsKeyName); val.IsValid() && !isEmptyValue(val) {
@@ -178,7 +187,7 @@ func expandBigQueryTableTimePartition(v interface{}, d TerraformResourceData, co
 	transformed := make(map[string]interface{})
 
 	transformedType, err := expandBigQueryTableTimePartitionType(original["type"], d, config)
-	
+
 	if err != nil {
 		return nil, err
 	} else if val := reflect.ValueOf(transformedType); val.IsValid() && !isEmptyValue(val) {
@@ -186,7 +195,7 @@ func expandBigQueryTableTimePartition(v interface{}, d TerraformResourceData, co
 	}
 
 	transformedExpirationMs, err := expandBigQueryTableTimePartitionExpirationMs(original["expiration_ms"], d, config)
-	
+
 	if err != nil {
 		return nil, err
 	} else if val := reflect.ValueOf(transformedExpirationMs); val.IsValid() && !isEmptyValue(val) {
@@ -194,15 +203,15 @@ func expandBigQueryTableTimePartition(v interface{}, d TerraformResourceData, co
 	}
 
 	transformedField, err := expandBigQueryTableTimeField(original["field"], d, config)
-	
+
 	if err != nil {
 		return nil, err
 	} else if val := reflect.ValueOf(transformedField); val.IsValid() && !isEmptyValue(val) {
 		transformed["field"] = transformedField
 	}
-	
+
 	transformedRequirePartitionFilter, err := expandBigQueryTableRequirePartitionFilter(original["require_partition_filter"], d, config)
-	
+
 	if err != nil {
 		return nil, err
 	} else if val := reflect.ValueOf(transformedRequirePartitionFilter); val.IsValid() && !isEmptyValue(val) {
@@ -221,7 +230,7 @@ func expandBigQueryTableTimePartitionExpirationMs(v interface{}, d TerraformReso
 
 func expandBigQueryTableTimeField(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
 	transformed := make(map[string]interface{})
-	
+
 	transformedValue, err := expandBigQueryTableTimeFieldValue(v, d, config)
 
 	if err != nil {
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/config.go b/converters/google/resources/config.go
index 69079f28..9fa86e51 100644
--- a/converters/google/resources/config.go
+++ b/converters/google/resources/config.go
@@ -166,6 +166,8 @@ type Config struct {
 	EventarcBasePath             string
 	GkeHubBasePath               string
 	OrgPolicyBasePath            string
+	// CloudBuild WorkerPool uses a different endpoint (v1beta1) than any other CloudBuild resources
+	CloudBuildWorkerPoolBasePath string
 }
 
 const AccessApprovalBasePathKey = "AccessApproval"
diff --git a/converters/google/resources/iam_apigee_environment.go b/converters/google/resources/iam_apigee_environment.go
new file mode 100644
index 00000000..7dbe271c
--- /dev/null
+++ b/converters/google/resources/iam_apigee_environment.go
@@ -0,0 +1,181 @@
+// ----------------------------------------------------------------------------
+//
+//     ***     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 (
+	"fmt"
+
+	"github.com/hashicorp/errwrap"
+	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+	"google.golang.org/api/cloudresourcemanager/v1"
+)
+
+var ApigeeEnvironmentIamSchema = map[string]*schema.Schema{
+	"org_id": {
+		Type:     schema.TypeString,
+		Required: true,
+		ForceNew: true,
+	},
+	"env_id": {
+		Type:             schema.TypeString,
+		Required:         true,
+		ForceNew:         true,
+		DiffSuppressFunc: compareSelfLinkOrResourceName,
+	},
+}
+
+type ApigeeEnvironmentIamUpdater struct {
+	orgId  string
+	envId  string
+	d      TerraformResourceData
+	Config *Config
+}
+
+func ApigeeEnvironmentIamUpdaterProducer(d TerraformResourceData, config *Config) (ResourceIamUpdater, error) {
+	values := make(map[string]string)
+
+	if v, ok := d.GetOk("org_id"); ok {
+		values["org_id"] = v.(string)
+	}
+
+	if v, ok := d.GetOk("env_id"); ok {
+		values["env_id"] = v.(string)
+	}
+
+	// We may have gotten either a long or short name, so attempt to parse long name if possible
+	m, err := getImportIdQualifiers([]string{"(?P<org_id>.+)/environments/(?P<env_id>[^/]+)", "(?P<env_id>[^/]+)"}, d, config, d.Get("env_id").(string))
+	if err != nil {
+		return nil, err
+	}
+
+	for k, v := range m {
+		values[k] = v
+	}
+
+	u := &ApigeeEnvironmentIamUpdater{
+		orgId:  values["org_id"],
+		envId:  values["env_id"],
+		d:      d,
+		Config: config,
+	}
+
+	if err := d.Set("org_id", u.orgId); err != nil {
+		return nil, fmt.Errorf("Error setting org_id: %s", err)
+	}
+	if err := d.Set("env_id", u.GetResourceId()); err != nil {
+		return nil, fmt.Errorf("Error setting env_id: %s", err)
+	}
+
+	return u, nil
+}
+
+func ApigeeEnvironmentIdParseFunc(d *schema.ResourceData, config *Config) error {
+	values := make(map[string]string)
+
+	m, err := getImportIdQualifiers([]string{"(?P<org_id>.+)/environments/(?P<env_id>[^/]+)", "(?P<env_id>[^/]+)"}, d, config, d.Id())
+	if err != nil {
+		return err
+	}
+
+	for k, v := range m {
+		values[k] = v
+	}
+
+	u := &ApigeeEnvironmentIamUpdater{
+		orgId:  values["org_id"],
+		envId:  values["env_id"],
+		d:      d,
+		Config: config,
+	}
+	if err := d.Set("env_id", u.GetResourceId()); err != nil {
+		return fmt.Errorf("Error setting env_id: %s", err)
+	}
+	d.SetId(u.GetResourceId())
+	return nil
+}
+
+func (u *ApigeeEnvironmentIamUpdater) GetResourceIamPolicy() (*cloudresourcemanager.Policy, error) {
+	url, err := u.qualifyEnvironmentUrl("getIamPolicy")
+	if err != nil {
+		return nil, err
+	}
+
+	var obj map[string]interface{}
+
+	userAgent, err := generateUserAgentString(u.d, u.Config.userAgent)
+	if err != nil {
+		return nil, err
+	}
+
+	policy, err := sendRequest(u.Config, "GET", "", url, userAgent, obj)
+	if err != nil {
+		return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for %s: {{err}}", u.DescribeResource()), err)
+	}
+
+	out := &cloudresourcemanager.Policy{}
+	err = Convert(policy, out)
+	if err != nil {
+		return nil, errwrap.Wrapf("Cannot convert a policy to a resource manager policy: {{err}}", err)
+	}
+
+	return out, nil
+}
+
+func (u *ApigeeEnvironmentIamUpdater) SetResourceIamPolicy(policy *cloudresourcemanager.Policy) error {
+	json, err := ConvertToMap(policy)
+	if err != nil {
+		return err
+	}
+
+	obj := make(map[string]interface{})
+	obj["policy"] = json
+
+	url, err := u.qualifyEnvironmentUrl("setIamPolicy")
+	if err != nil {
+		return err
+	}
+
+	userAgent, err := generateUserAgentString(u.d, u.Config.userAgent)
+	if err != nil {
+		return err
+	}
+
+	_, err = sendRequestWithTimeout(u.Config, "POST", "", url, userAgent, obj, u.d.Timeout(schema.TimeoutCreate))
+	if err != nil {
+		return errwrap.Wrapf(fmt.Sprintf("Error setting IAM policy for %s: {{err}}", u.DescribeResource()), err)
+	}
+
+	return nil
+}
+
+func (u *ApigeeEnvironmentIamUpdater) qualifyEnvironmentUrl(methodIdentifier string) (string, error) {
+	urlTemplate := fmt.Sprintf("{{ApigeeBasePath}}%s:%s", fmt.Sprintf("%s/environments/%s", u.orgId, u.envId), methodIdentifier)
+	url, err := replaceVars(u.d, u.Config, urlTemplate)
+	if err != nil {
+		return "", err
+	}
+	return url, nil
+}
+
+func (u *ApigeeEnvironmentIamUpdater) GetResourceId() string {
+	return fmt.Sprintf("%s/environments/%s", u.orgId, u.envId)
+}
+
+func (u *ApigeeEnvironmentIamUpdater) GetMutexKey() string {
+	return fmt.Sprintf("iam-apigee-environment-%s", u.GetResourceId())
+}
+
+func (u *ApigeeEnvironmentIamUpdater) DescribeResource() string {
+	return fmt.Sprintf("apigee environment %q", u.GetResourceId())
+}
diff --git a/converters/google/resources/iam_notebooks_runtime.go b/converters/google/resources/iam_notebooks_runtime.go
new file mode 100644
index 00000000..b5e15649
--- /dev/null
+++ b/converters/google/resources/iam_notebooks_runtime.go
@@ -0,0 +1,222 @@
+// ----------------------------------------------------------------------------
+//
+//     ***     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 (
+	"fmt"
+
+	"github.com/hashicorp/errwrap"
+	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+	"google.golang.org/api/cloudresourcemanager/v1"
+)
+
+var NotebooksRuntimeIamSchema = map[string]*schema.Schema{
+	"project": {
+		Type:     schema.TypeString,
+		Computed: true,
+		Optional: true,
+		ForceNew: true,
+	},
+	"location": {
+		Type:     schema.TypeString,
+		Computed: true,
+		Optional: true,
+		ForceNew: true,
+	},
+	"runtime_name": {
+		Type:             schema.TypeString,
+		Required:         true,
+		ForceNew:         true,
+		DiffSuppressFunc: compareSelfLinkOrResourceName,
+	},
+}
+
+type NotebooksRuntimeIamUpdater struct {
+	project     string
+	location    string
+	runtimeName string
+	d           TerraformResourceData
+	Config      *Config
+}
+
+func NotebooksRuntimeIamUpdaterProducer(d TerraformResourceData, config *Config) (ResourceIamUpdater, error) {
+	values := make(map[string]string)
+
+	project, _ := getProject(d, config)
+	if project != "" {
+		if err := d.Set("project", project); err != nil {
+			return nil, fmt.Errorf("Error setting project: %s", err)
+		}
+	}
+	values["project"] = project
+	location, _ := getLocation(d, config)
+	if location != "" {
+		if err := d.Set("location", location); err != nil {
+			return nil, fmt.Errorf("Error setting location: %s", err)
+		}
+	}
+	values["location"] = location
+	if v, ok := d.GetOk("runtime_name"); ok {
+		values["runtime_name"] = v.(string)
+	}
+
+	// We may have gotten either a long or short name, so attempt to parse long name if possible
+	m, err := getImportIdQualifiers([]string{"projects/(?P<project>[^/]+)/locations/(?P<location>[^/]+)/runtimes/(?P<runtime_name>[^/]+)", "(?P<project>[^/]+)/(?P<location>[^/]+)/(?P<runtime_name>[^/]+)", "(?P<location>[^/]+)/(?P<runtime_name>[^/]+)", "(?P<runtime_name>[^/]+)"}, d, config, d.Get("runtime_name").(string))
+	if err != nil {
+		return nil, err
+	}
+
+	for k, v := range m {
+		values[k] = v
+	}
+
+	u := &NotebooksRuntimeIamUpdater{
+		project:     values["project"],
+		location:    values["location"],
+		runtimeName: values["runtime_name"],
+		d:           d,
+		Config:      config,
+	}
+
+	if err := d.Set("project", u.project); err != nil {
+		return nil, fmt.Errorf("Error setting project: %s", err)
+	}
+	if err := d.Set("location", u.location); err != nil {
+		return nil, fmt.Errorf("Error setting location: %s", err)
+	}
+	if err := d.Set("runtime_name", u.GetResourceId()); err != nil {
+		return nil, fmt.Errorf("Error setting runtime_name: %s", err)
+	}
+
+	return u, nil
+}
+
+func NotebooksRuntimeIdParseFunc(d *schema.ResourceData, config *Config) error {
+	values := make(map[string]string)
+
+	project, _ := getProject(d, config)
+	if project != "" {
+		values["project"] = project
+	}
+
+	location, _ := getLocation(d, config)
+	if location != "" {
+		values["location"] = location
+	}
+
+	m, err := getImportIdQualifiers([]string{"projects/(?P<project>[^/]+)/locations/(?P<location>[^/]+)/runtimes/(?P<runtime_name>[^/]+)", "(?P<project>[^/]+)/(?P<location>[^/]+)/(?P<runtime_name>[^/]+)", "(?P<location>[^/]+)/(?P<runtime_name>[^/]+)", "(?P<runtime_name>[^/]+)"}, d, config, d.Id())
+	if err != nil {
+		return err
+	}
+
+	for k, v := range m {
+		values[k] = v
+	}
+
+	u := &NotebooksRuntimeIamUpdater{
+		project:     values["project"],
+		location:    values["location"],
+		runtimeName: values["runtime_name"],
+		d:           d,
+		Config:      config,
+	}
+	if err := d.Set("runtime_name", u.GetResourceId()); err != nil {
+		return fmt.Errorf("Error setting runtime_name: %s", err)
+	}
+	d.SetId(u.GetResourceId())
+	return nil
+}
+
+func (u *NotebooksRuntimeIamUpdater) GetResourceIamPolicy() (*cloudresourcemanager.Policy, error) {
+	url, err := u.qualifyRuntimeUrl("getIamPolicy")
+	if err != nil {
+		return nil, err
+	}
+
+	project, err := getProject(u.d, u.Config)
+	if err != nil {
+		return nil, err
+	}
+	var obj map[string]interface{}
+
+	userAgent, err := generateUserAgentString(u.d, u.Config.userAgent)
+	if err != nil {
+		return nil, err
+	}
+
+	policy, err := sendRequest(u.Config, "GET", project, url, userAgent, obj)
+	if err != nil {
+		return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for %s: {{err}}", u.DescribeResource()), err)
+	}
+
+	out := &cloudresourcemanager.Policy{}
+	err = Convert(policy, out)
+	if err != nil {
+		return nil, errwrap.Wrapf("Cannot convert a policy to a resource manager policy: {{err}}", err)
+	}
+
+	return out, nil
+}
+
+func (u *NotebooksRuntimeIamUpdater) SetResourceIamPolicy(policy *cloudresourcemanager.Policy) error {
+	json, err := ConvertToMap(policy)
+	if err != nil {
+		return err
+	}
+
+	obj := make(map[string]interface{})
+	obj["policy"] = json
+
+	url, err := u.qualifyRuntimeUrl("setIamPolicy")
+	if err != nil {
+		return err
+	}
+	project, err := getProject(u.d, u.Config)
+	if err != nil {
+		return err
+	}
+
+	userAgent, err := generateUserAgentString(u.d, u.Config.userAgent)
+	if err != nil {
+		return err
+	}
+
+	_, err = sendRequestWithTimeout(u.Config, "POST", project, url, userAgent, obj, u.d.Timeout(schema.TimeoutCreate))
+	if err != nil {
+		return errwrap.Wrapf(fmt.Sprintf("Error setting IAM policy for %s: {{err}}", u.DescribeResource()), err)
+	}
+
+	return nil
+}
+
+func (u *NotebooksRuntimeIamUpdater) qualifyRuntimeUrl(methodIdentifier string) (string, error) {
+	urlTemplate := fmt.Sprintf("{{NotebooksBasePath}}%s:%s", fmt.Sprintf("projects/%s/locations/%s/runtimes/%s", u.project, u.location, u.runtimeName), methodIdentifier)
+	url, err := replaceVars(u.d, u.Config, urlTemplate)
+	if err != nil {
+		return "", err
+	}
+	return url, nil
+}
+
+func (u *NotebooksRuntimeIamUpdater) GetResourceId() string {
+	return fmt.Sprintf("projects/%s/locations/%s/runtimes/%s", u.project, u.location, u.runtimeName)
+}
+
+func (u *NotebooksRuntimeIamUpdater) GetMutexKey() string {
+	return fmt.Sprintf("iam-notebooks-runtime-%s", u.GetResourceId())
+}
+
+func (u *NotebooksRuntimeIamUpdater) DescribeResource() string {
+	return fmt.Sprintf("notebooks runtime %q", u.GetResourceId())
+}
diff --git a/converters/google/resources/notebooks_runtime.go b/converters/google/resources/notebooks_runtime.go
new file mode 100644
index 00000000..1b0c6497
--- /dev/null
+++ b/converters/google/resources/notebooks_runtime.go
@@ -0,0 +1,804 @@
+// ----------------------------------------------------------------------------
+//
+//     ***     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 (
+	"reflect"
+	"strings"
+
+	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+const notebooksRuntimeGoogleProvidedLabel = "goog-caip-managed-notebook"
+
+func NotebooksRuntimeLabelDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
+	// Suppress diffs for the label provided by Google
+	if strings.Contains(k, notebooksRuntimeGoogleProvidedLabel) && 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
+}
+
+// NotReturnedByAPIDiffSuppress
+func NotReturnedByAPIDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
+	return true
+}
+
+const NotebooksRuntimeAssetType string = "notebooks.googleapis.com/Runtime"
+
+func resourceConverterNotebooksRuntime() ResourceConverter {
+	return ResourceConverter{
+		AssetType: NotebooksRuntimeAssetType,
+		Convert:   GetNotebooksRuntimeCaiObject,
+	}
+}
+
+func GetNotebooksRuntimeCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
+	name, err := assetName(d, config, "//notebooks.googleapis.com/projects/{{project}}/locations/{{location}}/runtimes/{{name}}")
+	if err != nil {
+		return []Asset{}, err
+	}
+	if obj, err := GetNotebooksRuntimeApiObject(d, config); err == nil {
+		return []Asset{{
+			Name: name,
+			Type: NotebooksRuntimeAssetType,
+			Resource: &AssetResource{
+				Version:              "v1",
+				DiscoveryDocumentURI: "https://www.googleapis.com/discovery/v1/apis/notebooks/v1/rest",
+				DiscoveryName:        "Runtime",
+				Data:                 obj,
+			},
+		}}, nil
+	} else {
+		return []Asset{}, err
+	}
+}
+
+func GetNotebooksRuntimeApiObject(d TerraformResourceData, config *Config) (map[string]interface{}, error) {
+	obj := make(map[string]interface{})
+	virtualMachineProp, err := expandNotebooksRuntimeVirtualMachine(d.Get("virtual_machine"), d, config)
+	if err != nil {
+		return nil, err
+	} else if v, ok := d.GetOkExists("virtual_machine"); !isEmptyValue(reflect.ValueOf(virtualMachineProp)) && (ok || !reflect.DeepEqual(v, virtualMachineProp)) {
+		obj["virtualMachine"] = virtualMachineProp
+	}
+	accessConfigProp, err := expandNotebooksRuntimeAccessConfig(d.Get("access_config"), d, config)
+	if err != nil {
+		return nil, err
+	} else if v, ok := d.GetOkExists("access_config"); !isEmptyValue(reflect.ValueOf(accessConfigProp)) && (ok || !reflect.DeepEqual(v, accessConfigProp)) {
+		obj["accessConfig"] = accessConfigProp
+	}
+	softwareConfigProp, err := expandNotebooksRuntimeSoftwareConfig(d.Get("software_config"), d, config)
+	if err != nil {
+		return nil, err
+	} else if v, ok := d.GetOkExists("software_config"); !isEmptyValue(reflect.ValueOf(softwareConfigProp)) && (ok || !reflect.DeepEqual(v, softwareConfigProp)) {
+		obj["softwareConfig"] = softwareConfigProp
+	}
+
+	return obj, nil
+}
+
+func expandNotebooksRuntimeVirtualMachine(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{})
+
+	transformedInstanceName, err := expandNotebooksRuntimeVirtualMachineInstanceName(original["instance_name"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedInstanceName); val.IsValid() && !isEmptyValue(val) {
+		transformed["instanceName"] = transformedInstanceName
+	}
+
+	transformedInstanceId, err := expandNotebooksRuntimeVirtualMachineInstanceId(original["instance_id"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedInstanceId); val.IsValid() && !isEmptyValue(val) {
+		transformed["instanceId"] = transformedInstanceId
+	}
+
+	transformedVirtualMachineConfig, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfig(original["virtual_machine_config"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedVirtualMachineConfig); val.IsValid() && !isEmptyValue(val) {
+		transformed["virtualMachineConfig"] = transformedVirtualMachineConfig
+	}
+
+	return transformed, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineInstanceName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineInstanceId(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfig(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{})
+
+	transformedZone, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigZone(original["zone"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedZone); val.IsValid() && !isEmptyValue(val) {
+		transformed["zone"] = transformedZone
+	}
+
+	transformedMachineType, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigMachineType(original["machine_type"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedMachineType); val.IsValid() && !isEmptyValue(val) {
+		transformed["machineType"] = transformedMachineType
+	}
+
+	transformedDataDisk, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDisk(original["data_disk"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedDataDisk); val.IsValid() && !isEmptyValue(val) {
+		transformed["dataDisk"] = transformedDataDisk
+	}
+
+	transformedContainerImages, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigContainerImages(original["container_images"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedContainerImages); val.IsValid() && !isEmptyValue(val) {
+		transformed["containerImages"] = transformedContainerImages
+	}
+
+	transformedEncryptionConfig, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigEncryptionConfig(original["encryption_config"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedEncryptionConfig); val.IsValid() && !isEmptyValue(val) {
+		transformed["encryptionConfig"] = transformedEncryptionConfig
+	}
+
+	transformedShieldedInstanceConfig, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigShieldedInstanceConfig(original["shielded_instance_config"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedShieldedInstanceConfig); val.IsValid() && !isEmptyValue(val) {
+		transformed["shieldedInstanceConfig"] = transformedShieldedInstanceConfig
+	}
+
+	transformedAcceleratorConfig, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigAcceleratorConfig(original["accelerator_config"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedAcceleratorConfig); val.IsValid() && !isEmptyValue(val) {
+		transformed["acceleratorConfig"] = transformedAcceleratorConfig
+	}
+
+	transformedNetwork, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigNetwork(original["network"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedNetwork); val.IsValid() && !isEmptyValue(val) {
+		transformed["network"] = transformedNetwork
+	}
+
+	transformedSubnet, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigSubnet(original["subnet"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedSubnet); val.IsValid() && !isEmptyValue(val) {
+		transformed["subnet"] = transformedSubnet
+	}
+
+	transformedInternalIpOnly, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigInternalIpOnly(original["internal_ip_only"], d, config)
+	if err != nil {
+		return nil, err
+	} else {
+		transformed["internalIpOnly"] = transformedInternalIpOnly
+	}
+
+	transformedTags, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigTags(original["tags"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedTags); val.IsValid() && !isEmptyValue(val) {
+		transformed["tags"] = transformedTags
+	}
+
+	transformedGuestAttributes, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigGuestAttributes(original["guest_attributes"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedGuestAttributes); val.IsValid() && !isEmptyValue(val) {
+		transformed["guestAttributes"] = transformedGuestAttributes
+	}
+
+	transformedMetadata, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigMetadata(original["metadata"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedMetadata); val.IsValid() && !isEmptyValue(val) {
+		transformed["metadata"] = transformedMetadata
+	}
+
+	transformedLabels, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigLabels(original["labels"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedLabels); val.IsValid() && !isEmptyValue(val) {
+		transformed["labels"] = transformedLabels
+	}
+
+	transformedNicType, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigNicType(original["nic_type"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedNicType); val.IsValid() && !isEmptyValue(val) {
+		transformed["nicType"] = transformedNicType
+	}
+
+	return transformed, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigZone(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigMachineType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDisk(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{})
+
+	transformedAutoDelete, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskAutoDelete(original["auto_delete"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedAutoDelete); val.IsValid() && !isEmptyValue(val) {
+		transformed["autoDelete"] = transformedAutoDelete
+	}
+
+	transformedBoot, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskBoot(original["boot"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedBoot); val.IsValid() && !isEmptyValue(val) {
+		transformed["boot"] = transformedBoot
+	}
+
+	transformedDeviceName, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskDeviceName(original["device_name"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedDeviceName); val.IsValid() && !isEmptyValue(val) {
+		transformed["deviceName"] = transformedDeviceName
+	}
+
+	transformedGuestOsFeatures, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskGuestOsFeatures(original["guest_os_features"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedGuestOsFeatures); val.IsValid() && !isEmptyValue(val) {
+		transformed["guestOsFeatures"] = transformedGuestOsFeatures
+	}
+
+	transformedIndex, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskIndex(original["index"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedIndex); val.IsValid() && !isEmptyValue(val) {
+		transformed["index"] = transformedIndex
+	}
+
+	transformedInitializeParams, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskInitializeParams(original["initialize_params"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedInitializeParams); val.IsValid() && !isEmptyValue(val) {
+		transformed["initializeParams"] = transformedInitializeParams
+	}
+
+	transformedInterface, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskInterface(original["interface"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedInterface); val.IsValid() && !isEmptyValue(val) {
+		transformed["interface"] = transformedInterface
+	}
+
+	transformedKind, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskKind(original["kind"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedKind); val.IsValid() && !isEmptyValue(val) {
+		transformed["kind"] = transformedKind
+	}
+
+	transformedLicenses, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskLicenses(original["licenses"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedLicenses); val.IsValid() && !isEmptyValue(val) {
+		transformed["licenses"] = transformedLicenses
+	}
+
+	transformedMode, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskMode(original["mode"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedMode); val.IsValid() && !isEmptyValue(val) {
+		transformed["mode"] = transformedMode
+	}
+
+	transformedSource, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskSource(original["source"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedSource); val.IsValid() && !isEmptyValue(val) {
+		transformed["source"] = transformedSource
+	}
+
+	transformedType, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskType(original["type"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedType); val.IsValid() && !isEmptyValue(val) {
+		transformed["type"] = transformedType
+	}
+
+	return transformed, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskAutoDelete(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskBoot(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskDeviceName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskGuestOsFeatures(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskIndex(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskInitializeParams(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{})
+
+	transformedDescription, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskInitializeParamsDescription(original["description"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedDescription); val.IsValid() && !isEmptyValue(val) {
+		transformed["description"] = transformedDescription
+	}
+
+	transformedDiskName, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskInitializeParamsDiskName(original["disk_name"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedDiskName); val.IsValid() && !isEmptyValue(val) {
+		transformed["diskName"] = transformedDiskName
+	}
+
+	transformedDiskSizeGb, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskInitializeParamsDiskSizeGb(original["disk_size_gb"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedDiskSizeGb); val.IsValid() && !isEmptyValue(val) {
+		transformed["diskSizeGb"] = transformedDiskSizeGb
+	}
+
+	transformedDiskType, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskInitializeParamsDiskType(original["disk_type"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedDiskType); val.IsValid() && !isEmptyValue(val) {
+		transformed["diskType"] = transformedDiskType
+	}
+
+	transformedLabels, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskInitializeParamsLabels(original["labels"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedLabels); val.IsValid() && !isEmptyValue(val) {
+		transformed["labels"] = transformedLabels
+	}
+
+	return transformed, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskInitializeParamsDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskInitializeParamsDiskName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskInitializeParamsDiskSizeGb(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskInitializeParamsDiskType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskInitializeParamsLabels(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 expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskInterface(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskKind(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskLicenses(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskMode(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskSource(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigDataDiskType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigContainerImages(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{})
+
+		transformedRepository, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigContainerImagesRepository(original["repository"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedRepository); val.IsValid() && !isEmptyValue(val) {
+			transformed["repository"] = transformedRepository
+		}
+
+		transformedTag, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigContainerImagesTag(original["tag"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedTag); val.IsValid() && !isEmptyValue(val) {
+			transformed["tag"] = transformedTag
+		}
+
+		req = append(req, transformed)
+	}
+	return req, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigContainerImagesRepository(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigContainerImagesTag(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigEncryptionConfig(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{})
+
+	transformedKmsKey, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigEncryptionConfigKmsKey(original["kms_key"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedKmsKey); val.IsValid() && !isEmptyValue(val) {
+		transformed["kmsKey"] = transformedKmsKey
+	}
+
+	return transformed, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigEncryptionConfigKmsKey(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigShieldedInstanceConfig(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{})
+
+	transformedEnableSecureBoot, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigShieldedInstanceConfigEnableSecureBoot(original["enable_secure_boot"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedEnableSecureBoot); val.IsValid() && !isEmptyValue(val) {
+		transformed["enableSecureBoot"] = transformedEnableSecureBoot
+	}
+
+	transformedEnableVtpm, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigShieldedInstanceConfigEnableVtpm(original["enable_vtpm"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedEnableVtpm); val.IsValid() && !isEmptyValue(val) {
+		transformed["enableVtpm"] = transformedEnableVtpm
+	}
+
+	transformedEnableIntegrityMonitoring, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigShieldedInstanceConfigEnableIntegrityMonitoring(original["enable_integrity_monitoring"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedEnableIntegrityMonitoring); val.IsValid() && !isEmptyValue(val) {
+		transformed["enableIntegrityMonitoring"] = transformedEnableIntegrityMonitoring
+	}
+
+	return transformed, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigShieldedInstanceConfigEnableSecureBoot(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigShieldedInstanceConfigEnableVtpm(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigShieldedInstanceConfigEnableIntegrityMonitoring(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigAcceleratorConfig(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{})
+
+	transformedType, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigAcceleratorConfigType(original["type"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedType); val.IsValid() && !isEmptyValue(val) {
+		transformed["type"] = transformedType
+	}
+
+	transformedCoreCount, err := expandNotebooksRuntimeVirtualMachineVirtualMachineConfigAcceleratorConfigCoreCount(original["core_count"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedCoreCount); val.IsValid() && !isEmptyValue(val) {
+		transformed["coreCount"] = transformedCoreCount
+	}
+
+	return transformed, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigAcceleratorConfigType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigAcceleratorConfigCoreCount(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigNetwork(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigSubnet(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigInternalIpOnly(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigTags(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeVirtualMachineVirtualMachineConfigGuestAttributes(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 expandNotebooksRuntimeVirtualMachineVirtualMachineConfigMetadata(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 expandNotebooksRuntimeVirtualMachineVirtualMachineConfigLabels(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 expandNotebooksRuntimeVirtualMachineVirtualMachineConfigNicType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeAccessConfig(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{})
+
+	transformedAccessType, err := expandNotebooksRuntimeAccessConfigAccessType(original["access_type"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedAccessType); val.IsValid() && !isEmptyValue(val) {
+		transformed["accessType"] = transformedAccessType
+	}
+
+	transformedRuntimeOwner, err := expandNotebooksRuntimeAccessConfigRuntimeOwner(original["runtime_owner"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedRuntimeOwner); val.IsValid() && !isEmptyValue(val) {
+		transformed["runtimeOwner"] = transformedRuntimeOwner
+	}
+
+	transformedProxyUri, err := expandNotebooksRuntimeAccessConfigProxyUri(original["proxy_uri"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedProxyUri); val.IsValid() && !isEmptyValue(val) {
+		transformed["proxyUri"] = transformedProxyUri
+	}
+
+	return transformed, nil
+}
+
+func expandNotebooksRuntimeAccessConfigAccessType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeAccessConfigRuntimeOwner(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeAccessConfigProxyUri(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeSoftwareConfig(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{})
+
+	transformedNotebookUpgradeSchedule, err := expandNotebooksRuntimeSoftwareConfigNotebookUpgradeSchedule(original["notebook_upgrade_schedule"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedNotebookUpgradeSchedule); val.IsValid() && !isEmptyValue(val) {
+		transformed["notebookUpgradeSchedule"] = transformedNotebookUpgradeSchedule
+	}
+
+	transformedEnableHealthMonitoring, err := expandNotebooksRuntimeSoftwareConfigEnableHealthMonitoring(original["enable_health_monitoring"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedEnableHealthMonitoring); val.IsValid() && !isEmptyValue(val) {
+		transformed["enableHealthMonitoring"] = transformedEnableHealthMonitoring
+	}
+
+	transformedIdleShutdown, err := expandNotebooksRuntimeSoftwareConfigIdleShutdown(original["idle_shutdown"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedIdleShutdown); val.IsValid() && !isEmptyValue(val) {
+		transformed["idleShutdown"] = transformedIdleShutdown
+	}
+
+	transformedIdleShutdownTimeout, err := expandNotebooksRuntimeSoftwareConfigIdleShutdownTimeout(original["idle_shutdown_timeout"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedIdleShutdownTimeout); val.IsValid() && !isEmptyValue(val) {
+		transformed["idleShutdownTimeout"] = transformedIdleShutdownTimeout
+	}
+
+	transformedInstallGpuDriver, err := expandNotebooksRuntimeSoftwareConfigInstallGpuDriver(original["install_gpu_driver"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedInstallGpuDriver); val.IsValid() && !isEmptyValue(val) {
+		transformed["installGpuDriver"] = transformedInstallGpuDriver
+	}
+
+	transformedCustomGpuDriverPath, err := expandNotebooksRuntimeSoftwareConfigCustomGpuDriverPath(original["custom_gpu_driver_path"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedCustomGpuDriverPath); val.IsValid() && !isEmptyValue(val) {
+		transformed["customGpuDriverPath"] = transformedCustomGpuDriverPath
+	}
+
+	transformedPostStartupScript, err := expandNotebooksRuntimeSoftwareConfigPostStartupScript(original["post_startup_script"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedPostStartupScript); val.IsValid() && !isEmptyValue(val) {
+		transformed["postStartupScript"] = transformedPostStartupScript
+	}
+
+	return transformed, nil
+}
+
+func expandNotebooksRuntimeSoftwareConfigNotebookUpgradeSchedule(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeSoftwareConfigEnableHealthMonitoring(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeSoftwareConfigIdleShutdown(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeSoftwareConfigIdleShutdownTimeout(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeSoftwareConfigInstallGpuDriver(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeSoftwareConfigCustomGpuDriverPath(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandNotebooksRuntimeSoftwareConfigPostStartupScript(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
diff --git a/converters/google/resources/notebooks_runtime_iam.go b/converters/google/resources/notebooks_runtime_iam.go
new file mode 100644
index 00000000..b7811f3c
--- /dev/null
+++ b/converters/google/resources/notebooks_runtime_iam.go
@@ -0,0 +1,120 @@
+// ----------------------------------------------------------------------------
+//
+//     ***     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 "fmt"
+
+// Provide a separate asset type constant so we don't have to worry about name conflicts between IAM and non-IAM converter files
+const NotebooksRuntimeIAMAssetType string = "notebooks.googleapis.com/Runtime"
+
+func resourceConverterNotebooksRuntimeIamPolicy() ResourceConverter {
+	return ResourceConverter{
+		AssetType:         NotebooksRuntimeIAMAssetType,
+		Convert:           GetNotebooksRuntimeIamPolicyCaiObject,
+		MergeCreateUpdate: MergeNotebooksRuntimeIamPolicy,
+	}
+}
+
+func resourceConverterNotebooksRuntimeIamBinding() ResourceConverter {
+	return ResourceConverter{
+		AssetType:         NotebooksRuntimeIAMAssetType,
+		Convert:           GetNotebooksRuntimeIamBindingCaiObject,
+		FetchFullResource: FetchNotebooksRuntimeIamPolicy,
+		MergeCreateUpdate: MergeNotebooksRuntimeIamBinding,
+		MergeDelete:       MergeNotebooksRuntimeIamBindingDelete,
+	}
+}
+
+func resourceConverterNotebooksRuntimeIamMember() ResourceConverter {
+	return ResourceConverter{
+		AssetType:         NotebooksRuntimeIAMAssetType,
+		Convert:           GetNotebooksRuntimeIamMemberCaiObject,
+		FetchFullResource: FetchNotebooksRuntimeIamPolicy,
+		MergeCreateUpdate: MergeNotebooksRuntimeIamMember,
+		MergeDelete:       MergeNotebooksRuntimeIamMemberDelete,
+	}
+}
+
+func GetNotebooksRuntimeIamPolicyCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
+	return newNotebooksRuntimeIamAsset(d, config, expandIamPolicyBindings)
+}
+
+func GetNotebooksRuntimeIamBindingCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
+	return newNotebooksRuntimeIamAsset(d, config, expandIamRoleBindings)
+}
+
+func GetNotebooksRuntimeIamMemberCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
+	return newNotebooksRuntimeIamAsset(d, config, expandIamMemberBindings)
+}
+
+func MergeNotebooksRuntimeIamPolicy(existing, incoming Asset) Asset {
+	existing.IAMPolicy = incoming.IAMPolicy
+	return existing
+}
+
+func MergeNotebooksRuntimeIamBinding(existing, incoming Asset) Asset {
+	return mergeIamAssets(existing, incoming, mergeAuthoritativeBindings)
+}
+
+func MergeNotebooksRuntimeIamBindingDelete(existing, incoming Asset) Asset {
+	return mergeDeleteIamAssets(existing, incoming, mergeDeleteAuthoritativeBindings)
+}
+
+func MergeNotebooksRuntimeIamMember(existing, incoming Asset) Asset {
+	return mergeIamAssets(existing, incoming, mergeAdditiveBindings)
+}
+
+func MergeNotebooksRuntimeIamMemberDelete(existing, incoming Asset) Asset {
+	return mergeDeleteIamAssets(existing, incoming, mergeDeleteAdditiveBindings)
+}
+
+func newNotebooksRuntimeIamAsset(
+	d TerraformResourceData,
+	config *Config,
+	expandBindings func(d TerraformResourceData) ([]IAMBinding, error),
+) ([]Asset, error) {
+	bindings, err := expandBindings(d)
+	if err != nil {
+		return []Asset{}, fmt.Errorf("expanding bindings: %v", err)
+	}
+
+	name, err := assetName(d, config, "//notebooks.googleapis.com/{{runtime}}")
+	if err != nil {
+		return []Asset{}, err
+	}
+
+	return []Asset{{
+		Name: name,
+		Type: NotebooksRuntimeIAMAssetType,
+		IAMPolicy: &IAMPolicy{
+			Bindings: bindings,
+		},
+	}}, nil
+}
+
+func FetchNotebooksRuntimeIamPolicy(d TerraformResourceData, config *Config) (Asset, error) {
+	// Check if the identity field returns a value
+	if _, ok := d.GetOk("{{runtime}}"); !ok {
+		return Asset{}, ErrEmptyIdentityField
+	}
+
+	return fetchIamPolicy(
+		NotebooksRuntimeIamUpdaterProducer,
+		d,
+		config,
+		"//notebooks.googleapis.com/{{runtime}}",
+		NotebooksRuntimeIAMAssetType,
+	)
+}
diff --git a/converters/google/resources/organization_iam_custom_role.go b/converters/google/resources/organization_iam_custom_role.go
new file mode 100644
index 00000000..7cebdfcc
--- /dev/null
+++ b/converters/google/resources/organization_iam_custom_role.go
@@ -0,0 +1,87 @@
+package google
+
+import (
+	"reflect"
+
+	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+const OrganizationIAMCustomRoleAssetType string = "iam.googleapis.com/Role"
+
+func resourceConverterOrganizationIAMCustomRole() ResourceConverter {
+	return ResourceConverter{
+		AssetType: OrganizationIAMCustomRoleAssetType,
+		Convert:   GetOrganizationIAMCustomRoleCaiObject,
+	}
+}
+
+func GetOrganizationIAMCustomRoleCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
+	name, err := assetName(d, config, "//iam.googleapis.com/organizations/{{org_id}}/roles/{{role_id}}")
+	if err != nil {
+		return []Asset{}, err
+	}
+	if obj, err := GetOrganizationIAMCustomRoleApiObject(d, config); err == nil {
+		return []Asset{{
+			Name: name,
+			Type: OrganizationIAMCustomRoleAssetType,
+			Resource: &AssetResource{
+				Version:              "v1",
+				DiscoveryDocumentURI: "https://iam.googleapis.com/$discovery/rest?version=v1",
+				DiscoveryName:        "Role",
+				Data:                 obj,
+			},
+		}}, nil
+	} else {
+		return []Asset{}, err
+	}
+}
+
+func GetOrganizationIAMCustomRoleApiObject(d TerraformResourceData, config *Config) (map[string]interface{}, error) {
+	obj := make(map[string]interface{})
+
+	descriptionProp, err := expandOrganizationIAMCustomRoleDescription(d.Get("description"), d, config)
+	if err != nil {
+		return nil, err
+	} else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) {
+		obj["description"] = descriptionProp
+	}
+
+	titleProp, err := expandOrganizationIAMCustomRoleTitle(d.Get("title"), d, config)
+	if err != nil {
+		return nil, err
+	} else if v, ok := d.GetOkExists("title"); !isEmptyValue(reflect.ValueOf(titleProp)) && (ok || !reflect.DeepEqual(v, titleProp)) {
+		obj["title"] = titleProp
+	}
+
+	stageProp, err := expandOrganizationIAMCustomRoleStage(d.Get("stage"), d, config)
+	if err != nil {
+		return nil, err
+	} else if v, ok := d.GetOkExists("stage"); !isEmptyValue(reflect.ValueOf(stageProp)) && (ok || !reflect.DeepEqual(v, stageProp)) {
+		obj["stage"] = stageProp
+	}
+
+	includedPermissionsProp, err := expandOrganizationIAMCustomRolePermissions(d.Get("permissions"), d, config)
+	if err != nil {
+		return nil, err
+	} else if v, ok := d.GetOkExists("permissions"); !isEmptyValue(reflect.ValueOf(includedPermissionsProp)) && (ok || !reflect.DeepEqual(v, includedPermissionsProp)) {
+		obj["includedPermissions"] = includedPermissionsProp
+	}
+
+	return obj, nil
+}
+
+func expandOrganizationIAMCustomRoleDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandOrganizationIAMCustomRoleTitle(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandOrganizationIAMCustomRoleStage(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandOrganizationIAMCustomRolePermissions(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v.(*schema.Set).List(), nil
+}
diff --git a/converters/google/resources/project_iam_custom_role.go b/converters/google/resources/project_iam_custom_role.go
new file mode 100644
index 00000000..2b6020a6
--- /dev/null
+++ b/converters/google/resources/project_iam_custom_role.go
@@ -0,0 +1,87 @@
+package google
+
+import (
+	"reflect"
+
+	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+const ProjectIAMCustomRoleAssetType string = "iam.googleapis.com/Role"
+
+func resourceConverterProjectIAMCustomRole() ResourceConverter {
+	return ResourceConverter{
+		AssetType: ProjectIAMCustomRoleAssetType,
+		Convert:   GetProjectIAMCustomRoleCaiObject,
+	}
+}
+
+func GetProjectIAMCustomRoleCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
+	name, err := assetName(d, config, "//iam.googleapis.com/projects/{{project}}/roles/{{role_id}}")
+	if err != nil {
+		return []Asset{}, err
+	}
+	if obj, err := GetProjectIAMCustomRoleApiObject(d, config); err == nil {
+		return []Asset{{
+			Name: name,
+			Type: ProjectIAMCustomRoleAssetType,
+			Resource: &AssetResource{
+				Version:              "v1",
+				DiscoveryDocumentURI: "https://iam.googleapis.com/$discovery/rest?version=v1",
+				DiscoveryName:        "Role",
+				Data:                 obj,
+			},
+		}}, nil
+	} else {
+		return []Asset{}, err
+	}
+}
+
+func GetProjectIAMCustomRoleApiObject(d TerraformResourceData, config *Config) (map[string]interface{}, error) {
+	obj := make(map[string]interface{})
+
+	descriptionProp, err := expandProjectIAMCustomRoleDescription(d.Get("description"), d, config)
+	if err != nil {
+		return nil, err
+	} else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) {
+		obj["description"] = descriptionProp
+	}
+
+	titleProp, err := expandProjectIAMCustomRoleTitle(d.Get("title"), d, config)
+	if err != nil {
+		return nil, err
+	} else if v, ok := d.GetOkExists("title"); !isEmptyValue(reflect.ValueOf(titleProp)) && (ok || !reflect.DeepEqual(v, titleProp)) {
+		obj["title"] = titleProp
+	}
+
+	stageProp, err := expandProjectIAMCustomRoleStage(d.Get("stage"), d, config)
+	if err != nil {
+		return nil, err
+	} else if v, ok := d.GetOkExists("stage"); !isEmptyValue(reflect.ValueOf(stageProp)) && (ok || !reflect.DeepEqual(v, stageProp)) {
+		obj["stage"] = stageProp
+	}
+
+	includedPermissionsProp, err := expandProjectIAMCustomRolePermissions(d.Get("permissions"), d, config)
+	if err != nil {
+		return nil, err
+	} else if v, ok := d.GetOkExists("permissions"); !isEmptyValue(reflect.ValueOf(includedPermissionsProp)) && (ok || !reflect.DeepEqual(v, includedPermissionsProp)) {
+		obj["includedPermissions"] = includedPermissionsProp
+	}
+
+	return obj, nil
+}
+
+func expandProjectIAMCustomRoleDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandProjectIAMCustomRoleTitle(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandProjectIAMCustomRoleStage(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandProjectIAMCustomRolePermissions(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v.(*schema.Set).List(), nil
+}
diff --git a/converters/google/resources/resource_converters.go b/converters/google/resources/resource_converters.go
index c0c8d9dd..53174bf4 100644
--- a/converters/google/resources/resource_converters.go
+++ b/converters/google/resources/resource_converters.go
@@ -23,15 +23,19 @@ package google
 // N:1 = [ResourceConverter{Convert: convertAbc, merge: mergeAbc}] (len=1)
 func ResourceConverters() map[string][]ResourceConverter {
 	return map[string][]ResourceConverter{
+		"google_compute_address":                           {resourceConverterComputeAddress()},
 		"google_compute_firewall":                          {resourceConverterComputeFirewall()},
 		"google_compute_disk":                              {resourceConverterComputeDisk()},
 		"google_compute_forwarding_rule":                   {resourceConverterComputeForwardingRule()},
+		"google_compute_global_address":                    {resourceConverterComputeGlobalAddress()},
 		"google_compute_global_forwarding_rule":            {resourceConverterComputeGlobalForwardingRule()},
 		"google_compute_instance":                          {resourceConverterComputeInstance()},
 		"google_compute_network":                           {resourceConverterComputeNetwork()},
 		"google_compute_snapshot":                          {resourceConverterComputeSnapshot()},
 		"google_compute_subnetwork":                        {resourceConverterComputeSubnetwork()},
+		"google_compute_ssl_policy":                        {resourceConverterComputeSslPolicy()},
 		"google_dns_managed_zone":                          {resourceConverterDNSManagedZone()},
+		"google_dns_policy":                                {resourceConverterDNSPolicy()},
 		"google_storage_bucket":                            {resourceConverterStorageBucket()},
 		"google_sql_database_instance":                     {resourceConverterSQLDatabaseInstance()},
 		"google_container_cluster":                         {resourceConverterContainerCluster()},
@@ -40,6 +44,7 @@ func ResourceConverters() map[string][]ResourceConverter {
 		"google_bigquery_dataset_iam_policy":               {resourceConverterBigqueryDatasetIamPolicy()},
 		"google_bigquery_dataset_iam_binding":              {resourceConverterBigqueryDatasetIamBinding()},
 		"google_bigquery_dataset_iam_member":               {resourceConverterBigqueryDatasetIamMember()},
+		"google_bigquery_table":                            {resourceConverterBigQueryTable()},
 		"google_spanner_instance":                          {resourceConverterSpannerInstance()},
 		"google_project_service":                           {resourceConverterServiceUsage()},
 		"google_pubsub_subscription":                       {resourceConverterPubsubSubscription()},
@@ -48,6 +53,13 @@ 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_monitoring_notification_channel":           {resourceConverterMonitoringNotificationChannel()},
+		"google_monitoring_alert_policy":                   {resourceConverterMonitoringAlertPolicy()},
+		"google_apigee_environment_iam_policy":             {resourceConverterApigeeEnvironmentIamPolicy()},
+		"google_apigee_environment_iam_binding":            {resourceConverterApigeeEnvironmentIamBinding()},
+		"google_apigee_environment_iam_member":             {resourceConverterApigeeEnvironmentIamMember()},
 		"google_bigquery_table_iam_policy":                 {resourceConverterBigQueryTableIamPolicy()},
 		"google_bigquery_table_iam_binding":                {resourceConverterBigQueryTableIamBinding()},
 		"google_bigquery_table_iam_member":                 {resourceConverterBigQueryTableIamMember()},
@@ -93,6 +105,9 @@ func ResourceConverters() map[string][]ResourceConverter {
 		"google_notebooks_instance_iam_policy":             {resourceConverterNotebooksInstanceIamPolicy()},
 		"google_notebooks_instance_iam_binding":            {resourceConverterNotebooksInstanceIamBinding()},
 		"google_notebooks_instance_iam_member":             {resourceConverterNotebooksInstanceIamMember()},
+		"google_notebooks_runtime_iam_policy":              {resourceConverterNotebooksRuntimeIamPolicy()},
+		"google_notebooks_runtime_iam_binding":             {resourceConverterNotebooksRuntimeIamBinding()},
+		"google_notebooks_runtime_iam_member":              {resourceConverterNotebooksRuntimeIamMember()},
 		"google_privateca_ca_pool_iam_policy":              {resourceConverterPrivatecaCaPoolIamPolicy()},
 		"google_privateca_ca_pool_iam_binding":             {resourceConverterPrivatecaCaPoolIamBinding()},
 		"google_privateca_ca_pool_iam_member":              {resourceConverterPrivatecaCaPoolIamMember()},
@@ -116,21 +131,23 @@ func ResourceConverters() map[string][]ResourceConverter {
 			resourceConverterBigtableInstance(),
 			resourceConverterBigtableCluster(),
 		},
-		"google_organization_iam_policy":     {resourceConverterOrganizationIamPolicy()},
-		"google_organization_iam_binding":    {resourceConverterOrganizationIamBinding()},
-		"google_organization_iam_member":     {resourceConverterOrganizationIamMember()},
-		"google_project_organization_policy": {resourceConverterProjectOrgPolicy()},
-		"google_folder_iam_policy":           {resourceConverterFolderIamPolicy()},
-		"google_folder_iam_binding":          {resourceConverterFolderIamBinding()},
-		"google_folder_iam_member":           {resourceConverterFolderIamMember()},
-		"google_kms_crypto_key_iam_policy":   {resourceConverterKmsCryptoKeyIamPolicy()},
-		"google_kms_crypto_key_iam_binding":  {resourceConverterKmsCryptoKeyIamBinding()},
-		"google_kms_crypto_key_iam_member":   {resourceConverterKmsCryptoKeyIamMember()},
-		"google_kms_key_ring_iam_policy":     {resourceConverterKmsKeyRingIamPolicy()},
-		"google_kms_key_ring_iam_binding":    {resourceConverterKmsKeyRingIamBinding()},
-		"google_kms_key_ring_iam_member":     {resourceConverterKmsKeyRingIamMember()},
-		"google_project_iam_policy":          {resourceConverterProjectIamPolicy()},
-		"google_project_iam_binding":         {resourceConverterProjectIamBinding()},
-		"google_project_iam_member":          {resourceConverterProjectIamMember()},
+		"google_organization_iam_policy":      {resourceConverterOrganizationIamPolicy()},
+		"google_organization_iam_binding":     {resourceConverterOrganizationIamBinding()},
+		"google_organization_iam_member":      {resourceConverterOrganizationIamMember()},
+		"google_project_organization_policy":  {resourceConverterProjectOrgPolicy()},
+		"google_folder_iam_policy":            {resourceConverterFolderIamPolicy()},
+		"google_folder_iam_binding":           {resourceConverterFolderIamBinding()},
+		"google_folder_iam_member":            {resourceConverterFolderIamMember()},
+		"google_kms_crypto_key_iam_policy":    {resourceConverterKmsCryptoKeyIamPolicy()},
+		"google_kms_crypto_key_iam_binding":   {resourceConverterKmsCryptoKeyIamBinding()},
+		"google_kms_crypto_key_iam_member":    {resourceConverterKmsCryptoKeyIamMember()},
+		"google_kms_key_ring_iam_policy":      {resourceConverterKmsKeyRingIamPolicy()},
+		"google_kms_key_ring_iam_binding":     {resourceConverterKmsKeyRingIamBinding()},
+		"google_kms_key_ring_iam_member":      {resourceConverterKmsKeyRingIamMember()},
+		"google_project_iam_policy":           {resourceConverterProjectIamPolicy()},
+		"google_project_iam_binding":          {resourceConverterProjectIamBinding()},
+		"google_project_iam_member":           {resourceConverterProjectIamMember()},
+		"google_project_iam_custom_role":      {resourceConverterProjectIAMCustomRole()},
+		"google_organization_iam_custom_role": {resourceConverterOrganizationIAMCustomRole()},
 	}
 }
diff --git a/docs/policy_library.md b/docs/policy_library.md
index 813f2bcd..e2387d56 100644
--- a/docs/policy_library.md
+++ b/docs/policy_library.md
@@ -19,7 +19,8 @@ A Policy Library repository contains the following directories:
 *   `policies`
     *   `constraints`: This is initially empty. You should place your constraint
         files here.
-    *   `templates`: This directory contains pre-defined constraint templates.
+    *   `templates`: This directory contains pre-defined constraint template logic
+        that constraints then parameterize.
 *   `validator`: This directory contains the `.rego` files and their associated
     unit tests. You do not need to touch this directory unless you intend to
     modify existing constraint templates or create new ones. Running `make
@@ -40,11 +41,6 @@ This policy library can also be made public, but it is not recommended. By
 making your policy library public, it would be allowing others to see what you
 are and __ARE NOT__ scanning for.
 
-To run the following commands, you will need to configure git to connect
-securely. It is recommended to connect with SSH. [Here is a helpful resource](https://help.github.com/en/github/authenticating-to-github/connecting-to-github-with-ssh) for learning about how
-this works, including steps to set this up for GitHub repositories; other
-providers offer this feature as well.
-
 ```
 export GIT_REPO_ADDR="git@github.com:${YOUR_GITHUB_USERNAME}/policy-library.git"
 git clone --bare https://github.com/GoogleCloudPlatform/policy-library.git
@@ -59,7 +55,7 @@ git clone ${GIT_REPO_ADDR}
 
 Then you need to examine the available constraint templates inside the
 `templates` directory. Pick the constraint templates that you wish to use,
-create constraint YAML files corresponding to those templates, and place them
+create constraint YAML files [providing the inputs for those templates](https://github.com/GoogleCloudPlatform/policy-library/blob/aeb91d2274d14a52d5f6ecd5723ea509e3d94050/samples/allowed_resource_types.yaml), and place them
 under `policies/constraints`. Commit the newly created constraint files to
 **your** Git repository. For example, assuming you have created a Git repository
 named "policy-library" under your GitHub account, you can use the following
diff --git a/docs/supported_resources.md b/docs/supported_resources.md
index d5c37763..d1276b57 100644
--- a/docs/supported_resources.md
+++ b/docs/supported_resources.md
@@ -12,6 +12,7 @@ google_bigquery_dataset                          | bigquery.googleapis.com/Datas
 google_bigquery_dataset_iam_binding              | bigquery.googleapis.com/Dataset
 google_bigquery_dataset_iam_member               | bigquery.googleapis.com/Dataset
 google_bigquery_dataset_iam_policy               | bigquery.googleapis.com/Dataset
+google_bigquery_table                            | bigquery.googleapis.com/Table
 google_bigquery_table_iam_binding                | bigquery.googleapis.com/Table
 google_bigquery_table_iam_member                 | bigquery.googleapis.com/Table
 google_bigquery_table_iam_policy                 | bigquery.googleapis.com/Table
diff --git a/docs/user_guide.md b/docs/user_guide.md
index 61eda3f1..925d8f01 100644
--- a/docs/user_guide.md
+++ b/docs/user_guide.md
@@ -17,16 +17,17 @@ terraform show -json ./tfplan.tfplan > ./tfplan.json
 
 In particular, you can use the following environment variables (in order of precedence) to provide a [service account key file](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference#full-reference):
 
-
+- `GOOGLE_APPLICATION_CREDENTIALS`
 - `GOOGLE_CREDENTIALS`
 - `GOOGLE_CLOUD_KEYFILE_JSON`
 - `GOOGLE_KEYFILE_JSON`
+- `GOOGLE_OAUTH_ACCESS_TOKEN`*
 
-Using Terraform-Validator-specific [service accounts](https://cloud.google.com/docs/authentication/getting-started) is the recommended practice when using Terraform Validator.
+<sub>*[uses oauth2 token](https://developers.google.com/identity/protocols/oauth2)</sub>
 
-You can also authenticate using an [OAuth 2.0 access token](https://developers.google.com/identity/protocols/OAuth2), which can be provided via the `GOOGLE_OAUTH_ACCESS_TOKEN` environment variable.
+Using Terraform-Validator-specific [service accounts](https://cloud.google.com/docs/authentication/getting-started) is the recommended practice when using Terraform Validator.
 
-For local development, you can also use [Google Application Default Credentials](https://cloud.google.com/docs/authentication/production) by providing the path to your application default credentials file via the `GOOGLE_APPLICATION_CREDENTIALS` environment variable.
+You can also use [Google Application Default Credentials](https://cloud.google.com/docs/authentication/production) by providing the path to your application default credentials file via the `GOOGLE_APPLICATION_CREDENTIALS` environment variable. This strategy is only recommended for local development
 
 ```
 gcloud auth application-default login  # local development only


Test patch:
diff --git a/.ci/cloudbuild-tests-go-licenses.yaml b/.ci/cloudbuild-tests-go-licenses.yaml
new file mode 100644
index 00000000..46fad1e1
--- /dev/null
+++ b/.ci/cloudbuild-tests-go-licenses.yaml
@@ -0,0 +1,26 @@
+# 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
+#
+#     https://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.
+
+# See cloud-foundation-cicd project
+
+timeout: 1800s
+steps:
+- id: test-go-licenses
+  name: 'gcr.io/graphite-docker-images/terraform-validator-builder'
+  entrypoint: /bin/bash
+  args: ['-c', 'make test-go-licenses']
+tags:
+- 'ci'
+options:
+  machineType: 'N1_HIGHCPU_8'
diff --git a/.ci/cloudbuild-tests-integration.yaml b/.ci/cloudbuild-tests-integration.yaml
index d3e47e1f..05ecfdd5 100644
--- a/.ci/cloudbuild-tests-integration.yaml
+++ b/.ci/cloudbuild-tests-integration.yaml
@@ -17,7 +17,7 @@
 timeout: 3600s
 steps:
 - id: build
-  name: 'gcr.io/cloud-builders/go'
+  name: 'gcr.io/cloud-builders/go:1.15'
   entrypoint: /usr/bin/make
   args: [build]
 - id: test-integration
diff --git a/.ci/cloudbuild-tests-unit.yaml b/.ci/cloudbuild-tests-unit.yaml
index cc27e212..d9704f1c 100644
--- a/.ci/cloudbuild-tests-unit.yaml
+++ b/.ci/cloudbuild-tests-unit.yaml
@@ -17,11 +17,11 @@
 timeout: 1800s
 steps:
 - id: build
-  name: 'gcr.io/cloud-builders/go'
+  name: 'gcr.io/cloud-builders/go:1.15'
   entrypoint: /usr/bin/make
-  args: [build]
+  args: ['build']
 - id: test
-  name: 'gcr.io/cloud-builders/go'
+  name: 'gcr.io/cloud-builders/go:1.15'
   entrypoint: /usr/bin/make
   args: ['test']
   env:
diff --git a/test/cli_test.go b/test/cli_test.go
index 5ae04558..3e1c26a4 100644
--- a/test/cli_test.go
+++ b/test/cli_test.go
@@ -54,62 +54,77 @@ func TestCLI(t *testing.T) {
 		constraints          []constraint
 		compareConvertOutput compareConvertOutputFunc
 	}{
+		// cli-only, the following tests are not in read_test or
+		// have unique paramters that seperate them
 		{name: "bucket"},
 		{name: "disk"},
 		{name: "firewall"},
 		{name: "instance"},
 		{name: "sql"},
+		{name: "example_compute_forwarding_rule"},
+		{name: "example_compute_instance"},
+		{name: "example_project_create", constraints: []constraint{alwaysViolate, {name: "project_match_target", wantViolation: false, wantOutputRegex: ""}}},
+		{name: "example_project_update", constraints: []constraint{alwaysViolate, {name: "project_match_target", wantViolation: true, wantOutputRegex: "Constraint GCPAlwaysViolatesConstraintV1.always_violates_project_match_target on resource"}}},
+		{name: "example_project_iam_binding", compareConvertOutput: compareMergedIamBindingOutput},
+		{name: "example_project_iam_member", compareConvertOutput: compareMergedIamMemberOutput},
+		{name: "example_storage_bucket_iam_binding", compareConvertOutput: compareMergedIamBindingOutput},
+		{name: "example_storage_bucket_iam_member", compareConvertOutput: compareMergedIamMemberOutput},
+		// auto inserted tests that are not in list above or manually inserted in read_test.go
 		{name: "example_access_context_manager_service_perimeter"},
 		{name: "example_bigquery_dataset"},
-		{name: "example_bigquery_dataset_iam_policy"},
 		{name: "example_bigquery_dataset_iam_binding"},
 		{name: "example_bigquery_dataset_iam_member"},
+		{name: "example_bigquery_dataset_iam_policy"},
+		{name: "example_bigquery_table"},
 		{name: "example_bigtable_instance"},
+		{name: "example_cloud_run_mapping"},
+		{name: "example_cloud_run_service"},
+		{name: "example_compute_address"},
 		{name: "example_compute_disk"},
 		{name: "example_compute_disk_empty_image"},
 		{name: "example_compute_firewall"},
-		{name: "example_compute_forwarding_rule"},
-		{name: "example_compute_instance"},
+		{name: "example_compute_global_address"},
+		{name: "example_compute_global_forwarding_rule"},
 		{name: "example_compute_network"},
 		{name: "example_compute_snapshot"},
+		{name: "example_compute_ssl_policy"},
 		{name: "example_compute_subnetwork"},
-		{name: "example_compute_global_forwarding_rule"},
 		{name: "example_container_cluster"},
 		{name: "example_dns_managed_zone"},
+		{name: "example_dns_policy"},
 		{name: "example_filestore_instance"},
 		{name: "example_kms_crypto_key"},
 		{name: "example_kms_crypto_key_iam_binding"},
 		{name: "example_kms_crypto_key_iam_member"},
 		{name: "example_kms_crypto_key_iam_policy"},
 		{name: "example_kms_key_ring"},
-		{name: "example_kms_key_ring_iam_policy"},
 		{name: "example_kms_key_ring_iam_binding"},
 		{name: "example_kms_key_ring_iam_member"},
+		{name: "example_kms_key_ring_iam_policy"},
+		{name: "example_monitoring_alert_policy"},
+		{name: "example_monitoring_notification_channel"},
 		{name: "example_organization_iam_binding"},
+		{name: "example_organization_iam_custom_role"},
 		{name: "example_organization_iam_member"},
 		{name: "example_organization_iam_policy"},
-		{name: "example_pubsub_topic"},
-		{name: "example_pubsub_subscription"},
-		{name: "example_project_create", constraints: []constraint{alwaysViolate, constraint{name: "project_match_target", wantViolation: false, wantOutputRegex: ""}}},
-		{name: "example_project_update", constraints: []constraint{alwaysViolate, constraint{name: "project_match_target", wantViolation: true, wantOutputRegex: "Constraint GCPAlwaysViolatesConstraintV1.always_violates_project_match_target on resource"}}},
-		{name: "example_project_in_org"},
-		{name: "example_project_in_folder"},
 		{name: "example_project_iam"},
-		{name: "example_project_iam_binding", compareConvertOutput: compareMergedIamBindingOutput},
-		{name: "example_project_iam_member", compareConvertOutput: compareMergedIamMemberOutput},
+		{name: "example_project_iam_custom_role"},
 		{name: "example_project_iam_policy"},
+		{name: "example_project_in_folder"},
+		{name: "example_project_in_org"},
 		{name: "example_project_organization_policy"},
 		{name: "example_project_service"},
+		{name: "example_pubsub_subscription"},
+		{name: "example_pubsub_topic"},
 		{name: "example_sql_database_instance"},
 		{name: "example_storage_bucket"},
-		{name: "example_storage_bucket_iam_binding", compareConvertOutput: compareMergedIamBindingOutput},
-		{name: "example_storage_bucket_iam_member", compareConvertOutput: compareMergedIamMemberOutput},
 		{name: "example_storage_bucket_iam_member_random_suffix"},
 		{name: "example_storage_bucket_iam_policy"},
 		{name: "full_compute_firewall"},
 		{name: "full_compute_instance"},
 		{name: "full_container_cluster"},
 		{name: "full_container_node_pool"},
+		{name: "full_spanner_instance"},
 		{name: "full_sql_database_instance"},
 		{name: "full_storage_bucket"},
 	}
diff --git a/test/read_test.go b/test/read_test.go
index ceafb466..532fd3b0 100644
--- a/test/read_test.go
+++ b/test/read_test.go
@@ -20,61 +20,71 @@ func TestReadPlannedAssetsCoverage(t *testing.T) {
 	cases := []struct {
 		name string
 	}{
+		// read-only, the following tests are not in cli_test or
+		// have unique paramters that seperate them
+		{name: "example_project_create"},
+		{name: "example_project_update"},
+		{name: "example_project_iam_binding"},
+		{name: "example_project_iam_member"},
+		{name: "example_storage_bucket_iam_binding"},
+		{name: "example_storage_bucket_iam_member"},
+		// auto inserted tests that are not in list above or manually inserted in cli_test.go
 		{name: "example_access_context_manager_service_perimeter"},
 		{name: "example_bigquery_dataset"},
-		{name: "example_bigquery_dataset_iam_policy"},
 		{name: "example_bigquery_dataset_iam_binding"},
 		{name: "example_bigquery_dataset_iam_member"},
+		{name: "example_bigquery_dataset_iam_policy"},
+		{name: "example_bigquery_table"},
 		{name: "example_bigtable_instance"},
+		{name: "example_cloud_run_mapping"},
+		{name: "example_cloud_run_service"},
+		{name: "example_compute_address"},
 		{name: "example_compute_disk"},
 		{name: "example_compute_disk_empty_image"},
 		{name: "example_compute_firewall"},
-		// This test can't run in offline mode
-		// {name: "example_compute_instance"},
+		{name: "example_compute_global_address"},
+		{name: "example_compute_global_forwarding_rule"},
 		{name: "example_compute_network"},
 		{name: "example_compute_snapshot"},
+		{name: "example_compute_ssl_policy"},
 		{name: "example_compute_subnetwork"},
-		// This test can't run in offline mode.
-		// {name: "example_compute_forwarding_rule"},
-		{name: "example_compute_global_forwarding_rule"},
 		{name: "example_container_cluster"},
 		{name: "example_dns_managed_zone"},
+		{name: "example_dns_policy"},
 		{name: "example_filestore_instance"},
 		{name: "example_kms_crypto_key"},
 		{name: "example_kms_crypto_key_iam_binding"},
 		{name: "example_kms_crypto_key_iam_member"},
 		{name: "example_kms_crypto_key_iam_policy"},
 		{name: "example_kms_key_ring"},
-		{name: "example_kms_key_ring_iam_policy"},
 		{name: "example_kms_key_ring_iam_binding"},
 		{name: "example_kms_key_ring_iam_member"},
+		{name: "example_kms_key_ring_iam_policy"},
+		{name: "example_monitoring_alert_policy"},
+		{name: "example_monitoring_notification_channel"},
 		{name: "example_organization_iam_binding"},
+		{name: "example_organization_iam_custom_role"},
 		{name: "example_organization_iam_member"},
 		{name: "example_organization_iam_policy"},
-		{name: "example_pubsub_topic"},
-		{name: "example_pubsub_subscription"},
-		{name: "example_project_create"},
-		{name: "example_project_update"},
-		{name: "example_project_in_org"},
-		{name: "example_project_in_folder"},
-		{name: "example_project_organization_policy"},
 		{name: "example_project_iam"},
-		{name: "example_project_iam_binding"},
-		{name: "example_project_iam_member"},
+		{name: "example_project_iam_custom_role"},
 		{name: "example_project_iam_policy"},
+		{name: "example_project_in_folder"},
+		{name: "example_project_in_org"},
+		{name: "example_project_organization_policy"},
 		{name: "example_project_service"},
+		{name: "example_pubsub_subscription"},
+		{name: "example_pubsub_topic"},
 		{name: "example_sql_database_instance"},
 		{name: "example_storage_bucket"},
-		{name: "example_storage_bucket_iam_binding"},
-		{name: "example_storage_bucket_iam_member"},
 		{name: "example_storage_bucket_iam_member_random_suffix"},
 		{name: "example_storage_bucket_iam_policy"},
 		{name: "full_compute_firewall"},
 		{name: "full_compute_instance"},
 		{name: "full_container_cluster"},
 		{name: "full_container_node_pool"},
-		{name: "full_sql_database_instance"},
 		{name: "full_spanner_instance"},
+		{name: "full_sql_database_instance"},
 		{name: "full_storage_bucket"},
 	}
 	for i := range cases {
diff --git a/testdata/templates/example_bigquery_table.json b/testdata/templates/example_bigquery_table.json
new file mode 100644
index 00000000..79f96366
--- /dev/null
+++ b/testdata/templates/example_bigquery_table.json
@@ -0,0 +1,21 @@
+[
+  {
+    "name": "//bigquery.googleapis.com/projects/{{.Provider.project}}/datasets/dataset/tables/table",
+    "asset_type": "bigquery.googleapis.com/Table",
+    "ancestry_path": "{{.Ancestry}}/project/{{.Provider.project}}",
+    "resource": {
+      "version": "v2",
+      "discovery_document_uri": "https://www.googleapis.com/discovery/v1/apis/bigquery/v2/rest",
+      "discovery_name": "Table",
+      "parent": "//cloudresourcemanager.googleapis.com/projects/{{.Provider.project}}",
+      "data": {
+        "friendlyName": "friendly table",
+        "tableReference": {
+          "datasetId": "dataset",
+          "project": "{{.Provider.project}}",
+          "tableId": "table"
+        }
+      }
+    }
+  }
+]
diff --git a/testdata/templates/example_bigquery_table.tf b/testdata/templates/example_bigquery_table.tf
new file mode 100644
index 00000000..0f49f7ac
--- /dev/null
+++ b/testdata/templates/example_bigquery_table.tf
@@ -0,0 +1,51 @@
+/**
+ * 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_bigquery_table" "table" {
+dataset_id          = "dataset"
+project             = "{{.Provider.project}}"
+table_id            = "table"
+friendly_name       = "friendly table"
+
+schema = <<EOF
+[
+  {
+    "name": "Card_Number",
+    "mode": "NULLABLE",
+    "type": "STRING"
+  },
+  {
+    "name": "Card_Holders_Name",
+    "mode": "NULLABLE",
+    "type": "STRING"
+  }
+]
+EOF
+
+}
\ No newline at end of file
diff --git a/testdata/templates/example_bigquery_table.tfplan.json b/testdata/templates/example_bigquery_table.tfplan.json
new file mode 100644
index 00000000..236c78e4
--- /dev/null
+++ b/testdata/templates/example_bigquery_table.tfplan.json
@@ -0,0 +1,117 @@
+{
+  "format_version": "0.1",
+  "terraform_version": "0.13.5",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_bigquery_table.table",
+          "mode": "managed",
+          "type": "google_bigquery_table",
+          "name": "table",
+          "provider_name": "registry.terraform.io/hashicorp/google",
+          "schema_version": 0,
+          "values": {
+            "clustering": null,
+            "dataset_id": "dataset",
+            "deletion_protection": true,
+            "description": null,
+            "encryption_configuration": [],
+            "external_data_configuration": [],
+            "friendly_name": "friendly table",
+            "labels": null,
+            "materialized_view": [],
+            "project": "{{.Provider.project}}",
+            "range_partitioning": [],
+            "schema": "[{\"mode\":\"NULLABLE\",\"name\":\"Card_Number\",\"type\":\"STRING\"},{\"mode\":\"NULLABLE\",\"name\":\"Card_Holders_Name\",\"type\":\"STRING\"}]",
+            "table_id": "table",
+            "time_partitioning": [],
+            "view": []
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "google_bigquery_table.table",
+      "mode": "managed",
+      "type": "google_bigquery_table",
+      "name": "table",
+      "provider_name": "registry.terraform.io/hashicorp/google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "clustering": null,
+          "dataset_id": "dataset",
+          "deletion_protection": true,
+          "description": null,
+          "encryption_configuration": [],
+          "external_data_configuration": [],
+          "friendly_name": "friendly table",
+          "labels": null,
+          "materialized_view": [],
+          "project": "{{.Provider.project}}",
+          "range_partitioning": [],
+          "schema": "[{\"mode\":\"NULLABLE\",\"name\":\"Card_Number\",\"type\":\"STRING\"},{\"mode\":\"NULLABLE\",\"name\":\"Card_Holders_Name\",\"type\":\"STRING\"}]",
+          "table_id": "table",
+          "time_partitioning": [],
+          "view": []
+        },
+        "after_unknown": {
+          "creation_time": true,
+          "encryption_configuration": [],
+          "etag": true,
+          "expiration_time": true,
+          "external_data_configuration": [],
+          "id": true,
+          "last_modified_time": true,
+          "location": true,
+          "materialized_view": [],
+          "num_bytes": true,
+          "num_long_term_bytes": true,
+          "num_rows": true,
+          "range_partitioning": [],
+          "self_link": true,
+          "time_partitioning": [],
+          "type": true,
+          "view": []
+        }
+      }
+    }
+  ],
+  "configuration": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_bigquery_table.table",
+          "mode": "managed",
+          "type": "google_bigquery_table",
+          "name": "table",
+          "provider_config_key": "google",
+          "expressions": {
+            "dataset_id": {
+              "constant_value": "dataset"
+            },
+            "friendly_name": {
+              "constant_value": "friendly table"
+            },
+            "project": {
+              "constant_value": "{{.Provider.project}}"
+            },
+            "schema": {
+              "constant_value": "[\n  {\n    \"name\": \"Card_Number\",\n    \"mode\": \"NULLABLE\",\n    \"type\": \"STRING\"\n  },\n  {\n    \"name\": \"Card_Holders_Name\",\n    \"mode\": \"NULLABLE\",\n    \"type\": \"STRING\"\n  }\n]\n"
+            },
+            "table_id": {
+              "constant_value": "table"
+            }
+          },
+          "schema_version": 0
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
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
+        }
+      ]
+    }
+  }
+}
diff --git a/testdata/templates/example_compute_address.json b/testdata/templates/example_compute_address.json
new file mode 100644
index 00000000..403a31b8
--- /dev/null
+++ b/testdata/templates/example_compute_address.json
@@ -0,0 +1,53 @@
+[
+  {
+    "name": "//compute.googleapis.com/projects/{{.Provider.project}}/global/networks/my-network",
+    "asset_type": "compute.googleapis.com/Network",
+    "ancestry_path": "{{.Ancestry}}/project/{{.Provider.project}}",
+    "resource": {
+      "version": "v1",
+      "discovery_document_uri": "https://www.googleapis.com/discovery/v1/apis/compute/v1/rest",
+      "discovery_name": "Network",
+      "parent": "//cloudresourcemanager.googleapis.com/projects/{{.Provider.project}}",
+      "data": {
+        "autoCreateSubnetworks": true,
+        "name": "my-network"
+      }
+    }
+  },
+  {
+    "name": "//compute.googleapis.com/projects/{{.Provider.project}}/regions/us-central1/addresses/my-internal-address",
+    "asset_type": "compute.googleapis.com/Address",
+    "ancestry_path": "{{.Ancestry}}/project/{{.Provider.project}}",
+    "resource": {
+      "version": "v1",
+      "discovery_document_uri": "https://www.googleapis.com/discovery/v1/apis/compute/v1/rest",
+      "discovery_name": "Address",
+      "parent": "//cloudresourcemanager.googleapis.com/projects/{{.Provider.project}}",
+      "data": {
+        "address": "10.0.42.42",
+        "addressType": "INTERNAL",
+        "name": "my-internal-address",
+        "region": "projects/{{.Provider.project}}/global/regions/us-central1"
+      }
+    }
+  },
+  {
+    "name": "//compute.googleapis.com/projects/{{.Provider.project}}/regions/us-central1/subnetworks/my-subnet",
+    "asset_type": "compute.googleapis.com/Subnetwork",
+    "ancestry_path": "{{.Ancestry}}/project/{{.Provider.project}}",
+    "resource": {
+      "version": "v1",
+      "discovery_document_uri": "https://www.googleapis.com/discovery/v1/apis/compute/v1/rest",
+      "discovery_name": "Subnetwork",
+      "parent": "//cloudresourcemanager.googleapis.com/projects/{{.Provider.project}}",
+      "data": {
+        "ipCidrRange": "10.0.0.0/16",
+        "logConfig": {
+          "enable": false
+        },
+        "name": "my-subnet",
+        "region": "projects/{{.Provider.project}}/global/regions/us-central1"
+      }
+    }
+  }
+]
diff --git a/testdata/templates/example_compute_address.tf b/testdata/templates/example_compute_address.tf
new file mode 100644
index 00000000..0755c67f
--- /dev/null
+++ b/testdata/templates/example_compute_address.tf
@@ -0,0 +1,47 @@
+/**
+ * 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_compute_network" "default" {
+  name = "my-network"
+}
+
+resource "google_compute_subnetwork" "default" {
+  name          = "my-subnet"
+  ip_cidr_range = "10.0.0.0/16"
+  region        = "us-central1"
+  network       = google_compute_network.default.id
+}
+
+resource "google_compute_address" "internal_with_subnet_and_address" {
+  name         = "my-internal-address"
+  subnetwork   = google_compute_subnetwork.default.id
+  address_type = "INTERNAL"
+  address      = "10.0.42.42"
+  region       = "us-central1"
+}
diff --git a/testdata/templates/example_compute_address.tfplan.json b/testdata/templates/example_compute_address.tfplan.json
new file mode 100644
index 00000000..d5d68aa6
--- /dev/null
+++ b/testdata/templates/example_compute_address.tfplan.json
@@ -0,0 +1,266 @@
+{
+  "format_version": "0.2",
+  "terraform_version": "1.0.10",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_compute_address.internal_with_subnet_and_address",
+          "mode": "managed",
+          "type": "google_compute_address",
+          "name": "internal_with_subnet_and_address",
+          "provider_name": "registry.terraform.io/hashicorp/google",
+          "schema_version": 0,
+          "values": {
+            "address": "10.0.42.42",
+            "address_type": "INTERNAL",
+            "description": null,
+            "name": "my-internal-address",
+            "network": null,
+            "prefix_length": null,
+            "region": "us-central1",
+            "timeouts": null
+          },
+          "sensitive_values": {
+            "users": []
+          }
+        },
+        {
+          "address": "google_compute_network.default",
+          "mode": "managed",
+          "type": "google_compute_network",
+          "name": "default",
+          "provider_name": "registry.terraform.io/hashicorp/google",
+          "schema_version": 0,
+          "values": {
+            "auto_create_subnetworks": true,
+            "delete_default_routes_on_create": false,
+            "description": null,
+            "name": "my-network",
+            "timeouts": null
+          },
+          "sensitive_values": {}
+        },
+        {
+          "address": "google_compute_subnetwork.default",
+          "mode": "managed",
+          "type": "google_compute_subnetwork",
+          "name": "default",
+          "provider_name": "registry.terraform.io/hashicorp/google",
+          "schema_version": 0,
+          "values": {
+            "description": null,
+            "ip_cidr_range": "10.0.0.0/16",
+            "ipv6_access_type": null,
+            "log_config": [],
+            "name": "my-subnet",
+            "private_ip_google_access": null,
+            "region": "us-central1",
+            "role": null,
+            "timeouts": null
+          },
+          "sensitive_values": {
+            "log_config": [],
+            "secondary_ip_range": []
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "google_compute_address.internal_with_subnet_and_address",
+      "mode": "managed",
+      "type": "google_compute_address",
+      "name": "internal_with_subnet_and_address",
+      "provider_name": "registry.terraform.io/hashicorp/google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "address": "10.0.42.42",
+          "address_type": "INTERNAL",
+          "description": null,
+          "name": "my-internal-address",
+          "network": null,
+          "prefix_length": null,
+          "region": "us-central1",
+          "timeouts": null
+        },
+        "after_unknown": {
+          "creation_timestamp": true,
+          "id": true,
+          "network_tier": true,
+          "project": true,
+          "purpose": true,
+          "self_link": true,
+          "subnetwork": true,
+          "users": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {
+          "users": []
+        }
+      }
+    },
+    {
+      "address": "google_compute_network.default",
+      "mode": "managed",
+      "type": "google_compute_network",
+      "name": "default",
+      "provider_name": "registry.terraform.io/hashicorp/google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "auto_create_subnetworks": true,
+          "delete_default_routes_on_create": false,
+          "description": null,
+          "name": "my-network",
+          "timeouts": null
+        },
+        "after_unknown": {
+          "gateway_ipv4": true,
+          "id": true,
+          "mtu": true,
+          "project": true,
+          "routing_mode": true,
+          "self_link": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    },
+    {
+      "address": "google_compute_subnetwork.default",
+      "mode": "managed",
+      "type": "google_compute_subnetwork",
+      "name": "default",
+      "provider_name": "registry.terraform.io/hashicorp/google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "description": null,
+          "ip_cidr_range": "10.0.0.0/16",
+          "ipv6_access_type": null,
+          "log_config": [],
+          "name": "my-subnet",
+          "private_ip_google_access": null,
+          "region": "us-central1",
+          "role": null,
+          "timeouts": null
+        },
+        "after_unknown": {
+          "creation_timestamp": true,
+          "external_ipv6_prefix": true,
+          "fingerprint": true,
+          "gateway_address": true,
+          "id": true,
+          "ipv6_cidr_range": true,
+          "log_config": [],
+          "network": true,
+          "private_ipv6_google_access": true,
+          "project": true,
+          "purpose": true,
+          "secondary_ip_range": true,
+          "self_link": true,
+          "stack_type": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {
+          "log_config": [],
+          "secondary_ip_range": []
+        }
+      }
+    }
+  ],
+  "configuration": {
+    "provider_config": {
+      "google": {
+        "name": "google",
+        "expressions": {
+          "project": {
+            "constant_value": "{{.Provider.project}}"
+          }
+        }
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_compute_address.internal_with_subnet_and_address",
+          "mode": "managed",
+          "type": "google_compute_address",
+          "name": "internal_with_subnet_and_address",
+          "provider_config_key": "google",
+          "expressions": {
+            "address": {
+              "constant_value": "10.0.42.42"
+            },
+            "address_type": {
+              "constant_value": "INTERNAL"
+            },
+            "name": {
+              "constant_value": "my-internal-address"
+            },
+            "region": {
+              "constant_value": "us-central1"
+            },
+            "subnetwork": {
+              "references": [
+                "google_compute_subnetwork.default.id",
+                "google_compute_subnetwork.default"
+              ]
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "google_compute_network.default",
+          "mode": "managed",
+          "type": "google_compute_network",
+          "name": "default",
+          "provider_config_key": "google",
+          "expressions": {
+            "name": {
+              "constant_value": "my-network"
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "google_compute_subnetwork.default",
+          "mode": "managed",
+          "type": "google_compute_subnetwork",
+          "name": "default",
+          "provider_config_key": "google",
+          "expressions": {
+            "ip_cidr_range": {
+              "constant_value": "10.0.0.0/16"
+            },
+            "name": {
+              "constant_value": "my-subnet"
+            },
+            "network": {
+              "references": [
+                "google_compute_network.default.id",
+                "google_compute_network.default"
+              ]
+            },
+            "region": {
+              "constant_value": "us-central1"
+            }
+          },
+          "schema_version": 0
+        }
+      ]
+    }
+  }
+}
diff --git a/testdata/templates/example_compute_global_address.json b/testdata/templates/example_compute_global_address.json
new file mode 100644
index 00000000..5ce52dd7
--- /dev/null
+++ b/testdata/templates/example_compute_global_address.json
@@ -0,0 +1,17 @@
+[
+  {
+    "name": "//compute.googleapis.com/projects/{{.Provider.project}}/global/addresses/global-appserver-ip",
+    "asset_type": "compute.googleapis.com/GlobalAddress",
+    "ancestry_path": "{{.Ancestry}}/project/{{.Provider.project}}",
+    "resource": {
+      "version": "v1",
+      "discovery_document_uri": "https://www.googleapis.com/discovery/v1/apis/compute/v1/rest",
+      "discovery_name": "GlobalAddress",
+      "parent": "//cloudresourcemanager.googleapis.com/projects/{{.Provider.project}}",
+      "data": {
+        "addressType": "EXTERNAL",
+        "name": "global-appserver-ip"
+      }
+    }
+  }
+]
diff --git a/testdata/templates/example_compute_global_address.tf b/testdata/templates/example_compute_global_address.tf
new file mode 100644
index 00000000..e3ea697b
--- /dev/null
+++ b/testdata/templates/example_compute_global_address.tf
@@ -0,0 +1,32 @@
+/**
+ * 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_compute_global_address" "default" {
+  name = "global-appserver-ip"
+}
diff --git a/testdata/templates/example_compute_global_address.tfplan.json b/testdata/templates/example_compute_global_address.tfplan.json
new file mode 100644
index 00000000..d81a2a43
--- /dev/null
+++ b/testdata/templates/example_compute_global_address.tfplan.json
@@ -0,0 +1,92 @@
+{
+  "format_version": "0.2",
+  "terraform_version": "1.0.10",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_compute_global_address.default",
+          "mode": "managed",
+          "type": "google_compute_global_address",
+          "name": "default",
+          "provider_name": "registry.terraform.io/hashicorp/google",
+          "schema_version": 0,
+          "values": {
+            "address_type": null,
+            "description": null,
+            "ip_version": null,
+            "name": "global-appserver-ip",
+            "network": null,
+            "prefix_length": null,
+            "purpose": null,
+            "timeouts": null
+          },
+          "sensitive_values": {}
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "google_compute_global_address.default",
+      "mode": "managed",
+      "type": "google_compute_global_address",
+      "name": "default",
+      "provider_name": "registry.terraform.io/hashicorp/google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "address_type": null,
+          "description": null,
+          "ip_version": null,
+          "name": "global-appserver-ip",
+          "network": null,
+          "prefix_length": null,
+          "purpose": null,
+          "timeouts": null
+        },
+        "after_unknown": {
+          "address": true,
+          "creation_timestamp": true,
+          "id": true,
+          "project": true,
+          "self_link": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    }
+  ],
+  "configuration": {
+    "provider_config": {
+      "google": {
+        "name": "google",
+        "expressions": {
+          "project": {
+            "constant_value": "{{.Provider.project}}"
+          }
+        }
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_compute_global_address.default",
+          "mode": "managed",
+          "type": "google_compute_global_address",
+          "name": "default",
+          "provider_config_key": "google",
+          "expressions": {
+            "name": {
+              "constant_value": "global-appserver-ip"
+            }
+          },
+          "schema_version": 0
+        }
+      ]
+    }
+  }
+}
diff --git a/testdata/templates/example_compute_ssl_policy.json b/testdata/templates/example_compute_ssl_policy.json
new file mode 100644
index 00000000..72db5ed7
--- /dev/null
+++ b/testdata/templates/example_compute_ssl_policy.json
@@ -0,0 +1,22 @@
+[
+  {
+    "name": "//compute.googleapis.com/projects/{{.Provider.project}}/global/sslPolicies/custom-ssl-policy",
+    "asset_type": "compute.googleapis.com/SslPolicy",
+    "ancestry_path": "{{.Ancestry}}/project/{{.Provider.project}}",
+    "resource": {
+      "version": "v1",
+      "discovery_document_uri": "https://www.googleapis.com/discovery/v1/apis/compute/v1/rest",
+      "discovery_name": "SslPolicy",
+      "parent": "//cloudresourcemanager.googleapis.com/projects/{{.Provider.project}}",
+      "data": {
+        "customFeatures": [
+          "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
+          "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
+        ],
+        "minTlsVersion": "TLS_1_2",
+        "name": "custom-ssl-policy",
+        "profile": "CUSTOM"
+      }
+    }
+  }
+]
diff --git a/testdata/templates/example_compute_ssl_policy.tf b/testdata/templates/example_compute_ssl_policy.tf
new file mode 100644
index 00000000..6c8081a0
--- /dev/null
+++ b/testdata/templates/example_compute_ssl_policy.tf
@@ -0,0 +1,35 @@
+/**
+ * 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_compute_ssl_policy" "custom-ssl-policy" {
+  name            = "custom-ssl-policy"
+  min_tls_version = "TLS_1_2"
+  profile         = "CUSTOM"
+  custom_features = ["TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"]
+}
diff --git a/testdata/templates/example_compute_ssl_policy.tfplan.json b/testdata/templates/example_compute_ssl_policy.tfplan.json
new file mode 100644
index 00000000..9e660d37
--- /dev/null
+++ b/testdata/templates/example_compute_ssl_policy.tfplan.json
@@ -0,0 +1,123 @@
+{
+  "format_version": "0.2",
+  "terraform_version": "1.0.10",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_compute_ssl_policy.custom-ssl-policy",
+          "mode": "managed",
+          "type": "google_compute_ssl_policy",
+          "name": "custom-ssl-policy",
+          "provider_name": "registry.terraform.io/hashicorp/google",
+          "schema_version": 0,
+          "values": {
+            "custom_features": [
+              "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
+              "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
+            ],
+            "description": null,
+            "min_tls_version": "TLS_1_2",
+            "name": "custom-ssl-policy",
+            "profile": "CUSTOM",
+            "timeouts": null
+          },
+          "sensitive_values": {
+            "custom_features": [
+              false,
+              false
+            ],
+            "enabled_features": []
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "google_compute_ssl_policy.custom-ssl-policy",
+      "mode": "managed",
+      "type": "google_compute_ssl_policy",
+      "name": "custom-ssl-policy",
+      "provider_name": "registry.terraform.io/hashicorp/google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "custom_features": [
+            "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
+            "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
+          ],
+          "description": null,
+          "min_tls_version": "TLS_1_2",
+          "name": "custom-ssl-policy",
+          "profile": "CUSTOM",
+          "timeouts": null
+        },
+        "after_unknown": {
+          "creation_timestamp": true,
+          "custom_features": [
+            false,
+            false
+          ],
+          "enabled_features": true,
+          "fingerprint": true,
+          "id": true,
+          "project": true,
+          "self_link": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {
+          "custom_features": [
+            false,
+            false
+          ],
+          "enabled_features": []
+        }
+      }
+    }
+  ],
+  "configuration": {
+    "provider_config": {
+      "google": {
+        "name": "google",
+        "expressions": {
+          "project": {
+            "constant_value": "{{.Provider.project}}"
+          }
+        }
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_compute_ssl_policy.custom-ssl-policy",
+          "mode": "managed",
+          "type": "google_compute_ssl_policy",
+          "name": "custom-ssl-policy",
+          "provider_config_key": "google",
+          "expressions": {
+            "custom_features": {
+              "constant_value": [
+                "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
+                "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
+              ]
+            },
+            "min_tls_version": {
+              "constant_value": "TLS_1_2"
+            },
+            "name": {
+              "constant_value": "custom-ssl-policy"
+            },
+            "profile": {
+              "constant_value": "CUSTOM"
+            }
+          },
+          "schema_version": 0
+        }
+      ]
+    }
+  }
+}
diff --git a/testdata/templates/example_dns_policy.json b/testdata/templates/example_dns_policy.json
new file mode 100644
index 00000000..cd98d60e
--- /dev/null
+++ b/testdata/templates/example_dns_policy.json
@@ -0,0 +1,60 @@
+[
+  {
+    "name": "//compute.googleapis.com/projects/{{.Provider.project}}/global/networks/network-1",
+    "asset_type": "compute.googleapis.com/Network",
+    "ancestry_path": "{{.Ancestry}}/project/{{.Provider.project}}",
+    "resource": {
+      "version": "v1",
+      "discovery_document_uri": "https://www.googleapis.com/discovery/v1/apis/compute/v1/rest",
+      "discovery_name": "Network",
+      "parent": "//cloudresourcemanager.googleapis.com/projects/{{.Provider.project}}",
+      "data": {
+        "autoCreateSubnetworks": false,
+        "name": "network-1"
+      }
+    }
+  },
+  {
+    "name": "//compute.googleapis.com/projects/{{.Provider.project}}/global/networks/network-2",
+    "asset_type": "compute.googleapis.com/Network",
+    "ancestry_path": "{{.Ancestry}}/project/{{.Provider.project}}",
+    "resource": {
+      "version": "v1",
+      "discovery_document_uri": "https://www.googleapis.com/discovery/v1/apis/compute/v1/rest",
+      "discovery_name": "Network",
+      "parent": "//cloudresourcemanager.googleapis.com/projects/{{.Provider.project}}",
+      "data": {
+        "autoCreateSubnetworks": false,
+        "name": "network-2"
+      }
+    }
+  },
+  {
+    "name": "//dns.googleapis.com/projects/{{.Provider.project}}/policies/example-policy",
+    "asset_type": "dns.googleapis.com/Policy",
+    "ancestry_path": "{{.Ancestry}}/project/{{.Provider.project}}",
+    "resource": {
+      "version": "v1",
+      "discovery_document_uri": "https://www.googleapis.com/discovery/v1/apis/dns/v1/rest",
+      "discovery_name": "Policy",
+      "parent": "//cloudresourcemanager.googleapis.com/projects/{{.Provider.project}}",
+      "data": {
+        "alternativeNameServerConfig": {
+          "targetNameServers": [
+            {
+              "ipv4Address": "172.16.1.20"
+            },
+            {
+              "forwardingPath": "private",
+              "ipv4Address": "172.16.1.10"
+            }
+          ]
+        },
+        "description": "Managed by Terraform",
+        "enableInboundForwarding": true,
+        "enableLogging": true,
+        "name": "example-policy"
+      }
+    }
+  }
+]
diff --git a/testdata/templates/example_dns_policy.tf b/testdata/templates/example_dns_policy.tf
new file mode 100644
index 00000000..35eec992
--- /dev/null
+++ b/testdata/templates/example_dns_policy.tf
@@ -0,0 +1,62 @@
+/**
+ * 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_dns_policy" "example-policy" {
+  name                      = "example-policy"
+  enable_inbound_forwarding = true
+
+  enable_logging = true
+
+  alternative_name_server_config {
+    target_name_servers {
+      ipv4_address    = "172.16.1.10"
+      forwarding_path = "private"
+    }
+    target_name_servers {
+      ipv4_address = "172.16.1.20"
+    }
+  }
+
+  networks {
+    network_url = google_compute_network.network-1.id
+  }
+  networks {
+    network_url = google_compute_network.network-2.id
+  }
+}
+
+resource "google_compute_network" "network-1" {
+  name                    = "network-1"
+  auto_create_subnetworks = false
+}
+
+resource "google_compute_network" "network-2" {
+  name                    = "network-2"
+  auto_create_subnetworks = false
+}
diff --git a/testdata/templates/example_dns_policy.tfplan.json b/testdata/templates/example_dns_policy.tfplan.json
new file mode 100644
index 00000000..3afed08c
--- /dev/null
+++ b/testdata/templates/example_dns_policy.tfplan.json
@@ -0,0 +1,328 @@
+{
+  "format_version": "0.2",
+  "terraform_version": "1.0.10",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_compute_network.network-1",
+          "mode": "managed",
+          "type": "google_compute_network",
+          "name": "network-1",
+          "provider_name": "registry.terraform.io/hashicorp/google",
+          "schema_version": 0,
+          "values": {
+            "auto_create_subnetworks": false,
+            "delete_default_routes_on_create": false,
+            "description": null,
+            "name": "network-1",
+            "timeouts": null
+          },
+          "sensitive_values": {}
+        },
+        {
+          "address": "google_compute_network.network-2",
+          "mode": "managed",
+          "type": "google_compute_network",
+          "name": "network-2",
+          "provider_name": "registry.terraform.io/hashicorp/google",
+          "schema_version": 0,
+          "values": {
+            "auto_create_subnetworks": false,
+            "delete_default_routes_on_create": false,
+            "description": null,
+            "name": "network-2",
+            "timeouts": null
+          },
+          "sensitive_values": {}
+        },
+        {
+          "address": "google_dns_policy.example-policy",
+          "mode": "managed",
+          "type": "google_dns_policy",
+          "name": "example-policy",
+          "provider_name": "registry.terraform.io/hashicorp/google",
+          "schema_version": 0,
+          "values": {
+            "alternative_name_server_config": [
+              {
+                "target_name_servers": [
+                  {
+                    "forwarding_path": "",
+                    "ipv4_address": "172.16.1.20"
+                  },
+                  {
+                    "forwarding_path": "private",
+                    "ipv4_address": "172.16.1.10"
+                  }
+                ]
+              }
+            ],
+            "description": "Managed by Terraform",
+            "enable_inbound_forwarding": true,
+            "enable_logging": true,
+            "name": "example-policy",
+            "networks": [
+              {},
+              {}
+            ],
+            "timeouts": null
+          },
+          "sensitive_values": {
+            "alternative_name_server_config": [
+              {
+                "target_name_servers": [
+                  {},
+                  {}
+                ]
+              }
+            ],
+            "networks": [
+              {},
+              {}
+            ]
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "google_compute_network.network-1",
+      "mode": "managed",
+      "type": "google_compute_network",
+      "name": "network-1",
+      "provider_name": "registry.terraform.io/hashicorp/google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "auto_create_subnetworks": false,
+          "delete_default_routes_on_create": false,
+          "description": null,
+          "name": "network-1",
+          "timeouts": null
+        },
+        "after_unknown": {
+          "gateway_ipv4": true,
+          "id": true,
+          "mtu": true,
+          "project": true,
+          "routing_mode": true,
+          "self_link": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    },
+    {
+      "address": "google_compute_network.network-2",
+      "mode": "managed",
+      "type": "google_compute_network",
+      "name": "network-2",
+      "provider_name": "registry.terraform.io/hashicorp/google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "auto_create_subnetworks": false,
+          "delete_default_routes_on_create": false,
+          "description": null,
+          "name": "network-2",
+          "timeouts": null
+        },
+        "after_unknown": {
+          "gateway_ipv4": true,
+          "id": true,
+          "mtu": true,
+          "project": true,
+          "routing_mode": true,
+          "self_link": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    },
+    {
+      "address": "google_dns_policy.example-policy",
+      "mode": "managed",
+      "type": "google_dns_policy",
+      "name": "example-policy",
+      "provider_name": "registry.terraform.io/hashicorp/google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "alternative_name_server_config": [
+            {
+              "target_name_servers": [
+                {
+                  "forwarding_path": "",
+                  "ipv4_address": "172.16.1.20"
+                },
+                {
+                  "forwarding_path": "private",
+                  "ipv4_address": "172.16.1.10"
+                }
+              ]
+            }
+          ],
+          "description": "Managed by Terraform",
+          "enable_inbound_forwarding": true,
+          "enable_logging": true,
+          "name": "example-policy",
+          "networks": [
+            {},
+            {}
+          ],
+          "timeouts": null
+        },
+        "after_unknown": {
+          "alternative_name_server_config": [
+            {
+              "target_name_servers": [
+                {},
+                {}
+              ]
+            }
+          ],
+          "id": true,
+          "networks": [
+            {
+              "network_url": true
+            },
+            {
+              "network_url": true
+            }
+          ],
+          "project": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {
+          "alternative_name_server_config": [
+            {
+              "target_name_servers": [
+                {},
+                {}
+              ]
+            }
+          ],
+          "networks": [
+            {},
+            {}
+          ]
+        }
+      }
+    }
+  ],
+  "configuration": {
+    "provider_config": {
+      "google": {
+        "name": "google",
+        "expressions": {
+          "project": {
+            "constant_value": "{{.Provider.project}}"
+          }
+        }
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_compute_network.network-1",
+          "mode": "managed",
+          "type": "google_compute_network",
+          "name": "network-1",
+          "provider_config_key": "google",
+          "expressions": {
+            "auto_create_subnetworks": {
+              "constant_value": false
+            },
+            "name": {
+              "constant_value": "network-1"
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "google_compute_network.network-2",
+          "mode": "managed",
+          "type": "google_compute_network",
+          "name": "network-2",
+          "provider_config_key": "google",
+          "expressions": {
+            "auto_create_subnetworks": {
+              "constant_value": false
+            },
+            "name": {
+              "constant_value": "network-2"
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "google_dns_policy.example-policy",
+          "mode": "managed",
+          "type": "google_dns_policy",
+          "name": "example-policy",
+          "provider_config_key": "google",
+          "expressions": {
+            "alternative_name_server_config": [
+              {
+                "target_name_servers": [
+                  {
+                    "forwarding_path": {
+                      "constant_value": "private"
+                    },
+                    "ipv4_address": {
+                      "constant_value": "172.16.1.10"
+                    }
+                  },
+                  {
+                    "ipv4_address": {
+                      "constant_value": "172.16.1.20"
+                    }
+                  }
+                ]
+              }
+            ],
+            "enable_inbound_forwarding": {
+              "constant_value": true
+            },
+            "enable_logging": {
+              "constant_value": true
+            },
+            "name": {
+              "constant_value": "example-policy"
+            },
+            "networks": [
+              {
+                "network_url": {
+                  "references": [
+                    "google_compute_network.network-1.id",
+                    "google_compute_network.network-1"
+                  ]
+                }
+              },
+              {
+                "network_url": {
+                  "references": [
+                    "google_compute_network.network-2.id",
+                    "google_compute_network.network-2"
+                  ]
+                }
+              }
+            ]
+          },
+          "schema_version": 0
+        }
+      ]
+    }
+  }
+}
diff --git a/testdata/templates/example_monitoring_alert_policy.json b/testdata/templates/example_monitoring_alert_policy.json
new file mode 100644
index 00000000..9654f83f
--- /dev/null
+++ b/testdata/templates/example_monitoring_alert_policy.json
@@ -0,0 +1,39 @@
+[
+  {
+    "name": "//monitoring.googleapis.com/placeholder-foobar",
+    "asset_type": "monitoring.googleapis.com/AlertPolicy",
+    "ancestry_path": "{{.Ancestry}}/project/{{.Provider.project}}",
+    "resource": {
+      "version": "v3",
+      "discovery_document_uri": "https://www.googleapis.com/discovery/v1/apis/monitoring/v3/rest",
+      "discovery_name": "AlertPolicy",
+      "parent": "//cloudresourcemanager.googleapis.com/projects/{{.Provider.project}}",
+      "data": {
+        "combiner": "OR",
+        "conditions": [
+          {
+            "conditionThreshold": {
+              "aggregations": [
+                {
+                  "alignmentPeriod": "60s",
+                  "perSeriesAligner": "ALIGN_RATE"
+                }
+              ],
+              "comparison": "COMPARISON_GT",
+              "duration": "60s",
+              "filter": "metric.type=\"compute.googleapis.com/instance/disk/write_bytes_count\" AND resource.type=\"gce_instance\""
+            },
+            "displayName": "test condition"
+          }
+        ],
+        "displayName": "My Alert Policy",
+        "enabled": true,
+        "notificationChannels": [
+          "projects/{{.Provider.project}}/notificationChannels/channel-1",
+          "projects/{{.Provider.project}}/notificationChannels/channel-2",
+          "projects/{{.Provider.project}}/notificationChannels/channel-3"
+        ]
+      }
+    }
+  }
+]
\ No newline at end of file
diff --git a/testdata/templates/example_monitoring_alert_policy.tf b/testdata/templates/example_monitoring_alert_policy.tf
new file mode 100644
index 00000000..8ca97d8f
--- /dev/null
+++ b/testdata/templates/example_monitoring_alert_policy.tf
@@ -0,0 +1,52 @@
+/**
+ * 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_monitoring_alert_policy" "alert_policy" {
+  project = "{{.Provider.project}}"
+  display_name = "My Alert Policy"
+  combiner = "OR"
+  conditions {
+    display_name = "test condition"
+    condition_threshold {
+      filter = "metric.type=\"compute.googleapis.com/instance/disk/write_bytes_count\" AND resource.type=\"gce_instance\""
+      duration = "60s"
+      comparison = "COMPARISON_GT"
+      aggregations {
+        alignment_period = "60s"
+        per_series_aligner = "ALIGN_RATE"
+      }
+    }
+  }
+
+  notification_channels = [
+    "projects/{{.Provider.project}}/notificationChannels/channel-1",
+    "projects/{{.Provider.project}}/notificationChannels/channel-2",
+    "projects/{{.Provider.project}}/notificationChannels/channel-3"
+  ]
+}
\ No newline at end of file
diff --git a/testdata/templates/example_monitoring_alert_policy.tfplan.json b/testdata/templates/example_monitoring_alert_policy.tfplan.json
new file mode 100644
index 00000000..aa7d264f
--- /dev/null
+++ b/testdata/templates/example_monitoring_alert_policy.tfplan.json
@@ -0,0 +1,202 @@
+{
+  "format_version": "0.1",
+  "terraform_version": "0.13.5",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_monitoring_alert_policy.alert_policy",
+          "mode": "managed",
+          "type": "google_monitoring_alert_policy",
+          "name": "alert_policy",
+          "provider_name": "registry.terraform.io/hashicorp/google",
+          "schema_version": 0,
+          "values": {
+            "combiner": "OR",
+            "conditions": [
+              {
+                "condition_absent": [],
+                "condition_monitoring_query_language": [],
+                "condition_threshold": [
+                  {
+                    "aggregations": [
+                      {
+                        "alignment_period": "60s",
+                        "cross_series_reducer": null,
+                        "group_by_fields": null,
+                        "per_series_aligner": "ALIGN_RATE"
+                      }
+                    ],
+                    "comparison": "COMPARISON_GT",
+                    "denominator_aggregations": [],
+                    "denominator_filter": null,
+                    "duration": "60s",
+                    "filter": "metric.type=\"compute.googleapis.com/instance/disk/write_bytes_count\" AND resource.type=\"gce_instance\"",
+                    "threshold_value": null,
+                    "trigger": []
+                  }
+                ],
+                "display_name": "test condition"
+              }
+            ],
+            "display_name": "My Alert Policy",
+            "documentation": [],
+            "enabled": true,
+            "notification_channels": [
+              "projects/{{.Provider.project}}/notificationChannels/channel-1",
+              "projects/{{.Provider.project}}/notificationChannels/channel-2",
+              "projects/{{.Provider.project}}/notificationChannels/channel-3"
+            ],
+            "project": "{{.Provider.project}}",
+            "timeouts": null,
+            "user_labels": null
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "google_monitoring_alert_policy.alert_policy",
+      "mode": "managed",
+      "type": "google_monitoring_alert_policy",
+      "name": "alert_policy",
+      "provider_name": "registry.terraform.io/hashicorp/google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "combiner": "OR",
+          "conditions": [
+            {
+              "condition_absent": [],
+              "condition_monitoring_query_language": [],
+              "condition_threshold": [
+                {
+                  "aggregations": [
+                    {
+                      "alignment_period": "60s",
+                      "cross_series_reducer": null,
+                      "group_by_fields": null,
+                      "per_series_aligner": "ALIGN_RATE"
+                    }
+                  ],
+                  "comparison": "COMPARISON_GT",
+                  "denominator_aggregations": [],
+                  "denominator_filter": null,
+                  "duration": "60s",
+                  "filter": "metric.type=\"compute.googleapis.com/instance/disk/write_bytes_count\" AND resource.type=\"gce_instance\"",
+                  "threshold_value": null,
+                  "trigger": []
+                }
+              ],
+              "display_name": "test condition"
+            }
+          ],
+          "display_name": "My Alert Policy",
+          "documentation": [],
+          "enabled": true,
+          "notification_channels": [
+            "projects/{{.Provider.project}}/notificationChannels/channel-1",
+            "projects/{{.Provider.project}}/notificationChannels/channel-2",
+            "projects/{{.Provider.project}}/notificationChannels/channel-3"
+          ],
+          "project": "{{.Provider.project}}",
+          "timeouts": null,
+          "user_labels": null
+        },
+        "after_unknown": {
+          "conditions": [
+            {
+              "condition_absent": [],
+              "condition_monitoring_query_language": [],
+              "condition_threshold": [
+                {
+                  "aggregations": [
+                    {}
+                  ],
+                  "denominator_aggregations": [],
+                  "trigger": []
+                }
+              ],
+              "name": true
+            }
+          ],
+          "creation_record": true,
+          "documentation": [],
+          "id": true,
+          "name": true,
+          "notification_channels": [
+            false,
+            false,
+            false
+          ]
+        }
+      }
+    }
+  ],
+  "configuration": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_monitoring_alert_policy.alert_policy",
+          "mode": "managed",
+          "type": "google_monitoring_alert_policy",
+          "name": "alert_policy",
+          "provider_config_key": "google",
+          "expressions": {
+            "combiner": {
+              "constant_value": "OR"
+            },
+            "conditions": [
+              {
+                "condition_threshold": [
+                  {
+                    "aggregations": [
+                      {
+                        "alignment_period": {
+                          "constant_value": "60s"
+                        },
+                        "per_series_aligner": {
+                          "constant_value": "ALIGN_RATE"
+                        }
+                      }
+                    ],
+                    "comparison": {
+                      "constant_value": "COMPARISON_GT"
+                    },
+                    "duration": {
+                      "constant_value": "60s"
+                    },
+                    "filter": {
+                      "constant_value": "metric.type=\"compute.googleapis.com/instance/disk/write_bytes_count\" AND resource.type=\"gce_instance\""
+                    }
+                  }
+                ],
+                "display_name": {
+                  "constant_value": "test condition"
+                }
+              }
+            ],
+            "display_name": {
+              "constant_value": "My Alert Policy"
+            },
+            "notification_channels": {
+              "constant_value": [
+                "projects/{{.Provider.project}}/notificationChannels/channel-1",
+                "projects/{{.Provider.project}}/notificationChannels/channel-2",
+                "projects/{{.Provider.project}}/notificationChannels/channel-3"
+              ]
+            },
+            "project": {
+              "constant_value": "{{.Provider.project}}"
+            }
+          },
+          "schema_version": 0
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/testdata/templates/example_monitoring_notification_channel.json b/testdata/templates/example_monitoring_notification_channel.json
new file mode 100644
index 00000000..6786df0b
--- /dev/null
+++ b/testdata/templates/example_monitoring_notification_channel.json
@@ -0,0 +1,21 @@
+[
+  {
+    "name": "//monitoring.googleapis.com/placeholder-foobar",
+    "asset_type": "monitoring.googleapis.com/NotificationChannel",
+    "ancestry_path": "{{.Ancestry}}/project/{{.Provider.project}}",
+    "resource": {
+      "version": "v3",
+      "discovery_document_uri": "https://www.googleapis.com/discovery/v1/apis/monitoring/v3/rest",
+      "discovery_name": "NotificationChannel",
+      "parent": "//cloudresourcemanager.googleapis.com/projects/{{.Provider.project}}",
+      "data": {
+        "displayName": "monitoring notification channel",
+        "enabled": true,
+        "labels": {
+          "email_address": "foo@bar.com"
+        },
+        "type": "email"
+      }
+    }
+  }
+]
diff --git a/testdata/templates/example_monitoring_notification_channel.tf b/testdata/templates/example_monitoring_notification_channel.tf
new file mode 100644
index 00000000..d5da3fd5
--- /dev/null
+++ b/testdata/templates/example_monitoring_notification_channel.tf
@@ -0,0 +1,37 @@
+/**
+ * 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_monitoring_notification_channel" "monitoring_notification_channel" {
+  project = "{{.Provider.project}}"
+  display_name = "monitoring notification channel"
+  type = "email"
+  labels = {
+    email_address = "foo@bar.com"
+  }
+}
\ No newline at end of file
diff --git a/testdata/templates/example_monitoring_notification_channel.tfplan.json b/testdata/templates/example_monitoring_notification_channel.tfplan.json
new file mode 100644
index 00000000..e68a5652
--- /dev/null
+++ b/testdata/templates/example_monitoring_notification_channel.tfplan.json
@@ -0,0 +1,96 @@
+{
+  "format_version": "0.1",
+  "terraform_version": "0.13.5",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_monitoring_notification_channel.monitoring_notification_channel",
+          "mode": "managed",
+          "type": "google_monitoring_notification_channel",
+          "name": "monitoring_notification_channel",
+          "provider_name": "registry.terraform.io/hashicorp/google",
+          "schema_version": 0,
+          "values": {
+            "description": null,
+            "display_name": "monitoring notification channel",
+            "enabled": true,
+            "labels": {
+              "email_address": "foo@bar.com"
+            },
+            "project": "{{.Provider.project}}",
+            "sensitive_labels": [],
+            "timeouts": null,
+            "type": "email",
+            "user_labels": null
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "google_monitoring_notification_channel.monitoring_notification_channel",
+      "mode": "managed",
+      "type": "google_monitoring_notification_channel",
+      "name": "monitoring_notification_channel",
+      "provider_name": "registry.terraform.io/hashicorp/google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "description": null,
+          "display_name": "monitoring notification channel",
+          "enabled": true,
+          "labels": {
+            "email_address": "foo@bar.com"
+          },
+          "project": "{{.Provider.project}}",
+          "sensitive_labels": [],
+          "timeouts": null,
+          "type": "email",
+          "user_labels": null
+        },
+        "after_unknown": {
+          "id": true,
+          "labels": {},
+          "name": true,
+          "sensitive_labels": [],
+          "verification_status": true
+        }
+      }
+    }
+  ],
+  "configuration": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_monitoring_notification_channel.monitoring_notification_channel",
+          "mode": "managed",
+          "type": "google_monitoring_notification_channel",
+          "name": "monitoring_notification_channel",
+          "provider_config_key": "google",
+          "expressions": {
+            "display_name": {
+              "constant_value": "monitoring notification channel"
+            },
+            "labels": {
+              "constant_value": {
+                "email_address": "foo@bar.com"
+              }
+            },
+            "project": {
+              "constant_value": "{{.Provider.project}}"
+            },
+            "type": {
+              "constant_value": "email"
+            }
+          },
+          "schema_version": 0
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/testdata/templates/example_organization_iam_custom_role.json b/testdata/templates/example_organization_iam_custom_role.json
new file mode 100644
index 00000000..2af903ef
--- /dev/null
+++ b/testdata/templates/example_organization_iam_custom_role.json
@@ -0,0 +1,23 @@
+[
+  {
+    "name": "//iam.googleapis.com/organizations/{{.OrgID}}/roles/myCustomRole",
+    "asset_type": "iam.googleapis.com/Role",
+    "ancestry_path": "{{.Ancestry}}/project/{{.Provider.project}}",
+    "resource": {
+      "version": "v1",
+      "discovery_document_uri": "https://iam.googleapis.com/$discovery/rest?version=v1",
+      "discovery_name": "Role",
+      "parent": "//cloudresourcemanager.googleapis.com/projects/{{.Provider.project}}",
+      "data": {
+        "description": "A description",
+        "includedPermissions": [
+          "iam.roles.delete",
+          "iam.roles.list",
+          "iam.roles.create"
+        ],
+        "stage": "GA",
+        "title": "My Custom Role"
+      }
+    }
+  }
+]
diff --git a/testdata/templates/example_organization_iam_custom_role.tf b/testdata/templates/example_organization_iam_custom_role.tf
new file mode 100644
index 00000000..eb2d76c4
--- /dev/null
+++ b/testdata/templates/example_organization_iam_custom_role.tf
@@ -0,0 +1,36 @@
+/**
+ * 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_organization_iam_custom_role" "my-custom-role" {
+org_id = "{{.OrgID}}"
+role_id = "myCustomRole"
+title = "My Custom Role"
+description = "A description"
+permissions = ["iam.roles.list", "iam.roles.create", "iam.roles.delete"]
+}
\ No newline at end of file
diff --git a/testdata/templates/example_organization_iam_custom_role.tfplan.json b/testdata/templates/example_organization_iam_custom_role.tfplan.json
new file mode 100644
index 00000000..2e1ad72f
--- /dev/null
+++ b/testdata/templates/example_organization_iam_custom_role.tfplan.json
@@ -0,0 +1,102 @@
+{
+  "format_version": "0.1",
+  "terraform_version": "0.13.5",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_organization_iam_custom_role.my-custom-role",
+          "mode": "managed",
+          "type": "google_organization_iam_custom_role",
+          "name": "my-custom-role",
+          "provider_name": "registry.terraform.io/hashicorp/google",
+          "schema_version": 0,
+          "values": {
+            "description": "A description",
+            "org_id": "{{.OrgID}}",
+            "permissions": [
+              "iam.roles.create",
+              "iam.roles.delete",
+              "iam.roles.list"
+            ],
+            "role_id": "myCustomRole",
+            "stage": "GA",
+            "title": "My Custom Role"
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "google_organization_iam_custom_role.my-custom-role",
+      "mode": "managed",
+      "type": "google_organization_iam_custom_role",
+      "name": "my-custom-role",
+      "provider_name": "registry.terraform.io/hashicorp/google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "description": "A description",
+          "org_id": "{{.OrgID}}",
+          "permissions": [
+            "iam.roles.create",
+            "iam.roles.delete",
+            "iam.roles.list"
+          ],
+          "role_id": "myCustomRole",
+          "stage": "GA",
+          "title": "My Custom Role"
+        },
+        "after_unknown": {
+          "deleted": true,
+          "id": true,
+          "name": true,
+          "permissions": [
+            false,
+            false,
+            false
+          ]
+        }
+      }
+    }
+  ],
+  "configuration": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_organization_iam_custom_role.my-custom-role",
+          "mode": "managed",
+          "type": "google_organization_iam_custom_role",
+          "name": "my-custom-role",
+          "provider_config_key": "google",
+          "expressions": {
+            "description": {
+              "constant_value": "A description"
+            },
+            "org_id": {
+              "constant_value": "{{.OrgID}}"
+            },
+            "permissions": {
+              "constant_value": [
+                "iam.roles.list",
+                "iam.roles.create",
+                "iam.roles.delete"
+              ]
+            },
+            "role_id": {
+              "constant_value": "myCustomRole"
+            },
+            "title": {
+              "constant_value": "My Custom Role"
+            }
+          },
+          "schema_version": 0
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/testdata/templates/example_project_iam_custom_role.json b/testdata/templates/example_project_iam_custom_role.json
new file mode 100644
index 00000000..4c7a259d
--- /dev/null
+++ b/testdata/templates/example_project_iam_custom_role.json
@@ -0,0 +1,23 @@
+[
+  {
+    "name": "//iam.googleapis.com/projects/{{.Provider.project}}/roles/myCustomRole",
+    "asset_type": "iam.googleapis.com/Role",
+    "ancestry_path": "{{.Ancestry}}/project/{{.Provider.project}}",
+    "resource": {
+      "version": "v1",
+      "discovery_document_uri": "https://iam.googleapis.com/$discovery/rest?version=v1",
+      "discovery_name": "Role",
+      "parent": "//cloudresourcemanager.googleapis.com/projects/{{.Provider.project}}",
+      "data": {
+        "description": "A description",
+        "includedPermissions": [
+          "iam.roles.delete",
+          "iam.roles.list",
+          "iam.roles.create"
+        ],
+        "stage": "GA",
+        "title": "My Custom Role"
+      }
+    }
+  }
+]
\ No newline at end of file
diff --git a/testdata/templates/example_project_iam_custom_role.tf b/testdata/templates/example_project_iam_custom_role.tf
new file mode 100644
index 00000000..cf7752af
--- /dev/null
+++ b/testdata/templates/example_project_iam_custom_role.tf
@@ -0,0 +1,36 @@
+/**
+ * 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_project_iam_custom_role" "my-custom-role" {
+  project = "{{.Provider.project}}"
+  role_id = "myCustomRole"
+  title = "My Custom Role"
+  description = "A description"
+  permissions = ["iam.roles.list", "iam.roles.create", "iam.roles.delete"]
+}
\ No newline at end of file
diff --git a/testdata/templates/example_project_iam_custom_role.tfplan.json b/testdata/templates/example_project_iam_custom_role.tfplan.json
new file mode 100644
index 00000000..a4b32516
--- /dev/null
+++ b/testdata/templates/example_project_iam_custom_role.tfplan.json
@@ -0,0 +1,102 @@
+{
+  "format_version": "0.1",
+  "terraform_version": "0.13.5",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_project_iam_custom_role.my-custom-role",
+          "mode": "managed",
+          "type": "google_project_iam_custom_role",
+          "name": "my-custom-role",
+          "provider_name": "registry.terraform.io/hashicorp/google",
+          "schema_version": 0,
+          "values": {
+            "description": "A description",
+            "permissions": [
+              "iam.roles.create",
+              "iam.roles.delete",
+              "iam.roles.list"
+            ],
+            "project": "{{.Provider.project}}",
+            "role_id": "myCustomRole",
+            "stage": "GA",
+            "title": "My Custom Role"
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "google_project_iam_custom_role.my-custom-role",
+      "mode": "managed",
+      "type": "google_project_iam_custom_role",
+      "name": "my-custom-role",
+      "provider_name": "registry.terraform.io/hashicorp/google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "description": "A description",
+          "permissions": [
+            "iam.roles.create",
+            "iam.roles.delete",
+            "iam.roles.list"
+          ],
+          "project": "{{.Provider.project}}",
+          "role_id": "myCustomRole",
+          "stage": "GA",
+          "title": "My Custom Role"
+        },
+        "after_unknown": {
+          "deleted": true,
+          "id": true,
+          "name": true,
+          "permissions": [
+            false,
+            false,
+            false
+          ]
+        }
+      }
+    }
+  ],
+  "configuration": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_project_iam_custom_role.my-custom-role",
+          "mode": "managed",
+          "type": "google_project_iam_custom_role",
+          "name": "my-custom-role",
+          "provider_config_key": "google",
+          "expressions": {
+            "description": {
+              "constant_value": "A description"
+            },
+            "permissions": {
+              "constant_value": [
+                "iam.roles.list",
+                "iam.roles.create",
+                "iam.roles.delete"
+              ]
+            },
+            "project": {
+              "constant_value": "{{.Provider.project}}"
+            },
+            "role_id": {
+              "constant_value": "myCustomRole"
+            },
+            "title": {
+              "constant_value": "My Custom Role"
+            }
+          },
+          "schema_version": 0
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/testdata/templates/full_sql_database_instance.json b/testdata/templates/full_sql_database_instance.json
index c9b4f83d..2ddd7a7a 100644
--- a/testdata/templates/full_sql_database_instance.json
+++ b/testdata/templates/full_sql_database_instance.json
@@ -31,13 +31,12 @@
         },
         "settings": {
           "activationPolicy": "test-activation_policy",
-
           "availabilityType": "REGIONAL",
           "backupConfiguration": {
             "binaryLogEnabled": true,
             "enabled": true,
-            "startTime": "42:42",
-            "location": "us"
+            "location": "us",
+            "startTime": "42:42"
           },
           "dataDiskSizeGb": "42",
           "dataDiskType": "test-disk_type",
@@ -86,6 +85,23 @@
       }
     }
   },
+  {
+    "name": "//compute.googleapis.com/projects/{{.Provider.project}}/global/addresses/private-ip-address",
+    "asset_type": "compute.googleapis.com/GlobalAddress",
+    "ancestry_path": "{{.Ancestry}}/project/{{.Provider.project}}",
+    "resource": {
+      "version": "v1",
+      "discovery_document_uri": "https://www.googleapis.com/discovery/v1/apis/compute/v1/rest",
+      "discovery_name": "GlobalAddress",
+      "parent": "//cloudresourcemanager.googleapis.com/projects/{{.Provider.project}}",
+      "data": {
+        "addressType": "INTERNAL",
+        "name": "private-ip-address",
+        "prefixLength": 16,
+        "purpose": "VPC_PEERING"
+      }
+    }
+  },
   {
     "name": "//compute.googleapis.com/projects/{{.Provider.project}}/global/networks/private-network",
     "asset_type": "compute.googleapis.com/Network",