Skip to content

Commit 871fc81

Browse files
coder-221rileykarson
authored andcommitted
Add datasource for ACM access policies (GoogleCloudPlatform#12272)
Co-authored-by: Riley Karson <[email protected]>
1 parent ac4683e commit 871fc81

File tree

4 files changed

+253
-0
lines changed

4 files changed

+253
-0
lines changed

mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ var handwrittenDatasources = map[string]*schema.Resource{
2323
"google_access_approval_folder_service_account": accessapproval.DataSourceAccessApprovalFolderServiceAccount(),
2424
"google_access_approval_organization_service_account": accessapproval.DataSourceAccessApprovalOrganizationServiceAccount(),
2525
"google_access_approval_project_service_account": accessapproval.DataSourceAccessApprovalProjectServiceAccount(),
26+
"google_access_context_manager_access_policy": accesscontextmanager.DataSourceAccessContextManagerAccessPolicy(),
2627
"google_active_folder": resourcemanager.DataSourceGoogleActiveFolder(),
2728
"google_alloydb_locations": alloydb.DataSourceAlloydbLocations(),
2829
"google_alloydb_supported_database_flags": alloydb.DataSourceAlloydbSupportedDatabaseFlags(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package accesscontextmanager
2+
3+
import (
4+
"fmt"
5+
"slices"
6+
"strings"
7+
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
9+
"github.com/hashicorp/terraform-provider-google/google/tpgresource"
10+
transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport"
11+
)
12+
13+
func DataSourceAccessContextManagerAccessPolicy() *schema.Resource {
14+
return &schema.Resource{
15+
Read: dataSourceAccessContextManagerAccessPolicyRead,
16+
Schema: map[string]*schema.Schema{
17+
"parent": {
18+
Type: schema.TypeString,
19+
Required: true,
20+
ForceNew: true,
21+
},
22+
"scopes": {
23+
Type: schema.TypeList,
24+
Elem: &schema.Schema{
25+
Type: schema.TypeString,
26+
},
27+
Optional: true,
28+
},
29+
"title": {
30+
Type: schema.TypeString,
31+
Computed: true,
32+
},
33+
"name": {
34+
Type: schema.TypeString,
35+
Computed: true,
36+
},
37+
},
38+
}
39+
}
40+
41+
func dataSourceAccessContextManagerAccessPolicyRead(d *schema.ResourceData, meta interface{}) error {
42+
config := meta.(*transport_tpg.Config)
43+
userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent)
44+
if err != nil {
45+
return err
46+
}
47+
48+
url, err := tpgresource.ReplaceVars(d, config, "{{AccessContextManagerBasePath}}accessPolicies?parent={{parent}}")
49+
if err != nil {
50+
return err
51+
}
52+
53+
billingProject := ""
54+
55+
// err == nil indicates that the billing_project value was found
56+
if bp, err := tpgresource.GetBillingProject(d, config); err == nil {
57+
billingProject = bp
58+
}
59+
60+
res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
61+
Config: config,
62+
Method: "GET",
63+
Project: billingProject,
64+
RawURL: url,
65+
UserAgent: userAgent,
66+
})
67+
68+
if err != nil {
69+
return transport_tpg.HandleDataSourceNotFoundError(err, d, fmt.Sprintf("AccessContextManagerAccessPolicy %q", d.Id()), url)
70+
}
71+
72+
if res == nil {
73+
return fmt.Errorf("Error fetching policies: %s", err)
74+
}
75+
76+
policies, err := parse_policies_response(res)
77+
if err != nil {
78+
fmt.Errorf("Error parsing list policies response: %s", err)
79+
}
80+
81+
// Find the matching policy in the list of policies response. Both the parent and scopes
82+
// should match
83+
for _, fetched_policy := range policies {
84+
scopes_match := compare_scopes(d.Get("scopes").([]interface{}), fetched_policy.Scopes)
85+
if fetched_policy.Parent == d.Get("parent").(string) && scopes_match {
86+
name_without_prefix := strings.Split(fetched_policy.Name, "accessPolicies/")[1]
87+
d.SetId(name_without_prefix)
88+
if err := d.Set("name", name_without_prefix); err != nil {
89+
return fmt.Errorf("Error setting policy name: %s", err)
90+
}
91+
92+
if err := d.Set("title", fetched_policy.Title); err != nil {
93+
return fmt.Errorf("Error setting policy title: %s", err)
94+
}
95+
96+
return nil
97+
}
98+
}
99+
100+
return nil
101+
}
102+
103+
func parse_policies_response(res map[string]interface{}) ([]AccessPolicy, error) {
104+
var policies []AccessPolicy
105+
for _, res_policy := range res["accessPolicies"].([]interface{}) {
106+
parsed_policy := &AccessPolicy{}
107+
108+
err := tpgresource.Convert(res_policy, parsed_policy)
109+
if err != nil {
110+
return nil, err
111+
}
112+
113+
policies = append(policies, *parsed_policy)
114+
}
115+
return policies, nil
116+
}
117+
118+
func compare_scopes(config_scopes []interface{}, policy_scopes []string) bool {
119+
// converts []interface{} to []string
120+
var config_scopes_slice []string
121+
for _, scope := range config_scopes {
122+
config_scopes_slice = append(config_scopes_slice, scope.(string))
123+
}
124+
125+
return slices.Equal(config_scopes_slice, policy_scopes)
126+
}
127+
128+
type AccessPolicy struct {
129+
Name string `json:"name"`
130+
Title string `json:"title"`
131+
Parent string `json:"parent"`
132+
Scopes []string `json:"scopes"`
133+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package accesscontextmanager_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
7+
8+
"github.com/hashicorp/terraform-provider-google/google/acctest"
9+
"github.com/hashicorp/terraform-provider-google/google/envvar"
10+
)
11+
12+
func TestAccDataSourceAccessContextManagerServicePerimeter_basicTest(t *testing.T) {
13+
14+
org := envvar.GetTestOrgFromEnv(t)
15+
policyTitle := "my title"
16+
17+
acctest.VcrTest(t, resource.TestCase{
18+
PreCheck: func() { acctest.AccTestPreCheck(t) },
19+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
20+
Steps: []resource.TestStep{
21+
{
22+
Config: testAccAccessContextManagerServicePerimeterDataSource_basic(org, policyTitle),
23+
Check: resource.ComposeTestCheckFunc(
24+
acctest.CheckDataSourceStateMatchesResourceState("data.google_access_context_manager_access_policy.policy", "google_access_context_manager_access_policy.policy"),
25+
),
26+
},
27+
},
28+
})
29+
}
30+
31+
func testAccAccessContextManagerServicePerimeterDataSource_basic(org, policyTitle string) string {
32+
return acctest.Nprintf(`
33+
resource "google_access_context_manager_access_policy" "policy" {
34+
parent = "organizations/%{org}"
35+
title = "%{policyTitle}"
36+
}
37+
38+
data "google_access_context_manager_access_policy" "policy" {
39+
parent = "organizations/%{org}"
40+
depends_on = [ google_access_context_manager_access_policy.policy ]
41+
}
42+
`, map[string]interface{}{"org": org, "policyTitle": policyTitle})
43+
}
44+
45+
func TestAccDataSourceAccessContextManagerServicePerimeter_scopedPolicyTest(t *testing.T) {
46+
47+
org := envvar.GetTestOrgFromEnv(t)
48+
project := envvar.GetTestProjectNumberFromEnv()
49+
policyTitle := "my title"
50+
51+
acctest.VcrTest(t, resource.TestCase{
52+
PreCheck: func() { acctest.AccTestPreCheck(t) },
53+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
54+
Steps: []resource.TestStep{
55+
{
56+
Config: testAccAccessContextManagerServicePerimeterDataSource_scopedPolicy(org, project, policyTitle),
57+
Check: resource.ComposeTestCheckFunc(
58+
acctest.CheckDataSourceStateMatchesResourceState("data.google_access_context_manager_access_policy.policy", "google_access_context_manager_access_policy.policy"),
59+
),
60+
},
61+
},
62+
})
63+
}
64+
65+
func testAccAccessContextManagerServicePerimeterDataSource_scopedPolicy(org, project, policyTitle string) string {
66+
return acctest.Nprintf(`
67+
resource "google_access_context_manager_access_policy" "policy" {
68+
parent = "organizations/%{org}"
69+
title = "%{policyTitle}"
70+
scopes = ["projects/%{project}"]
71+
}
72+
73+
data "google_access_context_manager_access_policy" "policy" {
74+
parent = "organizations/%{org}"
75+
scopes = ["projects/%{project}"]
76+
depends_on = [ google_access_context_manager_access_policy.policy ]
77+
}
78+
`, map[string]interface{}{"org": org, "policyTitle": policyTitle, "project": project})
79+
}
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)