Skip to content

Commit

Permalink
Add parameters to google_org_policy_policy (#12008) (#20647)
Browse files Browse the repository at this point in the history
[upstream:971f4cc87fb960871a449798d060c749e831e43c]

Signed-off-by: Modular Magician <magic-modules@google.com>
  • Loading branch information
modular-magician authored Dec 10, 2024
1 parent f93a93d commit 6682e70
Show file tree
Hide file tree
Showing 4 changed files with 228 additions and 10 deletions.
3 changes: 3 additions & 0 deletions .changelog/12008.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
orgpolicy: added `parameters` fields to `google_org_policy_policy` resource (beta)
```
101 changes: 91 additions & 10 deletions google/services/orgpolicy/resource_org_policy_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package orgpolicy

import (
"encoding/json"
"fmt"
"log"
"net/http"
Expand All @@ -27,6 +28,8 @@ import (
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"

"github.com/hashicorp/terraform-provider-google/google/tpgresource"
transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport"
Expand Down Expand Up @@ -139,6 +142,13 @@ func ResourceOrgPolicyPolicy() *schema.Resource {
Optional: true,
Description: `If '"TRUE"', then the 'Policy' is enforced. If '"FALSE"', then any configuration is acceptable. This field can be set only in Policies for boolean constraints.`,
},
"parameters": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringIsJSON,
StateFunc: func(v interface{}) string { s, _ := structure.NormalizeJsonString(v); return s },
Description: `Optional. Required for Managed Constraints if parameters defined in constraints. Pass parameter values when policy enforcement is enabled. Ensure that parameter value types match those defined in the constraint definition. For example: { \"allowedLocations\" : [\"us-east1\", \"us-west1\"], \"allowAll\" : true }`,
},
"values": {
Type: schema.TypeList,
Optional: true,
Expand Down Expand Up @@ -250,6 +260,13 @@ func ResourceOrgPolicyPolicy() *schema.Resource {
Optional: true,
Description: `If '"TRUE"', then the 'Policy' is enforced. If '"FALSE"', then any configuration is acceptable. This field can be set only in Policies for boolean constraints.`,
},
"parameters": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringIsJSON,
StateFunc: func(v interface{}) string { s, _ := structure.NormalizeJsonString(v); return s },
Description: `Optional. Required for Managed Constraints if parameters defined in constraints. Pass parameter values when policy enforcement is enabled. Ensure that parameter value types match those defined in the constraint definition. For example: { \"allowedLocations\" : [\"us-east1\", \"us-west1\"], \"allowAll\" : true }`,
},
"values": {
Type: schema.TypeList,
Optional: true,
Expand Down Expand Up @@ -609,11 +626,12 @@ func flattenOrgPolicyPolicySpecRules(v interface{}, d *schema.ResourceData, conf
continue
}
transformed = append(transformed, map[string]interface{}{
"values": flattenOrgPolicyPolicySpecRulesValues(original["values"], d, config),
"allow_all": flattenOrgPolicyPolicySpecRulesAllowAll(original["allowAll"], d, config),
"deny_all": flattenOrgPolicyPolicySpecRulesDenyAll(original["denyAll"], d, config),
"enforce": flattenOrgPolicyPolicySpecRulesEnforce(original["enforce"], d, config),
"condition": flattenOrgPolicyPolicySpecRulesCondition(original["condition"], d, config),
"values": flattenOrgPolicyPolicySpecRulesValues(original["values"], d, config),
"allow_all": flattenOrgPolicyPolicySpecRulesAllowAll(original["allowAll"], d, config),
"deny_all": flattenOrgPolicyPolicySpecRulesDenyAll(original["denyAll"], d, config),
"enforce": flattenOrgPolicyPolicySpecRulesEnforce(original["enforce"], d, config),
"parameters": flattenOrgPolicyPolicySpecRulesParameters(original["parameters"], d, config),
"condition": flattenOrgPolicyPolicySpecRulesCondition(original["condition"], d, config),
})
}
return transformed
Expand Down Expand Up @@ -662,6 +680,18 @@ func flattenOrgPolicyPolicySpecRulesEnforce(v interface{}, d *schema.ResourceDat
return strings.ToUpper(strconv.FormatBool(v.(bool)))
}

func flattenOrgPolicyPolicySpecRulesParameters(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
if v == nil {
return nil
}
b, err := json.Marshal(v)
if err != nil {
// TODO: return error once https://github.com/GoogleCloudPlatform/magic-modules/issues/3257 is fixed.
log.Printf("[ERROR] failed to marshal schema to JSON: %v", err)
}
return string(b)
}

func flattenOrgPolicyPolicySpecRulesCondition(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
if v == nil {
return nil
Expand Down Expand Up @@ -747,11 +777,12 @@ func flattenOrgPolicyPolicyDryRunSpecRules(v interface{}, d *schema.ResourceData
continue
}
transformed = append(transformed, map[string]interface{}{
"values": flattenOrgPolicyPolicyDryRunSpecRulesValues(original["values"], d, config),
"allow_all": flattenOrgPolicyPolicyDryRunSpecRulesAllowAll(original["allowAll"], d, config),
"deny_all": flattenOrgPolicyPolicyDryRunSpecRulesDenyAll(original["denyAll"], d, config),
"enforce": flattenOrgPolicyPolicyDryRunSpecRulesEnforce(original["enforce"], d, config),
"condition": flattenOrgPolicyPolicyDryRunSpecRulesCondition(original["condition"], d, config),
"values": flattenOrgPolicyPolicyDryRunSpecRulesValues(original["values"], d, config),
"allow_all": flattenOrgPolicyPolicyDryRunSpecRulesAllowAll(original["allowAll"], d, config),
"deny_all": flattenOrgPolicyPolicyDryRunSpecRulesDenyAll(original["denyAll"], d, config),
"enforce": flattenOrgPolicyPolicyDryRunSpecRulesEnforce(original["enforce"], d, config),
"parameters": flattenOrgPolicyPolicyDryRunSpecRulesParameters(original["parameters"], d, config),
"condition": flattenOrgPolicyPolicyDryRunSpecRulesCondition(original["condition"], d, config),
})
}
return transformed
Expand Down Expand Up @@ -800,6 +831,18 @@ func flattenOrgPolicyPolicyDryRunSpecRulesEnforce(v interface{}, d *schema.Resou
return strings.ToUpper(strconv.FormatBool(v.(bool)))
}

func flattenOrgPolicyPolicyDryRunSpecRulesParameters(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
if v == nil {
return nil
}
b, err := json.Marshal(v)
if err != nil {
// TODO: return error once https://github.com/GoogleCloudPlatform/magic-modules/issues/3257 is fixed.
log.Printf("[ERROR] failed to marshal schema to JSON: %v", err)
}
return string(b)
}

func flattenOrgPolicyPolicyDryRunSpecRulesCondition(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
if v == nil {
return nil
Expand Down Expand Up @@ -944,6 +987,13 @@ func expandOrgPolicyPolicySpecRules(v interface{}, d tpgresource.TerraformResour
transformed["enforce"] = transformedEnforce
}

transformedParameters, err := expandOrgPolicyPolicySpecRulesParameters(original["parameters"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedParameters); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["parameters"] = transformedParameters
}

transformedCondition, err := expandOrgPolicyPolicySpecRulesCondition(original["condition"], d, config)
if err != nil {
return nil, err
Expand Down Expand Up @@ -1026,6 +1076,18 @@ func expandOrgPolicyPolicySpecRulesEnforce(v interface{}, d tpgresource.Terrafor
return b, nil
}

func expandOrgPolicyPolicySpecRulesParameters(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
b := []byte(v.(string))
if len(b) == 0 {
return nil, nil
}
m := make(map[string]interface{})
if err := json.Unmarshal(b, &m); err != nil {
return nil, err
}
return m, nil
}

func expandOrgPolicyPolicySpecRulesCondition(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 || l[0] == nil {
Expand Down Expand Up @@ -1183,6 +1245,13 @@ func expandOrgPolicyPolicyDryRunSpecRules(v interface{}, d tpgresource.Terraform
transformed["enforce"] = transformedEnforce
}

transformedParameters, err := expandOrgPolicyPolicyDryRunSpecRulesParameters(original["parameters"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedParameters); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["parameters"] = transformedParameters
}

transformedCondition, err := expandOrgPolicyPolicyDryRunSpecRulesCondition(original["condition"], d, config)
if err != nil {
return nil, err
Expand Down Expand Up @@ -1265,6 +1334,18 @@ func expandOrgPolicyPolicyDryRunSpecRulesEnforce(v interface{}, d tpgresource.Te
return b, nil
}

func expandOrgPolicyPolicyDryRunSpecRulesParameters(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
b := []byte(v.(string))
if len(b) == 0 {
return nil, nil
}
m := make(map[string]interface{})
if err := json.Unmarshal(b, &m); err != nil {
return nil, err
}
return m, nil
}

func expandOrgPolicyPolicyDryRunSpecRulesCondition(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 || l[0] == nil {
Expand Down
103 changes: 103 additions & 0 deletions google/services/orgpolicy/resource_org_policy_policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -460,3 +460,106 @@ func testAccCheckOrgPolicyPolicyDestroyProducer(t *testing.T) func(s *terraform.
return nil
}
}
func TestAccOrgPolicyPolicy_EnforceParameterizedMCPolicy(t *testing.T) {
// Skip this test as no constraints yet launched in production, verified functionality with manual testing.
t.Skip()
t.Parallel()

context := map[string]interface{}{
"org_id": envvar.GetTestOrgFromEnv(t),
"random_suffix": acctest.RandString(t, 10),
}

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckOrgPolicyPolicyDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccOrgPolicyPolicy_EnforceParameterizedMCPolicy(context),
},
{
ResourceName: "google_org_policy_policy.primary",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"name", "spec.0.rules.0.condition.0.expression"},
},
},
})
}
func testAccOrgPolicyPolicy_EnforceParameterizedMCPolicy(context map[string]interface{}) string {
return acctest.Nprintf(`
resource "google_org_policy_policy" "primary" {
name = "projects/${google_project.basic.name}/policies/essentialcontacts.managed.allowedContactDomains"
parent = "projects/${google_project.basic.name}"
spec {
rules {
enforce = "TRUE"
parameters = "{\"allowedDomains\": [\"@google.com\"]}"
}
}
}
resource "google_project" "basic" {
project_id = "tf-test-id%{random_suffix}"
name = "tf-test-id%{random_suffix}"
org_id = "%{org_id}"
deletion_policy = "DELETE"
}
`, context)
}

func TestAccOrgPolicyPolicy_EnforceParameterizedMCDryRunPolicy(t *testing.T) {
// Skip this test as no constraints yet launched in production, verified functionality with manual testing.
t.Skip()
t.Parallel()

context := map[string]interface{}{
"org_id": envvar.GetTestOrgFromEnv(t),
"random_suffix": acctest.RandString(t, 10),
}

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckOrgPolicyPolicyDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccOrgPolicyPolicy_EnforceParameterizedMCDryRunPolicy(context),
},
{
ResourceName: "google_org_policy_policy.primary",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"name", "spec.0.rules.0.condition.0.expression"},
},
},
})
}
func testAccOrgPolicyPolicy_EnforceParameterizedMCDryRunPolicy(context map[string]interface{}) string {
return acctest.Nprintf(`
resource "google_org_policy_policy" "primary" {
name = "projects/${google_project.basic.name}/policies/essentialcontacts.managed.allowedContactDomains"
parent = "projects/${google_project.basic.name}"
dry_run_spec {
rules {
enforce = "TRUE"
parameters = "{\"allowedDomains\": [\"@google.com\"]}"
}
}
}
resource "google_project" "basic" {
project_id = "tf-test-id%{random_suffix}"
name = "tf-test-id%{random_suffix}"
org_id = "%{org_id}"
deletion_policy = "DELETE"
}
`, context)
}
31 changes: 31 additions & 0 deletions website/docs/r/org_policy_policy.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,29 @@ resource "google_org_policy_policy" "primary" {
}
}
```
## Example Usage - Org Policy Policy Parameters Enforce


```hcl
resource "google_org_policy_policy" "primary" {
name = "projects/${google_project.basic.name}/policies/compute.managed.restrictDiskCreation"
parent = "projects/${google_project.basic.name}"
spec {
rules {
enforce = "TRUE"
parameters = jsonencode({"isSizeLimitCheck" : true, "allowedDiskTypes" : ["pd-ssd", "pd-standard"]})
}
}
}
resource "google_project" "basic" {
project_id = "id"
name = "id"
org_id = "123456789"
deletion_policy = "DELETE"
}
```

## Argument Reference

Expand Down Expand Up @@ -229,6 +252,10 @@ The following arguments are supported:
(Optional)
If `"TRUE"`, then the `Policy` is enforced. If `"FALSE"`, then any configuration is acceptable. This field can be set only in Policies for boolean constraints.

* `parameters` -
(Optional)
Optional. Required for Managed Constraints if parameters defined in constraints. Pass parameter values when policy enforcement is enabled. Ensure that parameter value types match those defined in the constraint definition. For example: { \"allowedLocations\" : [\"us-east1\", \"us-west1\"], \"allowAll\" : true }

* `condition` -
(Optional)
A condition which determines whether this rule is used in the evaluation of the policy. When set, the `expression` field in the `Expr' must include from 1 to 10 subexpressions, joined by the "||" or "&&" operators. Each subexpression must be of the form "resource.matchTag('/tag_key_short_name, 'tag_value_short_name')". or "resource.matchTagId('tagKeys/key_id', 'tagValues/value_id')". where key_name and value_name are the resource names for Label Keys and Values. These names are available from the Tag Manager Service. An example expression is: "resource.matchTag('123456789/environment, 'prod')". or "resource.matchTagId('tagKeys/123', 'tagValues/456')".
Expand Down Expand Up @@ -306,6 +333,10 @@ The following arguments are supported:
(Optional)
If `"TRUE"`, then the `Policy` is enforced. If `"FALSE"`, then any configuration is acceptable. This field can be set only in Policies for boolean constraints.

* `parameters` -
(Optional)
Optional. Required for Managed Constraints if parameters defined in constraints. Pass parameter values when policy enforcement is enabled. Ensure that parameter value types match those defined in the constraint definition. For example: { \"allowedLocations\" : [\"us-east1\", \"us-west1\"], \"allowAll\" : true }

* `condition` -
(Optional)
A condition which determines whether this rule is used in the evaluation of the policy. When set, the `expression` field in the `Expr' must include from 1 to 10 subexpressions, joined by the "||" or "&&" operators. Each subexpression must be of the form "resource.matchTag('/tag_key_short_name, 'tag_value_short_name')". or "resource.matchTagId('tagKeys/key_id', 'tagValues/value_id')". where key_name and value_name are the resource names for Label Keys and Values. These names are available from the Tag Manager Service. An example expression is: "resource.matchTag('123456789/environment, 'prod')". or "resource.matchTagId('tagKeys/123', 'tagValues/456')".
Expand Down

0 comments on commit 6682e70

Please sign in to comment.