Skip to content

Commit

Permalink
Add datasource for ACM access policies (#12272) (#20295)
Browse files Browse the repository at this point in the history
[upstream:a5e30bb31f73651675f353913e40fa26a6f4ff19]

Signed-off-by: Modular Magician <[email protected]>
  • Loading branch information
modular-magician authored Nov 11, 2024
1 parent 6a6aa09 commit 863bc41
Show file tree
Hide file tree
Showing 5 changed files with 260 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/12272.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-datasource
`google_access_context_manager_access_policy`
```
1 change: 1 addition & 0 deletions google/provider/provider_mmv1_resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ var handwrittenDatasources = map[string]*schema.Resource{
"google_access_approval_folder_service_account": accessapproval.DataSourceAccessApprovalFolderServiceAccount(),
"google_access_approval_organization_service_account": accessapproval.DataSourceAccessApprovalOrganizationServiceAccount(),
"google_access_approval_project_service_account": accessapproval.DataSourceAccessApprovalProjectServiceAccount(),
"google_access_context_manager_access_policy": accesscontextmanager.DataSourceAccessContextManagerAccessPolicy(),
"google_active_folder": resourcemanager.DataSourceGoogleActiveFolder(),
"google_alloydb_locations": alloydb.DataSourceAlloydbLocations(),
"google_alloydb_supported_database_flags": alloydb.DataSourceAlloydbSupportedDatabaseFlags(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package accesscontextmanager

import (
"fmt"
"slices"
"strings"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-google/google/tpgresource"
transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport"
)

func DataSourceAccessContextManagerAccessPolicy() *schema.Resource {
return &schema.Resource{
Read: dataSourceAccessContextManagerAccessPolicyRead,
Schema: map[string]*schema.Schema{
"parent": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"scopes": {
Type: schema.TypeList,
Elem: &schema.Schema{
Type: schema.TypeString,
},
Optional: true,
},
"title": {
Type: schema.TypeString,
Computed: true,
},
"name": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func dataSourceAccessContextManagerAccessPolicyRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*transport_tpg.Config)
userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent)
if err != nil {
return err
}

url, err := tpgresource.ReplaceVars(d, config, "{{AccessContextManagerBasePath}}accessPolicies?parent={{parent}}")
if err != nil {
return err
}

billingProject := ""

// err == nil indicates that the billing_project value was found
if bp, err := tpgresource.GetBillingProject(d, config); err == nil {
billingProject = bp
}

res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
Config: config,
Method: "GET",
Project: billingProject,
RawURL: url,
UserAgent: userAgent,
})

if err != nil {
return transport_tpg.HandleDataSourceNotFoundError(err, d, fmt.Sprintf("AccessContextManagerAccessPolicy %q", d.Id()), url)
}

if res == nil {
return fmt.Errorf("Error fetching policies: %s", err)
}

policies, err := parse_policies_response(res)
if err != nil {
fmt.Errorf("Error parsing list policies response: %s", err)
}

// Find the matching policy in the list of policies response. Both the parent and scopes
// should match
for _, fetched_policy := range policies {
scopes_match := compare_scopes(d.Get("scopes").([]interface{}), fetched_policy.Scopes)
if fetched_policy.Parent == d.Get("parent").(string) && scopes_match {
name_without_prefix := strings.Split(fetched_policy.Name, "accessPolicies/")[1]
d.SetId(name_without_prefix)
if err := d.Set("name", name_without_prefix); err != nil {
return fmt.Errorf("Error setting policy name: %s", err)
}

if err := d.Set("title", fetched_policy.Title); err != nil {
return fmt.Errorf("Error setting policy title: %s", err)
}

return nil
}
}

return nil
}

func parse_policies_response(res map[string]interface{}) ([]AccessPolicy, error) {
var policies []AccessPolicy
for _, res_policy := range res["accessPolicies"].([]interface{}) {
parsed_policy := &AccessPolicy{}

err := tpgresource.Convert(res_policy, parsed_policy)
if err != nil {
return nil, err
}

policies = append(policies, *parsed_policy)
}
return policies, nil
}

func compare_scopes(config_scopes []interface{}, policy_scopes []string) bool {
// converts []interface{} to []string
var config_scopes_slice []string
for _, scope := range config_scopes {
config_scopes_slice = append(config_scopes_slice, scope.(string))
}

return slices.Equal(config_scopes_slice, policy_scopes)
}

type AccessPolicy struct {
Name string `json:"name"`
Title string `json:"title"`
Parent string `json:"parent"`
Scopes []string `json:"scopes"`
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package accesscontextmanager_test

import (
"testing"

"github.com/hashicorp/terraform-plugin-testing/helper/resource"

"github.com/hashicorp/terraform-provider-google/google/acctest"
"github.com/hashicorp/terraform-provider-google/google/envvar"
)

func TestAccDataSourceAccessContextManagerServicePerimeter_basicTest(t *testing.T) {

org := envvar.GetTestOrgFromEnv(t)
policyTitle := "my title"

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
Steps: []resource.TestStep{
{
Config: testAccAccessContextManagerServicePerimeterDataSource_basic(org, policyTitle),
Check: resource.ComposeTestCheckFunc(
acctest.CheckDataSourceStateMatchesResourceState("data.google_access_context_manager_access_policy.policy", "google_access_context_manager_access_policy.policy"),
),
},
},
})
}

func testAccAccessContextManagerServicePerimeterDataSource_basic(org, policyTitle string) string {
return acctest.Nprintf(`
resource "google_access_context_manager_access_policy" "policy" {
parent = "organizations/%{org}"
title = "%{policyTitle}"
}
data "google_access_context_manager_access_policy" "policy" {
parent = "organizations/%{org}"
depends_on = [ google_access_context_manager_access_policy.policy ]
}
`, map[string]interface{}{"org": org, "policyTitle": policyTitle})
}

func TestAccDataSourceAccessContextManagerServicePerimeter_scopedPolicyTest(t *testing.T) {

org := envvar.GetTestOrgFromEnv(t)
project := envvar.GetTestProjectNumberFromEnv()
policyTitle := "my title"

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
Steps: []resource.TestStep{
{
Config: testAccAccessContextManagerServicePerimeterDataSource_scopedPolicy(org, project, policyTitle),
Check: resource.ComposeTestCheckFunc(
acctest.CheckDataSourceStateMatchesResourceState("data.google_access_context_manager_access_policy.policy", "google_access_context_manager_access_policy.policy"),
),
},
},
})
}

func testAccAccessContextManagerServicePerimeterDataSource_scopedPolicy(org, project, policyTitle string) string {
return acctest.Nprintf(`
resource "google_access_context_manager_access_policy" "policy" {
parent = "organizations/%{org}"
title = "%{policyTitle}"
scopes = ["projects/%{project}"]
}
data "google_access_context_manager_access_policy" "policy" {
parent = "organizations/%{org}"
scopes = ["projects/%{project}"]
depends_on = [ google_access_context_manager_access_policy.policy ]
}
`, map[string]interface{}{"org": org, "policyTitle": policyTitle, "project": project})
}
40 changes: 40 additions & 0 deletions website/docs/d/access_context_manager_access_policy.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
subcategory: "Access Context Manager (VPC Service Controls)"
description: |-
Fetches an AccessPolicy from Access Context Manager.
---

# google_access_context_manager_access_policy

Get information about an Access Context Manager AccessPolicy.

## Example Usage

```tf
data "google_access_context_manager_access_policy" "policy-org" {
parent = "organizations/1234567"
}
data "google_access_context_manager_access_policy" "policy-scoped" {
parent = "organizations/1234567"
scopes = ["projects/1234567"]
}
```

## Argument Reference

The following arguments are supported:

* `parent` - (Required) The parent of this AccessPolicy in the Cloud Resource Hierarchy. Format: `organizations/{{organization_id}}`

* `scopes` - (Optional) Folder or project on which this policy is applicable. Format: `folders/{{folder_id}}` or `projects/{{project_number}}`


## Attributes Reference

In addition to the arguments listed above, the following attributes are exported:

* `name` - Resource name of the AccessPolicy.

* `title` - Human readable title. Does not affect behavior.

0 comments on commit 863bc41

Please sign in to comment.