diff --git a/google/resource_google_folder_organization_policy.go b/google/resource_google_folder_organization_policy.go index 94063d3b..6a12247f 100644 --- a/google/resource_google_folder_organization_policy.go +++ b/google/resource_google_folder_organization_policy.go @@ -52,6 +52,7 @@ func resourceGoogleFolderOrganizationPolicyRead(d *schema.ResourceData, meta int d.Set("constraint", policy.Constraint) d.Set("boolean_policy", flattenBooleanOrganizationPolicy(policy.BooleanPolicy)) d.Set("list_policy", flattenListOrganizationPolicy(policy.ListPolicy)) + d.Set("restore_policy", flattenRestoreOrganizationPolicy(policy.RestoreDefault)) d.Set("version", policy.Version) d.Set("etag", policy.Etag) d.Set("update_time", policy.UpdateTime) @@ -85,18 +86,25 @@ func resourceGoogleFolderOrganizationPolicyDelete(d *schema.ResourceData, meta i func setFolderOrganizationPolicy(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) folder := canonicalFolderId(d.Get("folder").(string)) + listPolicy, err := expandListOrganizationPolicy(d.Get("list_policy").([]interface{})) if err != nil { return err } + restoreDefault, err := expandRestoreOrganizationPolicy(d.Get("restore_policy").([]interface{})) + if err != nil { + return err + } + _, err = config.clientResourceManager.Folders.SetOrgPolicy(folder, &cloudresourcemanager.SetOrgPolicyRequest{ Policy: &cloudresourcemanager.OrgPolicy{ - Constraint: canonicalOrgPolicyConstraint(d.Get("constraint").(string)), - BooleanPolicy: expandBooleanOrganizationPolicy(d.Get("boolean_policy").([]interface{})), - ListPolicy: listPolicy, - Version: int64(d.Get("version").(int)), - Etag: d.Get("etag").(string), + Constraint: canonicalOrgPolicyConstraint(d.Get("constraint").(string)), + BooleanPolicy: expandBooleanOrganizationPolicy(d.Get("boolean_policy").([]interface{})), + ListPolicy: listPolicy, + RestoreDefault: restoreDefault, + Version: int64(d.Get("version").(int)), + Etag: d.Get("etag").(string), }, }).Do() diff --git a/google/resource_google_folder_organization_policy_test.go b/google/resource_google_folder_organization_policy_test.go index 8259c4c2..a8b8d052 100644 --- a/google/resource_google_folder_organization_policy_test.go +++ b/google/resource_google_folder_organization_policy_test.go @@ -129,6 +129,24 @@ func TestAccFolderOrganizationPolicy_list_update(t *testing.T) { }) } +func TestAccFolderOrganizationPolicy_restore_defaultTrue(t *testing.T) { + t.Parallel() + + folder := acctest.RandomWithPrefix("tf-test") + org := getTestOrgFromEnv(t) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckGoogleOrganizationPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccFolderOrganizationPolicy_restore_defaultTrue(org, folder), + Check: getGoogleFolderOrganizationRestoreDefaultTrue("restore", &cloudresourcemanager.RestoreDefault{}), + }, + }, + }) +} + func testAccCheckGoogleFolderOrganizationPolicyDestroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) @@ -222,6 +240,22 @@ func testAccCheckGoogleFolderOrganizationListPolicyDeniedValues(n string, values } } +func getGoogleFolderOrganizationRestoreDefaultTrue(n string, policyDefault *cloudresourcemanager.RestoreDefault) resource.TestCheckFunc { + return func(s *terraform.State) error { + + policy, err := getGoogleFolderOrganizationPolicyTestResource(s, n) + if err != nil { + return err + } + + if !reflect.DeepEqual(policy.RestoreDefault, policyDefault) { + return fmt.Errorf("Expected the restore default '%s', instead denied, %s", policyDefault, policy.RestoreDefault) + } + + return nil + } +} + func getGoogleFolderOrganizationPolicyTestResource(s *terraform.State, n string) (*cloudresourcemanager.OrgPolicy, error) { rn := "google_folder_organization_policy." + n rs, ok := s.RootModule().Resources[rn] @@ -249,7 +283,7 @@ resource "google_folder" "orgpolicy" { } resource "google_folder_organization_policy" "bool" { - # Test numeric folder ID. + # Test numeric folder ID. folder = "${replace(google_folder.orgpolicy.name, "folders/", "")}" constraint = "constraints/compute.disableSerialPortAccess" @@ -322,3 +356,21 @@ resource "google_folder_organization_policy" "list" { } `, folder, "organizations/"+org) } + +func testAccFolderOrganizationPolicy_restore_defaultTrue(org, folder string) string { + return fmt.Sprintf(` +resource "google_folder" "orgpolicy" { + display_name = "%s" + parent = "%s" +} + +resource "google_folder_organization_policy" "restore" { + folder = "${google_folder.orgpolicy.name}" + constraint = "serviceuser.services" + + restore_policy { + default = true + } +} +`, folder, "organizations/"+org) +} diff --git a/google/resource_google_organization_policy.go b/google/resource_google_organization_policy.go index fdb34f65..71c9cba3 100644 --- a/google/resource_google_organization_policy.go +++ b/google/resource_google_organization_policy.go @@ -18,7 +18,7 @@ var schemaOrganizationPolicy = map[string]*schema.Schema{ Type: schema.TypeList, Optional: true, MaxItems: 1, - ConflictsWith: []string{"list_policy"}, + ConflictsWith: []string{"list_policy", "restore_policy"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "enforced": { @@ -32,7 +32,7 @@ var schemaOrganizationPolicy = map[string]*schema.Schema{ Type: schema.TypeList, Optional: true, MaxItems: 1, - ConflictsWith: []string{"boolean_policy"}, + ConflictsWith: []string{"boolean_policy", "restore_policy"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "allow": { @@ -99,6 +99,20 @@ var schemaOrganizationPolicy = map[string]*schema.Schema{ Type: schema.TypeString, Computed: true, }, + "restore_policy": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ConflictsWith: []string{"boolean_policy", "list_policy"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "default": { + Type: schema.TypeBool, + Required: true, + }, + }, + }, + }, } func resourceGoogleOrganizationPolicy() *schema.Resource { @@ -152,6 +166,7 @@ func resourceGoogleOrganizationPolicyRead(d *schema.ResourceData, meta interface d.Set("version", policy.Version) d.Set("etag", policy.Etag) d.Set("update_time", policy.UpdateTime) + d.Set("restore_policy", flattenRestoreOrganizationPolicy(policy.RestoreDefault)) return nil } @@ -200,13 +215,19 @@ func setOrganizationPolicy(d *schema.ResourceData, meta interface{}) error { return err } + restoreDefault, err := expandRestoreOrganizationPolicy(d.Get("restore_policy").([]interface{})) + if err != nil { + return err + } + _, err = config.clientResourceManager.Organizations.SetOrgPolicy(org, &cloudresourcemanager.SetOrgPolicyRequest{ Policy: &cloudresourcemanager.OrgPolicy{ - Constraint: canonicalOrgPolicyConstraint(d.Get("constraint").(string)), - BooleanPolicy: expandBooleanOrganizationPolicy(d.Get("boolean_policy").([]interface{})), - ListPolicy: listPolicy, - Version: int64(d.Get("version").(int)), - Etag: d.Get("etag").(string), + Constraint: canonicalOrgPolicyConstraint(d.Get("constraint").(string)), + BooleanPolicy: expandBooleanOrganizationPolicy(d.Get("boolean_policy").([]interface{})), + ListPolicy: listPolicy, + RestoreDefault: restoreDefault, + Version: int64(d.Get("version").(int)), + Etag: d.Get("etag").(string), }, }).Do() @@ -227,6 +248,20 @@ func flattenBooleanOrganizationPolicy(policy *cloudresourcemanager.BooleanPolicy return bPolicies } +func flattenRestoreOrganizationPolicy(restore_policy *cloudresourcemanager.RestoreDefault) []map[string]interface{} { + rp := make([]map[string]interface{}, 0, 1) + + if restore_policy == nil { + return rp + } + + rp = append(rp, map[string]interface{}{ + "default": true, + }) + + return rp +} + func expandBooleanOrganizationPolicy(configured []interface{}) *cloudresourcemanager.BooleanPolicy { if len(configured) == 0 { return nil @@ -238,6 +273,21 @@ func expandBooleanOrganizationPolicy(configured []interface{}) *cloudresourceman } } +func expandRestoreOrganizationPolicy(configured []interface{}) (*cloudresourcemanager.RestoreDefault, error) { + if len(configured) == 0 { + return nil, nil + } + + restoreDefaultMap := configured[0].(map[string]interface{}) + default_value := restoreDefaultMap["default"].(bool) + + if default_value { + return &cloudresourcemanager.RestoreDefault{}, nil + } + + return nil, fmt.Errorf("Invalid value for restore_policy. Expecting default = true") +} + func flattenListOrganizationPolicy(policy *cloudresourcemanager.ListPolicy) []map[string]interface{} { lPolicies := make([]map[string]interface{}, 0, 1) diff --git a/google/resource_google_organization_policy_test.go b/google/resource_google_organization_policy_test.go index 4a09f0c8..b62a0bac 100644 --- a/google/resource_google_organization_policy_test.go +++ b/google/resource_google_organization_policy_test.go @@ -25,6 +25,7 @@ func TestAccOrganizationPolicy(t *testing.T) { "list_allowSome": testAccOrganizationPolicy_list_allowSome, "list_denySome": testAccOrganizationPolicy_list_denySome, "list_update": testAccOrganizationPolicy_list_update, + "restore_policy": testAccOrganizationPolicy_restore_defaultTrue, } for name, tc := range testCases { @@ -165,6 +166,26 @@ func testAccOrganizationPolicy_list_update(t *testing.T) { }) } +func testAccOrganizationPolicy_restore_defaultTrue(t *testing.T) { + org := getTestOrgTargetFromEnv(t) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckGoogleOrganizationPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccOrganizationPolicyConfig_restore_defaultTrue(org), + Check: testAccCheckGoogleOrganizationRestoreDefaultTrue("restore", &cloudresourcemanager.RestoreDefault{}), + }, + { + ResourceName: "google_organization_policy.restore", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccCheckGoogleOrganizationPolicyDestroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) @@ -258,6 +279,22 @@ func testAccCheckGoogleOrganizationListPolicyDeniedValues(n string, values []str } } +func testAccCheckGoogleOrganizationRestoreDefaultTrue(n string, policyDefault *cloudresourcemanager.RestoreDefault) resource.TestCheckFunc { + return func(s *terraform.State) error { + + policy, err := getGoogleOrganizationPolicyTestResource(s, n) + if err != nil { + return err + } + + if !reflect.DeepEqual(policy.RestoreDefault, policyDefault) { + return fmt.Errorf("Expected the restore default '%s', instead denied, %s", policyDefault, policy.RestoreDefault) + } + + return nil + } +} + func getGoogleOrganizationPolicyTestResource(s *terraform.State, n string) (*cloudresourcemanager.OrgPolicy, error) { rn := "google_organization_policy." + n rs, ok := s.RootModule().Resources[rn] @@ -279,12 +316,12 @@ func getGoogleOrganizationPolicyTestResource(s *terraform.State, n string) (*clo func testAccOrganizationPolicyConfig_boolean(org string, enforced bool) string { return fmt.Sprintf(` resource "google_organization_policy" "bool" { - org_id = "%s" - constraint = "constraints/compute.disableSerialPortAccess" + org_id = "%s" + constraint = "constraints/compute.disableSerialPortAccess" - boolean_policy { - enforced = %t - } + boolean_policy { + enforced = %t + } } `, org, enforced) } @@ -292,14 +329,14 @@ resource "google_organization_policy" "bool" { func testAccOrganizationPolicyConfig_list_allowAll(org string) string { return fmt.Sprintf(` resource "google_organization_policy" "list" { - org_id = "%s" - constraint = "constraints/serviceuser.services" + org_id = "%s" + constraint = "constraints/serviceuser.services" - list_policy { - allow { - all = true - } - } + list_policy { + allow { + all = true + } + } } `, org) } @@ -307,16 +344,16 @@ resource "google_organization_policy" "list" { func testAccOrganizationPolicyConfig_list_allowSome(org, project string) string { return fmt.Sprintf(` resource "google_organization_policy" "list" { - org_id = "%s" - constraint = "constraints/compute.trustedImageProjects" + org_id = "%s" + constraint = "constraints/compute.trustedImageProjects" - list_policy { - allow { - values = [ - "projects/%s", - "projects/debian-cloud" - ] - } + list_policy { + allow { + values = [ + "projects/%s", + "projects/debian-cloud" + ] + } } } `, org, project) @@ -325,17 +362,30 @@ resource "google_organization_policy" "list" { func testAccOrganizationPolicyConfig_list_denySome(org string) string { return fmt.Sprintf(` resource "google_organization_policy" "list" { - org_id = "%s" - constraint = "serviceuser.services" + org_id = "%s" + constraint = "serviceuser.services" - list_policy { - deny { - values = [ - "doubleclicksearch.googleapis.com", - "replicapoolupdater.googleapis.com", - ] - } - } + list_policy { + deny { + values = [ + "doubleclicksearch.googleapis.com", + "replicapoolupdater.googleapis.com", + ] + } + } +} +`, org) +} + +func testAccOrganizationPolicyConfig_restore_defaultTrue(org string) string { + return fmt.Sprintf(` +resource "google_organization_policy" "restore" { + org_id = "%s" + constraint = "serviceuser.services" + + restore_policy { + default = true + } } `, org) } diff --git a/google/resource_google_project_organization_policy.go b/google/resource_google_project_organization_policy.go index 2f986cf0..ca497d5d 100644 --- a/google/resource_google_project_organization_policy.go +++ b/google/resource_google_project_organization_policy.go @@ -52,6 +52,7 @@ func resourceGoogleProjectOrganizationPolicyRead(d *schema.ResourceData, meta in d.Set("constraint", policy.Constraint) d.Set("boolean_policy", flattenBooleanOrganizationPolicy(policy.BooleanPolicy)) d.Set("list_policy", flattenListOrganizationPolicy(policy.ListPolicy)) + d.Set("restore_policy", flattenRestoreOrganizationPolicy(policy.RestoreDefault)) d.Set("version", policy.Version) d.Set("etag", policy.Etag) d.Set("update_time", policy.UpdateTime) @@ -85,18 +86,25 @@ func resourceGoogleProjectOrganizationPolicyDelete(d *schema.ResourceData, meta func setProjectOrganizationPolicy(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) project := prefixedProject(d.Get("project").(string)) + listPolicy, err := expandListOrganizationPolicy(d.Get("list_policy").([]interface{})) if err != nil { return err } + restore_default, err := expandRestoreOrganizationPolicy(d.Get("restore_policy").([]interface{})) + if err != nil { + return err + } + _, err = config.clientResourceManager.Projects.SetOrgPolicy(project, &cloudresourcemanager.SetOrgPolicyRequest{ Policy: &cloudresourcemanager.OrgPolicy{ - Constraint: canonicalOrgPolicyConstraint(d.Get("constraint").(string)), - BooleanPolicy: expandBooleanOrganizationPolicy(d.Get("boolean_policy").([]interface{})), - ListPolicy: listPolicy, - Version: int64(d.Get("version").(int)), - Etag: d.Get("etag").(string), + Constraint: canonicalOrgPolicyConstraint(d.Get("constraint").(string)), + BooleanPolicy: expandBooleanOrganizationPolicy(d.Get("boolean_policy").([]interface{})), + ListPolicy: listPolicy, + RestoreDefault: restore_default, + Version: int64(d.Get("version").(int)), + Etag: d.Get("etag").(string), }, }).Do() diff --git a/google/resource_google_project_organization_policy_test.go b/google/resource_google_project_organization_policy_test.go index 84fcd52e..12067285 100644 --- a/google/resource_google_project_organization_policy_test.go +++ b/google/resource_google_project_organization_policy_test.go @@ -122,6 +122,22 @@ func TestAccProjectOrganizationPolicy_list_update(t *testing.T) { }) } +func TestAccProjectOrganizationPolicy_restore_defaultTrue(t *testing.T) { + projectId := getTestProjectFromEnv() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckGoogleProjectOrganizationPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccProjectOrganizationPolicy_restore_defaultTrue(projectId), + Check: getGoogleProjectOrganizationRestoreDefaultTrue("restore", &cloudresourcemanager.RestoreDefault{}), + }, + }, + }) +} + func testAccCheckGoogleProjectOrganizationPolicyDestroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) @@ -219,6 +235,22 @@ func testAccCheckGoogleProjectOrganizationListPolicyDeniedValues(n string, value } } +func getGoogleProjectOrganizationRestoreDefaultTrue(n string, policyDefault *cloudresourcemanager.RestoreDefault) resource.TestCheckFunc { + return func(s *terraform.State) error { + + policy, err := getGoogleProjectOrganizationPolicyTestResource(s, n) + if err != nil { + return err + } + + if !reflect.DeepEqual(policy.RestoreDefault, policyDefault) { + return fmt.Errorf("Expected the restore default '%s', instead denied, %s", policyDefault, policy.RestoreDefault) + } + + return nil + } +} + func getGoogleProjectOrganizationPolicyTestResource(s *terraform.State, n string) (*cloudresourcemanager.OrgPolicy, error) { rn := "google_project_organization_policy." + n rs, ok := s.RootModule().Resources[rn] @@ -301,6 +333,19 @@ resource "google_project_organization_policy" "list" { `, pid) } +func testAccProjectOrganizationPolicy_restore_defaultTrue(pid string) string { + return fmt.Sprintf(` +resource "google_project_organization_policy" "restore" { + project = "%s" + constraint = "constraints/serviceuser.services" + + restore_policy { + default = true + } +} +`, pid) +} + func canonicalProjectId(project string) string { if strings.HasPrefix(project, "projects/") { return project diff --git a/website/docs/r/google_folder_organization_policy.html.markdown b/website/docs/r/google_folder_organization_policy.html.markdown index 58401009..f9c79b4e 100644 --- a/website/docs/r/google_folder_organization_policy.html.markdown +++ b/website/docs/r/google_folder_organization_policy.html.markdown @@ -62,6 +62,19 @@ resource "google_folder_organization_policy" "services_policy" { } ``` +To restore the default folder organization policy, use the following instead: + +```hcl +resource "google_folder_organization_policy" "services_policy" { + folder = "folders/123456789" + constraint = "serviceuser.services" + + restore_policy { + default = true + } +} +``` + ## Argument Reference The following arguments are supported: @@ -76,7 +89,10 @@ The following arguments are supported: * `boolean_policy` - (Optional) A boolean policy is a constraint that is either enforced or not. Structure is documented below. -* `list_policy` - (Optional) A policy that can define specific values that are allowed or denied for the given constraint. It can also be used to allow or deny all values. Structure is documented below. +* `list_policy` - (Optional) A policy that can define specific values that are allowed or denied for the given constraint. It +can also be used to allow or deny all values. Structure is documented below. + +* `restore_policy` - (Optional) A restore policy is a constraint to restore the default policy. Structure is documented below. - - - @@ -96,6 +112,10 @@ The `allow` or `deny` blocks support: * `values` - (Optional) The policy can define specific values that are allowed or denied. +The `restore_policy` block supports: + +* `default` - (Required) May only be set to true. If set, then the default Policy is restored. + ## Attributes Reference In addition to the arguments listed above, the following computed attributes are diff --git a/website/docs/r/google_organization_policy.html.markdown b/website/docs/r/google_organization_policy.html.markdown index 15344d2b..ca0734c5 100644 --- a/website/docs/r/google_organization_policy.html.markdown +++ b/website/docs/r/google_organization_policy.html.markdown @@ -44,7 +44,6 @@ resource "google_organization_policy" "services_policy" { } ``` - Or to deny some services, use the following instead: ```hcl @@ -62,6 +61,19 @@ resource "google_organization_policy" "services_policy" { } ``` +To restore the default organization policy, use the following instead: + +```hcl +resource "google_organization_policy" "services_policy" { + org_id = "123456789" + constraint = "serviceuser.services" + + restore_policy { + default = true + } +} +``` + ## Argument Reference The following arguments are supported: @@ -78,6 +90,8 @@ The following arguments are supported: * `list_policy` - (Optional) A policy that can define specific values that are allowed or denied for the given constraint. It can also be used to allow or deny all values. Structure is documented below. +* `restore_policy` - (Optional) A restore policy is a constraint to restore the default policy. Structure is documented below. + - - - The `boolean_policy` block supports: @@ -96,6 +110,10 @@ The `allow` or `deny` blocks support: * `values` - (Optional) The policy can define specific values that are allowed or denied. +The `restore_policy` block supports: + +* `default` - (Required) May only be set to true. If set, then the default Policy is restored. + ## Attributes Reference In addition to the arguments listed above, the following computed attributes are diff --git a/website/docs/r/google_project_organization_policy.html.markdown b/website/docs/r/google_project_organization_policy.html.markdown index d210ba75..8004fb8b 100644 --- a/website/docs/r/google_project_organization_policy.html.markdown +++ b/website/docs/r/google_project_organization_policy.html.markdown @@ -62,6 +62,19 @@ resource "google_project_organization_policy" "services_policy" { } ``` +To restore the default project organization policy, use the following instead: + +```hcl +resource "google_project_organization_policy" "services_policy" { + project = "your-project-id" + constraint = "serviceuser.services" + + restore_policy { + default = true + } +} +``` + ## Argument Reference The following arguments are supported: @@ -78,6 +91,8 @@ The following arguments are supported: * `list_policy` - (Optional) A policy that can define specific values that are allowed or denied for the given constraint. It can also be used to allow or deny all values. Structure is documented below. +* `restore_policy` - (Optional) A restore policy is a constraint to restore the default policy. Structure is documented below. + - - - The `boolean_policy` block supports: @@ -96,6 +111,10 @@ The `allow` or `deny` blocks support: * `values` - (Optional) The policy can define specific values that are allowed or denied. +The `restore_policy` block supports: + +* `default` - (Required) May only be set to true. If set, then the default Policy is restored. + ## Attributes Reference In addition to the arguments listed above, the following computed attributes are