Repository: GoogleCloudPlatform/terraform-validator
Pull request #1313 (2023-01-24 20:58:28)

Add support for access boundaries
Access boundaries can be used to restrict access to other GCP resources. They define an upper bound whichs limits what a principal may access.

This feature is currently in private preview.

<!--
Replace each [ ] with [X] to check it. Switch to the preview view to make it easier to click on links.
These steps will speed up the review process, and we appreciate you spending time on them before sending
your code to be reviewed.
-->
If this PR is for Terraform, I acknowledge that I have:

- [X] Searched through the [issue tracker](https://github.com/hashicorp/terraform-provider-google/issues) for an open issue that this either resolves or contributes to, commented on it to claim it, and written "fixes {url}" or "part of {url}" in this PR description. If there were no relevant open issues, I opened one and commented that I would like to work on it (not necessary for very small changes).
- [X] [Generated Terraform](https://github.com/GoogleCloudPlatform/magic-modules#generating-the-terraform-providers), and ran `make test` and `make lint` to ensure it passes unit and linter tests.
- [X] Ensured that all new fields I added that can be set by a user appear in at least one [example](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/templates/terraform/examples) (for generated resources) or [third_party test](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/tests) (for handwritten resources or update tests).
- [X] [Ran](https://github.com/hashicorp/terraform-provider-google/blob/main/.github/CONTRIBUTING.md#tests) relevant acceptance tests (If the acceptance tests do not yet pass or you are unable to run them, please let your reviewer know).
- [X] Read the [Release Notes Guide](https://github.com/GoogleCloudPlatform/magic-modules/blob/main/.ci/RELEASE_NOTES_GUIDE.md) before writing my release note below.

<!-- AUTOCHANGELOG for Downstream PRs.

Please select one of the following "release-note:" headings:
    - release-note:enhancement
    - release-note:bug
    - release-note:note
    - release-note:new-resource
    - release-note:new-datasource
    - release-note:deprecation
    - release-note:breaking-change
    - release-note:none
    
Unless you choose release-note:none, please add a release note.

See .ci/RELEASE_NOTES_GUIDE.md for writing good release notes.

You can add more release note blocks if you want more than one CHANGELOG
entry for this PR.
-->
**Release Note Template for Downstream PRs (will be copied)**

```release-note:new-resource
`google_iam_access_boundary_policy`
```

Derived from https://github.com/GoogleCloudPlatform/magic-modules/pull/7144


Patch:
diff --git a/converters/google/resources/config.go b/converters/google/resources/config.go
index 7c99dd3f..4a27bba1 100644
--- a/converters/google/resources/config.go
+++ b/converters/google/resources/config.go
@@ -220,6 +220,7 @@ type Config struct {
 	GKEBackupBasePath            string
 	GKEHubBasePath               string
 	HealthcareBasePath           string
+	IAM2BasePath                 string
 	IAMBetaBasePath              string
 	IAMWorkforcePoolBasePath     string
 	IapBasePath                  string
@@ -323,6 +324,7 @@ const GameServicesBasePathKey = "GameServices"
 const GKEBackupBasePathKey = "GKEBackup"
 const GKEHubBasePathKey = "GKEHub"
 const HealthcareBasePathKey = "Healthcare"
+const IAM2BasePathKey = "IAM2"
 const IAMBetaBasePathKey = "IAMBeta"
 const IAMWorkforcePoolBasePathKey = "IAMWorkforcePool"
 const IapBasePathKey = "Iap"
@@ -420,6 +422,7 @@ var DefaultBasePaths = map[string]string{
 	GKEBackupBasePathKey:            "https://gkebackup.googleapis.com/v1/",
 	GKEHubBasePathKey:               "https://gkehub.googleapis.com/v1/",
 	HealthcareBasePathKey:           "https://healthcare.googleapis.com/v1/",
+	IAM2BasePathKey:                 "https://iam.googleapis.com/v2/",
 	IAMBetaBasePathKey:              "https://iam.googleapis.com/v1/",
 	IAMWorkforcePoolBasePathKey:     "https://iam.googleapis.com/v1/",
 	IapBasePathKey:                  "https://iap.googleapis.com/v1/",
@@ -1279,6 +1282,7 @@ func ConfigureBasePaths(c *Config) {
 	c.GKEBackupBasePath = DefaultBasePaths[GKEBackupBasePathKey]
 	c.GKEHubBasePath = DefaultBasePaths[GKEHubBasePathKey]
 	c.HealthcareBasePath = DefaultBasePaths[HealthcareBasePathKey]
+	c.IAM2BasePath = DefaultBasePaths[IAM2BasePathKey]
 	c.IAMBetaBasePath = DefaultBasePaths[IAMBetaBasePathKey]
 	c.IAMWorkforcePoolBasePath = DefaultBasePaths[IAMWorkforcePoolBasePathKey]
 	c.IapBasePath = DefaultBasePaths[IapBasePathKey]
diff --git a/converters/google/resources/iam2_access_boundary_policy.go b/converters/google/resources/iam2_access_boundary_policy.go
new file mode 100644
index 00000000..5376a318
--- /dev/null
+++ b/converters/google/resources/iam2_access_boundary_policy.go
@@ -0,0 +1,209 @@
+// ----------------------------------------------------------------------------
+//
+//     ***     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"
+
+const IAM2AccessBoundaryPolicyAssetType string = "iam.googleapis.com/AccessBoundaryPolicy"
+
+func resourceConverterIAM2AccessBoundaryPolicy() ResourceConverter {
+	return ResourceConverter{
+		AssetType: IAM2AccessBoundaryPolicyAssetType,
+		Convert:   GetIAM2AccessBoundaryPolicyCaiObject,
+	}
+}
+
+func GetIAM2AccessBoundaryPolicyCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
+	name, err := assetName(d, config, "//iam.googleapis.com/policies/{{parent}}/accessboundarypolicies/{{name}}")
+	if err != nil {
+		return []Asset{}, err
+	}
+	if obj, err := GetIAM2AccessBoundaryPolicyApiObject(d, config); err == nil {
+		return []Asset{{
+			Name: name,
+			Type: IAM2AccessBoundaryPolicyAssetType,
+			Resource: &AssetResource{
+				Version:              "v2",
+				DiscoveryDocumentURI: "https://www.googleapis.com/discovery/v1/apis/iam/v2/rest",
+				DiscoveryName:        "AccessBoundaryPolicy",
+				Data:                 obj,
+			},
+		}}, nil
+	} else {
+		return []Asset{}, err
+	}
+}
+
+func GetIAM2AccessBoundaryPolicyApiObject(d TerraformResourceData, config *Config) (map[string]interface{}, error) {
+	obj := make(map[string]interface{})
+	displayNameProp, err := expandIAM2AccessBoundaryPolicyDisplayName(d.Get("display_name"), d, config)
+	if err != nil {
+		return nil, err
+	} else if v, ok := d.GetOkExists("display_name"); !isEmptyValue(reflect.ValueOf(displayNameProp)) && (ok || !reflect.DeepEqual(v, displayNameProp)) {
+		obj["displayName"] = displayNameProp
+	}
+	etagProp, err := expandIAM2AccessBoundaryPolicyEtag(d.Get("etag"), d, config)
+	if err != nil {
+		return nil, err
+	} else if v, ok := d.GetOkExists("etag"); !isEmptyValue(reflect.ValueOf(etagProp)) && (ok || !reflect.DeepEqual(v, etagProp)) {
+		obj["etag"] = etagProp
+	}
+	rulesProp, err := expandIAM2AccessBoundaryPolicyRules(d.Get("rules"), d, config)
+	if err != nil {
+		return nil, err
+	} else if v, ok := d.GetOkExists("rules"); !isEmptyValue(reflect.ValueOf(rulesProp)) && (ok || !reflect.DeepEqual(v, rulesProp)) {
+		obj["rules"] = rulesProp
+	}
+
+	return obj, nil
+}
+
+func expandIAM2AccessBoundaryPolicyDisplayName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandIAM2AccessBoundaryPolicyEtag(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandIAM2AccessBoundaryPolicyRules(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{})
+
+		transformedDescription, err := expandIAM2AccessBoundaryPolicyRulesDescription(original["description"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedDescription); val.IsValid() && !isEmptyValue(val) {
+			transformed["description"] = transformedDescription
+		}
+
+		transformedAccessBoundaryRule, err := expandIAM2AccessBoundaryPolicyRulesAccessBoundaryRule(original["access_boundary_rule"], d, config)
+		if err != nil {
+			return nil, err
+		} else if val := reflect.ValueOf(transformedAccessBoundaryRule); val.IsValid() && !isEmptyValue(val) {
+			transformed["accessBoundaryRule"] = transformedAccessBoundaryRule
+		}
+
+		req = append(req, transformed)
+	}
+	return req, nil
+}
+
+func expandIAM2AccessBoundaryPolicyRulesDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandIAM2AccessBoundaryPolicyRulesAccessBoundaryRule(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{})
+
+	transformedAvailableResource, err := expandIAM2AccessBoundaryPolicyRulesAccessBoundaryRuleAvailableResource(original["available_resource"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedAvailableResource); val.IsValid() && !isEmptyValue(val) {
+		transformed["availableResource"] = transformedAvailableResource
+	}
+
+	transformedAvailablePermissions, err := expandIAM2AccessBoundaryPolicyRulesAccessBoundaryRuleAvailablePermissions(original["available_permissions"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedAvailablePermissions); val.IsValid() && !isEmptyValue(val) {
+		transformed["availablePermissions"] = transformedAvailablePermissions
+	}
+
+	transformedAvailabilityCondition, err := expandIAM2AccessBoundaryPolicyRulesAccessBoundaryRuleAvailabilityCondition(original["availability_condition"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedAvailabilityCondition); val.IsValid() && !isEmptyValue(val) {
+		transformed["availabilityCondition"] = transformedAvailabilityCondition
+	}
+
+	return transformed, nil
+}
+
+func expandIAM2AccessBoundaryPolicyRulesAccessBoundaryRuleAvailableResource(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandIAM2AccessBoundaryPolicyRulesAccessBoundaryRuleAvailablePermissions(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandIAM2AccessBoundaryPolicyRulesAccessBoundaryRuleAvailabilityCondition(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{})
+
+	transformedExpression, err := expandIAM2AccessBoundaryPolicyRulesAccessBoundaryRuleAvailabilityConditionExpression(original["expression"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedExpression); val.IsValid() && !isEmptyValue(val) {
+		transformed["expression"] = transformedExpression
+	}
+
+	transformedTitle, err := expandIAM2AccessBoundaryPolicyRulesAccessBoundaryRuleAvailabilityConditionTitle(original["title"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedTitle); val.IsValid() && !isEmptyValue(val) {
+		transformed["title"] = transformedTitle
+	}
+
+	transformedDescription, err := expandIAM2AccessBoundaryPolicyRulesAccessBoundaryRuleAvailabilityConditionDescription(original["description"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedDescription); val.IsValid() && !isEmptyValue(val) {
+		transformed["description"] = transformedDescription
+	}
+
+	transformedLocation, err := expandIAM2AccessBoundaryPolicyRulesAccessBoundaryRuleAvailabilityConditionLocation(original["location"], d, config)
+	if err != nil {
+		return nil, err
+	} else if val := reflect.ValueOf(transformedLocation); val.IsValid() && !isEmptyValue(val) {
+		transformed["location"] = transformedLocation
+	}
+
+	return transformed, nil
+}
+
+func expandIAM2AccessBoundaryPolicyRulesAccessBoundaryRuleAvailabilityConditionExpression(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandIAM2AccessBoundaryPolicyRulesAccessBoundaryRuleAvailabilityConditionTitle(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandIAM2AccessBoundaryPolicyRulesAccessBoundaryRuleAvailabilityConditionDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
+
+func expandIAM2AccessBoundaryPolicyRulesAccessBoundaryRuleAvailabilityConditionLocation(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+	return v, nil
+}
diff --git a/go.mod b/go.mod
index 244725a3..9afbe33e 100644
--- a/go.mod
+++ b/go.mod
@@ -26,7 +26,7 @@ require (
 	github.com/hashicorp/go-cleanhttp v0.5.2
 	github.com/hashicorp/terraform-json v0.14.0
 	github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.0
-	github.com/hashicorp/terraform-provider-google v1.20.1-0.20230124190404-baf82a9cca0f
+	github.com/hashicorp/terraform-provider-google v1.20.1-0.20230124205347-5452ecfb8d27
 	github.com/mitchellh/go-homedir v1.1.0
 	github.com/pkg/errors v0.9.1
 	github.com/sirupsen/logrus v1.9.0
diff --git a/go.sum b/go.sum
index 9c0bd04f..943f4f4e 100644
--- a/go.sum
+++ b/go.sum
@@ -514,8 +514,8 @@ github.com/hashicorp/terraform-plugin-log v0.7.0 h1:SDxJUyT8TwN4l5b5/VkiTIaQgY6R
 github.com/hashicorp/terraform-plugin-log v0.7.0/go.mod h1:p4R1jWBXRTvL4odmEkFfDdhUjHf9zcs/BCoNHAc7IK4=
 github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.0 h1:FtCLTiTcykdsURXPt/ku7fYXm3y19nbzbZcUxHx9RbI=
 github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.0/go.mod h1:80wf5oad1tW+oLnbXS4UTYmDCrl7BuN1Q+IA91X1a4Y=
-github.com/hashicorp/terraform-provider-google v1.20.1-0.20230124190404-baf82a9cca0f h1:lnYnWfV9dOgCBSyp4QGWeqD89TxkKQx2rtsMM8TyzEM=
-github.com/hashicorp/terraform-provider-google v1.20.1-0.20230124190404-baf82a9cca0f/go.mod h1:hO1IJNy6D0qbRLaGdfmGGERihNWUKSKKL5TU8hNOgRg=
+github.com/hashicorp/terraform-provider-google v1.20.1-0.20230124205347-5452ecfb8d27 h1:u7uUvZZyisI/5WfnlgyhpeCVwZgx56+E6buHVhhwrnw=
+github.com/hashicorp/terraform-provider-google v1.20.1-0.20230124205347-5452ecfb8d27/go.mod h1:hO1IJNy6D0qbRLaGdfmGGERihNWUKSKKL5TU8hNOgRg=
 github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b572c h1:D8aRO6+mTqHfLsK/BC3j5OAoogv1WLRWzY1AaTo3rBg=
 github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b572c/go.mod h1:Wn3Na71knbXc1G8Lh+yu/dQWWJeFQEpDeJMtWMtlmNI=
 github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 h1:HKLsbzeOsfXmKNpr3GiT18XAblV0BjCbzL8KQAMZGa0=


Test patch:
diff --git a/converters/google/resources/config_test_utils.go b/converters/google/resources/config_test_utils.go
index 3c25a8f7..b375b4eb 100644
--- a/converters/google/resources/config_test_utils.go
+++ b/converters/google/resources/config_test_utils.go
@@ -67,6 +67,7 @@ func configureTestBasePaths(c *Config, url string) {
 	c.GKEBackupBasePath = url
 	c.GKEHubBasePath = url
 	c.HealthcareBasePath = url
+	c.IAM2BasePath = url
 	c.IAMBetaBasePath = url
 	c.IAMWorkforcePoolBasePath = url
 	c.IapBasePath = url