mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-07-05 17:52:38 +00:00
google_project_organization_policy (#1226)
* support google_project_organization_policy * add documentation for google_project_organization_policy * remove "folder" references and cleanup docs * fix tests * un-parallelize tests * add comment about non-parralel tests * moving canonicalProjectId() to test
This commit is contained in:
parent
6a76b84d6e
commit
5b6e7f29c0
|
@ -180,6 +180,7 @@ func Provider() terraform.ResourceProvider {
|
|||
"google_project_iam_member": ResourceIamMemberWithImport(IamProjectSchema, NewProjectIamUpdater, ProjectIdParseFunc),
|
||||
"google_project_service": resourceGoogleProjectService(),
|
||||
"google_project_iam_custom_role": resourceGoogleProjectIamCustomRole(),
|
||||
"google_project_organization_policy": resourceGoogleProjectOrganizationPolicy(),
|
||||
"google_project_usage_export_bucket": resourceProjectUsageBucket(),
|
||||
"google_project_services": resourceGoogleProjectServices(),
|
||||
"google_pubsub_topic": resourcePubsubTopic(),
|
||||
|
|
104
google/resource_google_project_organization_policy.go
Normal file
104
google/resource_google_project_organization_policy.go
Normal file
|
@ -0,0 +1,104 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"google.golang.org/api/cloudresourcemanager/v1"
|
||||
)
|
||||
|
||||
func resourceGoogleProjectOrganizationPolicy() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceGoogleProjectOrganizationPolicyCreate,
|
||||
Read: resourceGoogleProjectOrganizationPolicyRead,
|
||||
Update: resourceGoogleProjectOrganizationPolicyUpdate,
|
||||
Delete: resourceGoogleProjectOrganizationPolicyDelete,
|
||||
|
||||
Schema: mergeSchemas(
|
||||
schemaOrganizationPolicy,
|
||||
map[string]*schema.Schema{
|
||||
"project": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func resourceGoogleProjectOrganizationPolicyCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
if err := setProjectOrganizationPolicy(d, meta); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.SetId(fmt.Sprintf("%s:%s", d.Get("project"), d.Get("constraint")))
|
||||
|
||||
return resourceGoogleProjectOrganizationPolicyRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceGoogleProjectOrganizationPolicyRead(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
project := prefixedProject(d.Get("project").(string))
|
||||
|
||||
policy, err := config.clientResourceManager.Projects.GetOrgPolicy(project, &cloudresourcemanager.GetOrgPolicyRequest{
|
||||
Constraint: canonicalOrgPolicyConstraint(d.Get("constraint").(string)),
|
||||
}).Do()
|
||||
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("Organization policy for %s", project))
|
||||
}
|
||||
|
||||
d.Set("constraint", policy.Constraint)
|
||||
d.Set("boolean_policy", flattenBooleanOrganizationPolicy(policy.BooleanPolicy))
|
||||
d.Set("list_policy", flattenListOrganizationPolicy(policy.ListPolicy))
|
||||
d.Set("version", policy.Version)
|
||||
d.Set("etag", policy.Etag)
|
||||
d.Set("update_time", policy.UpdateTime)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceGoogleProjectOrganizationPolicyUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
if err := setProjectOrganizationPolicy(d, meta); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return resourceGoogleProjectOrganizationPolicyRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceGoogleProjectOrganizationPolicyDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
project := prefixedProject(d.Get("project").(string))
|
||||
|
||||
_, err := config.clientResourceManager.Projects.ClearOrgPolicy(project, &cloudresourcemanager.ClearOrgPolicyRequest{
|
||||
Constraint: canonicalOrgPolicyConstraint(d.Get("constraint").(string)),
|
||||
}).Do()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
_, 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),
|
||||
},
|
||||
}).Do()
|
||||
|
||||
return err
|
||||
}
|
305
google/resource_google_project_organization_policy_test.go
Normal file
305
google/resource_google_project_organization_policy_test.go
Normal file
|
@ -0,0 +1,305 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"google.golang.org/api/cloudresourcemanager/v1"
|
||||
)
|
||||
|
||||
/*
|
||||
Tests for `google_project_organization_policy`
|
||||
|
||||
These are *not* run in parallel, as they all use the same project
|
||||
and I end up with 409 Conflict errors from the API when they are
|
||||
run in parallel.
|
||||
*/
|
||||
|
||||
func TestAccProjectOrganizationPolicy_boolean(t *testing.T) {
|
||||
projectId := getTestProjectFromEnv()
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckGoogleProjectOrganizationPolicyDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
// Test creation of an enforced boolean policy
|
||||
Config: testAccProjectOrganizationPolicy_boolean(projectId, true),
|
||||
Check: testAccCheckGoogleProjectOrganizationBooleanPolicy("bool", true),
|
||||
},
|
||||
{
|
||||
// Test update from enforced to not
|
||||
Config: testAccProjectOrganizationPolicy_boolean(projectId, false),
|
||||
Check: testAccCheckGoogleProjectOrganizationBooleanPolicy("bool", false),
|
||||
},
|
||||
{
|
||||
Config: " ",
|
||||
Destroy: true,
|
||||
},
|
||||
{
|
||||
// Test creation of a not enforced boolean policy
|
||||
Config: testAccProjectOrganizationPolicy_boolean(projectId, false),
|
||||
Check: testAccCheckGoogleProjectOrganizationBooleanPolicy("bool", false),
|
||||
},
|
||||
{
|
||||
// Test update from not enforced to enforced
|
||||
Config: testAccProjectOrganizationPolicy_boolean(projectId, true),
|
||||
Check: testAccCheckGoogleProjectOrganizationBooleanPolicy("bool", true),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccProjectOrganizationPolicy_list_allowAll(t *testing.T) {
|
||||
projectId := getTestProjectFromEnv()
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckGoogleProjectOrganizationPolicyDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccProjectOrganizationPolicy_list_allowAll(projectId),
|
||||
Check: testAccCheckGoogleProjectOrganizationListPolicyAll("list", "ALLOW"),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccProjectOrganizationPolicy_list_allowSome(t *testing.T) {
|
||||
project := getTestProjectFromEnv()
|
||||
canonicalProject := canonicalProjectId(project)
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckGoogleProjectOrganizationPolicyDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccProjectOrganizationPolicy_list_allowSome(project),
|
||||
Check: testAccCheckGoogleProjectOrganizationListPolicyAllowedValues("list", []string{canonicalProject}),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccProjectOrganizationPolicy_list_denySome(t *testing.T) {
|
||||
projectId := getTestProjectFromEnv()
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckGoogleProjectOrganizationPolicyDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccProjectOrganizationPolicy_list_denySome(projectId),
|
||||
Check: testAccCheckGoogleProjectOrganizationListPolicyDeniedValues("list", DENIED_ORG_POLICIES),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccProjectOrganizationPolicy_list_update(t *testing.T) {
|
||||
projectId := getTestProjectFromEnv()
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckGoogleProjectOrganizationPolicyDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccProjectOrganizationPolicy_list_allowAll(projectId),
|
||||
Check: testAccCheckGoogleProjectOrganizationListPolicyAll("list", "ALLOW"),
|
||||
},
|
||||
{
|
||||
Config: testAccProjectOrganizationPolicy_list_denySome(projectId),
|
||||
Check: testAccCheckGoogleProjectOrganizationListPolicyDeniedValues("list", DENIED_ORG_POLICIES),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckGoogleProjectOrganizationPolicyDestroy(s *terraform.State) error {
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "google_project_organization_policy" {
|
||||
continue
|
||||
}
|
||||
|
||||
projectId := canonicalProjectId(rs.Primary.Attributes["project"])
|
||||
constraint := canonicalOrgPolicyConstraint(rs.Primary.Attributes["constraint"])
|
||||
policy, err := config.clientResourceManager.Projects.GetOrgPolicy(projectId, &cloudresourcemanager.GetOrgPolicyRequest{
|
||||
Constraint: constraint,
|
||||
}).Do()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if policy.ListPolicy != nil || policy.BooleanPolicy != nil {
|
||||
return fmt.Errorf("Org policy with constraint '%s' hasn't been cleared", constraint)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckGoogleProjectOrganizationBooleanPolicy(n string, enforced bool) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
policy, err := getGoogleProjectOrganizationPolicyTestResource(s, n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if policy.BooleanPolicy.Enforced != enforced {
|
||||
return fmt.Errorf("Expected boolean policy enforcement to be '%t', got '%t'", enforced, policy.BooleanPolicy.Enforced)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckGoogleProjectOrganizationListPolicyAll(n, policyType string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
policy, err := getGoogleProjectOrganizationPolicyTestResource(s, n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(policy.ListPolicy.AllowedValues) > 0 || len(policy.ListPolicy.DeniedValues) > 0 {
|
||||
return fmt.Errorf("The `values` field shouldn't be set")
|
||||
}
|
||||
|
||||
if policy.ListPolicy.AllValues != policyType {
|
||||
return fmt.Errorf("The list policy should %s all values", policyType)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckGoogleProjectOrganizationListPolicyAllowedValues(n string, values []string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
policy, err := getGoogleProjectOrganizationPolicyTestResource(s, n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sort.Strings(policy.ListPolicy.AllowedValues)
|
||||
sort.Strings(values)
|
||||
if !reflect.DeepEqual(policy.ListPolicy.AllowedValues, values) {
|
||||
return fmt.Errorf("Expected the list policy to allow '%s', instead allowed '%s'", values, policy.ListPolicy.AllowedValues)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckGoogleProjectOrganizationListPolicyDeniedValues(n string, values []string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
policy, err := getGoogleProjectOrganizationPolicyTestResource(s, n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sort.Strings(policy.ListPolicy.DeniedValues)
|
||||
sort.Strings(values)
|
||||
if !reflect.DeepEqual(policy.ListPolicy.DeniedValues, values) {
|
||||
return fmt.Errorf("Expected the list policy to deny '%s', instead denied '%s'", values, policy.ListPolicy.DeniedValues)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func getGoogleProjectOrganizationPolicyTestResource(s *terraform.State, n string) (*cloudresourcemanager.OrgPolicy, error) {
|
||||
rn := "google_project_organization_policy." + n
|
||||
rs, ok := s.RootModule().Resources[rn]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Not found: %s", rn)
|
||||
}
|
||||
|
||||
if rs.Primary.ID == "" {
|
||||
return nil, fmt.Errorf("No ID is set")
|
||||
}
|
||||
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
projectId := canonicalProjectId(rs.Primary.Attributes["project"])
|
||||
|
||||
return config.clientResourceManager.Projects.GetOrgPolicy(projectId, &cloudresourcemanager.GetOrgPolicyRequest{
|
||||
Constraint: rs.Primary.Attributes["constraint"],
|
||||
}).Do()
|
||||
}
|
||||
|
||||
func testAccProjectOrganizationPolicy_boolean(pid string, enforced bool) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "google_project_organization_policy" "bool" {
|
||||
project = "%s"
|
||||
constraint = "constraints/compute.disableSerialPortAccess"
|
||||
|
||||
boolean_policy {
|
||||
enforced = %t
|
||||
}
|
||||
}
|
||||
`, pid, enforced)
|
||||
}
|
||||
|
||||
func testAccProjectOrganizationPolicy_list_allowAll(pid string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "google_project_organization_policy" "list" {
|
||||
project = "%s"
|
||||
constraint = "constraints/serviceuser.services"
|
||||
|
||||
list_policy {
|
||||
allow {
|
||||
all = true
|
||||
}
|
||||
}
|
||||
}
|
||||
`, pid)
|
||||
}
|
||||
|
||||
func testAccProjectOrganizationPolicy_list_allowSome(pid string) string {
|
||||
return fmt.Sprintf(`
|
||||
|
||||
resource "google_project_organization_policy" "list" {
|
||||
project = "%s"
|
||||
constraint = "constraints/compute.trustedImageProjects"
|
||||
|
||||
list_policy {
|
||||
allow {
|
||||
values = ["projects/%s"]
|
||||
}
|
||||
}
|
||||
}
|
||||
`, pid, pid)
|
||||
}
|
||||
|
||||
func testAccProjectOrganizationPolicy_list_denySome(pid string) string {
|
||||
return fmt.Sprintf(`
|
||||
|
||||
resource "google_project_organization_policy" "list" {
|
||||
project = "%s"
|
||||
constraint = "constraints/serviceuser.services"
|
||||
|
||||
list_policy {
|
||||
deny {
|
||||
values = [
|
||||
"doubleclicksearch.googleapis.com",
|
||||
"replicapoolupdater.googleapis.com",
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
`, pid)
|
||||
}
|
||||
|
||||
func canonicalProjectId(project string) string {
|
||||
if strings.HasPrefix(project, "projects/") {
|
||||
return project
|
||||
}
|
||||
return fmt.Sprintf("projects/%s", project)
|
||||
}
|
106
website/docs/r/google_project_organization_policy.html.markdown
Normal file
106
website/docs/r/google_project_organization_policy.html.markdown
Normal file
|
@ -0,0 +1,106 @@
|
|||
---
|
||||
layout: "google"
|
||||
page_title: "Google: google_project_organization_policy"
|
||||
sidebar_current: "docs-google-project-organization-policy"
|
||||
description: |-
|
||||
Allows management of Organization policies for a Google Project.
|
||||
---
|
||||
|
||||
# google\_project\_organization\_policy
|
||||
|
||||
Allows management of Organization policies for a Google Project. For more information see
|
||||
[the official
|
||||
documentation](https://cloud.google.com/resource-manager/docs/organization-policy/overview) and
|
||||
[API](https://cloud.google.com/resource-manager/reference/rest/v1/projects/setOrgPolicy).
|
||||
|
||||
## Example Usage
|
||||
|
||||
To set policy with a [boolean constraint](https://cloud.google.com/resource-manager/docs/organization-policy/quickstart-boolean-constraints):
|
||||
|
||||
```hcl
|
||||
resource "google_project_organization_policy" "serial_port_policy" {
|
||||
project = "your-project-id"
|
||||
constraint = "compute.disableSerialPortAccess"
|
||||
|
||||
boolean_policy {
|
||||
enforced = true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
To set a policy with a [list contraint](https://cloud.google.com/resource-manager/docs/organization-policy/quickstart-list-constraints):
|
||||
|
||||
```hcl
|
||||
resource "google_project_organization_policy" "services_policy" {
|
||||
project = "your-project-id"
|
||||
constraint = "serviceuser.services"
|
||||
|
||||
list_policy {
|
||||
allow {
|
||||
all = true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Or to deny some services, use the following instead:
|
||||
|
||||
```hcl
|
||||
resource "google_project_organization_policy" "services_policy" {
|
||||
project = "your-project-id"
|
||||
constraint = "serviceuser.services"
|
||||
|
||||
list_policy {
|
||||
suggested_values = "compute.googleapis.com"
|
||||
|
||||
deny {
|
||||
values = ["cloudresourcemanager.googleapis.com"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `project` - (Required) The project id of the project to set the policy for.
|
||||
|
||||
* `constraint` - (Required) The name of the Constraint the Policy is configuring, for example, `serviceuser.services`. Check out the [complete list of available constraints](https://cloud.google.com/resource-manager/docs/organization-policy/understanding-constraints#available_constraints).
|
||||
|
||||
- - -
|
||||
|
||||
* `version` - (Optional) Version of the Policy. Default version is 0.
|
||||
|
||||
* `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.
|
||||
|
||||
- - -
|
||||
|
||||
The `boolean_policy` block supports:
|
||||
|
||||
* `enforced` - (Required) If true, then the Policy is enforced. If false, then any configuration is acceptable.
|
||||
|
||||
The `list_policy` block supports:
|
||||
|
||||
* `allow` or `deny` - (Optional) One or the other must be set.
|
||||
|
||||
* `suggested_values` - (Optional) The Google Cloud Console will try to default to a configuration that matches the value specified in this field.
|
||||
|
||||
The `allow` or `deny` blocks support:
|
||||
|
||||
* `all` - (Optional) The policy allows or denies all values.
|
||||
|
||||
* `values` - (Optional) The policy can define specific values that are allowed or denied.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
In addition to the arguments listed above, the following computed attributes are
|
||||
exported:
|
||||
|
||||
* `etag` - (Computed) The etag of the organization policy. `etag` is used for optimistic concurrency control as a way to help prevent simultaneous updates of a policy from overwriting each other.
|
||||
|
||||
* `update_time` - (Computed) The timestamp in RFC3339 UTC "Zulu" format, accurate to nanoseconds, representing when the variable was last updated. Example: "2016-10-09T12:33:37.578138407Z".
|
|
@ -180,6 +180,9 @@
|
|||
<li<%= sidebar_current("docs-google-project-iam-custom-role") %>>
|
||||
<a href="/docs/providers/google/r/google_project_iam_custom_role.html">google_project_iam_custom_role</a>
|
||||
</li>
|
||||
<li<%= sidebar_current("docs-google-project-organization-policy") %>>
|
||||
<a href="/docs/providers/google/r/google_project_organization_policy.html">google_project_organization_policy</a>
|
||||
</li>
|
||||
<li<%= sidebar_current("docs-google-project-service-x") %>>
|
||||
<a href="/docs/providers/google/r/google_project_service.html">google_project_service</a>
|
||||
</li>
|
||||
|
|
Loading…
Reference in New Issue
Block a user