Skip to content

Commit e70873b

Browse files
Add datasource for ACM access policies (#12272) (#8676)
[upstream:a5e30bb31f73651675f353913e40fa26a6f4ff19] Signed-off-by: Modular Magician <[email protected]>
1 parent 82379f5 commit e70873b

File tree

5 files changed

+260
-0
lines changed

5 files changed

+260
-0
lines changed

.changelog/12272.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:new-datasource
2+
`google_access_context_manager_access_policy`
3+
```

google-beta/provider/provider_mmv1_resources.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ var handwrittenDatasources = map[string]*schema.Resource{
160160
"google_access_approval_folder_service_account": accessapproval.DataSourceAccessApprovalFolderServiceAccount(),
161161
"google_access_approval_organization_service_account": accessapproval.DataSourceAccessApprovalOrganizationServiceAccount(),
162162
"google_access_approval_project_service_account": accessapproval.DataSourceAccessApprovalProjectServiceAccount(),
163+
"google_access_context_manager_access_policy": accesscontextmanager.DataSourceAccessContextManagerAccessPolicy(),
163164
"google_active_folder": resourcemanager.DataSourceGoogleActiveFolder(),
164165
"google_alloydb_locations": alloydb.DataSourceAlloydbLocations(),
165166
"google_alloydb_supported_database_flags": alloydb.DataSourceAlloydbSupportedDatabaseFlags(),
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
package accesscontextmanager
4+
5+
import (
6+
"fmt"
7+
"slices"
8+
"strings"
9+
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
11+
"github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource"
12+
transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport"
13+
)
14+
15+
func DataSourceAccessContextManagerAccessPolicy() *schema.Resource {
16+
return &schema.Resource{
17+
Read: dataSourceAccessContextManagerAccessPolicyRead,
18+
Schema: map[string]*schema.Schema{
19+
"parent": {
20+
Type: schema.TypeString,
21+
Required: true,
22+
ForceNew: true,
23+
},
24+
"scopes": {
25+
Type: schema.TypeList,
26+
Elem: &schema.Schema{
27+
Type: schema.TypeString,
28+
},
29+
Optional: true,
30+
},
31+
"title": {
32+
Type: schema.TypeString,
33+
Computed: true,
34+
},
35+
"name": {
36+
Type: schema.TypeString,
37+
Computed: true,
38+
},
39+
},
40+
}
41+
}
42+
43+
func dataSourceAccessContextManagerAccessPolicyRead(d *schema.ResourceData, meta interface{}) error {
44+
config := meta.(*transport_tpg.Config)
45+
userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent)
46+
if err != nil {
47+
return err
48+
}
49+
50+
url, err := tpgresource.ReplaceVars(d, config, "{{AccessContextManagerBasePath}}accessPolicies?parent={{parent}}")
51+
if err != nil {
52+
return err
53+
}
54+
55+
billingProject := ""
56+
57+
// err == nil indicates that the billing_project value was found
58+
if bp, err := tpgresource.GetBillingProject(d, config); err == nil {
59+
billingProject = bp
60+
}
61+
62+
res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
63+
Config: config,
64+
Method: "GET",
65+
Project: billingProject,
66+
RawURL: url,
67+
UserAgent: userAgent,
68+
})
69+
70+
if err != nil {
71+
return transport_tpg.HandleDataSourceNotFoundError(err, d, fmt.Sprintf("AccessContextManagerAccessPolicy %q", d.Id()), url)
72+
}
73+
74+
if res == nil {
75+
return fmt.Errorf("Error fetching policies: %s", err)
76+
}
77+
78+
policies, err := parse_policies_response(res)
79+
if err != nil {
80+
fmt.Errorf("Error parsing list policies response: %s", err)
81+
}
82+
83+
// Find the matching policy in the list of policies response. Both the parent and scopes
84+
// should match
85+
for _, fetched_policy := range policies {
86+
scopes_match := compare_scopes(d.Get("scopes").([]interface{}), fetched_policy.Scopes)
87+
if fetched_policy.Parent == d.Get("parent").(string) && scopes_match {
88+
name_without_prefix := strings.Split(fetched_policy.Name, "accessPolicies/")[1]
89+
d.SetId(name_without_prefix)
90+
if err := d.Set("name", name_without_prefix); err != nil {
91+
return fmt.Errorf("Error setting policy name: %s", err)
92+
}
93+
94+
if err := d.Set("title", fetched_policy.Title); err != nil {
95+
return fmt.Errorf("Error setting policy title: %s", err)
96+
}
97+
98+
return nil
99+
}
100+
}
101+
102+
return nil
103+
}
104+
105+
func parse_policies_response(res map[string]interface{}) ([]AccessPolicy, error) {
106+
var policies []AccessPolicy
107+
for _, res_policy := range res["accessPolicies"].([]interface{}) {
108+
parsed_policy := &AccessPolicy{}
109+
110+
err := tpgresource.Convert(res_policy, parsed_policy)
111+
if err != nil {
112+
return nil, err
113+
}
114+
115+
policies = append(policies, *parsed_policy)
116+
}
117+
return policies, nil
118+
}
119+
120+
func compare_scopes(config_scopes []interface{}, policy_scopes []string) bool {
121+
// converts []interface{} to []string
122+
var config_scopes_slice []string
123+
for _, scope := range config_scopes {
124+
config_scopes_slice = append(config_scopes_slice, scope.(string))
125+
}
126+
127+
return slices.Equal(config_scopes_slice, policy_scopes)
128+
}
129+
130+
type AccessPolicy struct {
131+
Name string `json:"name"`
132+
Title string `json:"title"`
133+
Parent string `json:"parent"`
134+
Scopes []string `json:"scopes"`
135+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
package accesscontextmanager_test
4+
5+
import (
6+
"testing"
7+
8+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
9+
10+
"github.com/hashicorp/terraform-provider-google-beta/google-beta/acctest"
11+
"github.com/hashicorp/terraform-provider-google-beta/google-beta/envvar"
12+
)
13+
14+
func TestAccDataSourceAccessContextManagerServicePerimeter_basicTest(t *testing.T) {
15+
16+
org := envvar.GetTestOrgFromEnv(t)
17+
policyTitle := "my title"
18+
19+
acctest.VcrTest(t, resource.TestCase{
20+
PreCheck: func() { acctest.AccTestPreCheck(t) },
21+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
22+
Steps: []resource.TestStep{
23+
{
24+
Config: testAccAccessContextManagerServicePerimeterDataSource_basic(org, policyTitle),
25+
Check: resource.ComposeTestCheckFunc(
26+
acctest.CheckDataSourceStateMatchesResourceState("data.google_access_context_manager_access_policy.policy", "google_access_context_manager_access_policy.policy"),
27+
),
28+
},
29+
},
30+
})
31+
}
32+
33+
func testAccAccessContextManagerServicePerimeterDataSource_basic(org, policyTitle string) string {
34+
return acctest.Nprintf(`
35+
resource "google_access_context_manager_access_policy" "policy" {
36+
parent = "organizations/%{org}"
37+
title = "%{policyTitle}"
38+
}
39+
40+
data "google_access_context_manager_access_policy" "policy" {
41+
parent = "organizations/%{org}"
42+
depends_on = [ google_access_context_manager_access_policy.policy ]
43+
}
44+
`, map[string]interface{}{"org": org, "policyTitle": policyTitle})
45+
}
46+
47+
func TestAccDataSourceAccessContextManagerServicePerimeter_scopedPolicyTest(t *testing.T) {
48+
49+
org := envvar.GetTestOrgFromEnv(t)
50+
project := envvar.GetTestProjectNumberFromEnv()
51+
policyTitle := "my title"
52+
53+
acctest.VcrTest(t, resource.TestCase{
54+
PreCheck: func() { acctest.AccTestPreCheck(t) },
55+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
56+
Steps: []resource.TestStep{
57+
{
58+
Config: testAccAccessContextManagerServicePerimeterDataSource_scopedPolicy(org, project, policyTitle),
59+
Check: resource.ComposeTestCheckFunc(
60+
acctest.CheckDataSourceStateMatchesResourceState("data.google_access_context_manager_access_policy.policy", "google_access_context_manager_access_policy.policy"),
61+
),
62+
},
63+
},
64+
})
65+
}
66+
67+
func testAccAccessContextManagerServicePerimeterDataSource_scopedPolicy(org, project, policyTitle string) string {
68+
return acctest.Nprintf(`
69+
resource "google_access_context_manager_access_policy" "policy" {
70+
parent = "organizations/%{org}"
71+
title = "%{policyTitle}"
72+
scopes = ["projects/%{project}"]
73+
}
74+
75+
data "google_access_context_manager_access_policy" "policy" {
76+
parent = "organizations/%{org}"
77+
scopes = ["projects/%{project}"]
78+
depends_on = [ google_access_context_manager_access_policy.policy ]
79+
}
80+
`, map[string]interface{}{"org": org, "policyTitle": policyTitle, "project": project})
81+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
subcategory: "Access Context Manager (VPC Service Controls)"
3+
description: |-
4+
Fetches an AccessPolicy from Access Context Manager.
5+
---
6+
7+
# google_access_context_manager_access_policy
8+
9+
Get information about an Access Context Manager AccessPolicy.
10+
11+
## Example Usage
12+
13+
```tf
14+
data "google_access_context_manager_access_policy" "policy-org" {
15+
parent = "organizations/1234567"
16+
}
17+
18+
data "google_access_context_manager_access_policy" "policy-scoped" {
19+
parent = "organizations/1234567"
20+
scopes = ["projects/1234567"]
21+
}
22+
23+
```
24+
25+
## Argument Reference
26+
27+
The following arguments are supported:
28+
29+
* `parent` - (Required) The parent of this AccessPolicy in the Cloud Resource Hierarchy. Format: `organizations/{{organization_id}}`
30+
31+
* `scopes` - (Optional) Folder or project on which this policy is applicable. Format: `folders/{{folder_id}}` or `projects/{{project_number}}`
32+
33+
34+
## Attributes Reference
35+
36+
In addition to the arguments listed above, the following attributes are exported:
37+
38+
* `name` - Resource name of the AccessPolicy.
39+
40+
* `title` - Human readable title. Does not affect behavior.

0 commit comments

Comments
 (0)