Skip to content

Commit

Permalink
add cloud identity data sources (#3714) (#2240)
Browse files Browse the repository at this point in the history
* add datasources for groups and group memberships in cloud identity

* remove comment

* fix docs

* make config changes beta-only

Signed-off-by: Modular Magician <[email protected]>
  • Loading branch information
modular-magician authored Jun 26, 2020
1 parent d28ccf6 commit 0eddadb
Show file tree
Hide file tree
Showing 10 changed files with 408 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .changelog/3714.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
```release-note:new-datasource
`google_cloud_identity_groups`
```
```release-note:new-datasource
`google_cloud_identity_group_memberships`
```
13 changes: 13 additions & 0 deletions google-beta/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"google.golang.org/api/cloudbilling/v1"
"google.golang.org/api/cloudbuild/v1"
"google.golang.org/api/cloudfunctions/v1"
cloudidentity "google.golang.org/api/cloudidentity/v1beta1"
"google.golang.org/api/cloudiot/v1"
"google.golang.org/api/cloudkms/v1"
"google.golang.org/api/cloudresourcemanager/v1"
Expand Down Expand Up @@ -142,6 +143,8 @@ type Config struct {

clientBuild *cloudbuild.Service

clientCloudIdentity *cloudidentity.Service

ComposerBasePath string
clientComposer *composer.Service

Expand Down Expand Up @@ -671,6 +674,16 @@ func (c *Config) LoadAndValidate(ctx context.Context) error {
c.clientHealthcare.UserAgent = userAgent
c.clientHealthcare.BasePath = healthcareClientBasePath

cloudidentityClientBasePath := removeBasePathVersion(c.CloudIdentityBasePath)
log.Printf("[INFO] Instantiating Google Cloud CloudIdentity client for path %s", cloudidentityClientBasePath)

c.clientCloudIdentity, err = cloudidentity.NewService(ctx, option.WithHTTPClient(client))
if err != nil {
return err
}
c.clientCloudIdentity.UserAgent = userAgent
c.clientCloudIdentity.BasePath = cloudidentityClientBasePath

c.Region = GetRegionFromRegionSelfLink(c.Region)

c.requestBatcherServiceUsage = NewRequestBatcher("Service Usage", ctx, c.BatchingConfig)
Expand Down
70 changes: 70 additions & 0 deletions google-beta/data_source_cloud_identity_group_memberships.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package google

import (
"fmt"
"time"

"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
cloudidentity "google.golang.org/api/cloudidentity/v1beta1"
)

func dataSourceGoogleCloudIdentityGroupMemberships() *schema.Resource {
// Generate datasource schema from resource
dsSchema := datasourceSchemaFromResourceSchema(resourceCloudIdentityGroupMembership().Schema)

return &schema.Resource{
Read: dataSourceGoogleCloudIdentityGroupMembershipsRead,

Schema: map[string]*schema.Schema{
"memberships": {
Type: schema.TypeList,
Computed: true,
Description: `List of Cloud Identity group memberships.`,
Elem: &schema.Resource{
Schema: dsSchema,
},
},
"group": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
DiffSuppressFunc: compareSelfLinkOrResourceName,
Description: `The name of the Group to get memberships from.`,
},
},
}
}

func dataSourceGoogleCloudIdentityGroupMembershipsRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)

resp, err := config.clientCloudIdentity.Groups.Memberships.List(d.Get("group").(string)).View("FULL").Do()
if err != nil {
return handleNotFoundError(err, d, fmt.Sprintf("CloudIdentityGroups %q", d.Id()))
}

result := []map[string]interface{}{}
for _, member := range resp.Memberships {
result = append(result, map[string]interface{}{
"name": member.Name,
"roles": flattenCloudIdentityGroupMembershipsRoles(member.Roles),
"member_key": flattenCloudIdentityGroupsEntityKey(member.MemberKey),
"preferred_member_key": flattenCloudIdentityGroupsEntityKey(member.PreferredMemberKey),
})
}

d.Set("memberships", result)
d.SetId(time.Now().UTC().String())
return nil
}

func flattenCloudIdentityGroupMembershipsRoles(roles []*cloudidentity.MembershipRole) []interface{} {
transformed := []interface{}{}

for _, role := range roles {
transformed = append(transformed, map[string]interface{}{
"name": role.Name,
})
}
return transformed
}
48 changes: 48 additions & 0 deletions google-beta/data_source_cloud_identity_group_memberships_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package google

import (
"testing"

"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
)

func TestAccDataSourceCloudIdentityGroupMemberships_basic(t *testing.T) {

context := map[string]interface{}{
"org_domain": getTestOrgDomainFromEnv(t),
"cust_id": getTestCustIdFromEnv(t),
"identity_user": getTestIdentityUserFromEnv(t),
"random_suffix": randString(t, 10),
}

memberId := Nprintf("%{identity_user}@%{org_domain}", context)

vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProvidersOiCS,
Steps: []resource.TestStep{
{
Config: testAccCloudIdentityGroupMembershipConfig(context),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.google_cloud_identity_group_memberships.members",
"memberships.#", "1"),
resource.TestCheckResourceAttr("data.google_cloud_identity_group_memberships.members",
"memberships.0.roles.#", "2"),
resource.TestCheckResourceAttr("data.google_cloud_identity_group_memberships.members",
"memberships.0.member_key.0.id", memberId),
),
},
},
})
}

func testAccCloudIdentityGroupMembershipConfig(context map[string]interface{}) string {
return testAccCloudIdentityGroupMembership_cloudIdentityGroupMembershipUserExample(context) + Nprintf(`
data "google_cloud_identity_group_memberships" "members" {
provider = google-beta
group = google_cloud_identity_group_membership.cloud_identity_group_membership_basic.group
}
`, context)
}
71 changes: 71 additions & 0 deletions google-beta/data_source_cloud_identity_groups.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package google

import (
"fmt"
"time"

"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
cloudidentity "google.golang.org/api/cloudidentity/v1beta1"
)

func dataSourceGoogleCloudIdentityGroups() *schema.Resource {
// Generate datasource schema from resource
dsSchema := datasourceSchemaFromResourceSchema(resourceCloudIdentityGroup().Schema)

return &schema.Resource{
Read: dataSourceGoogleCloudIdentityGroupsRead,

Schema: map[string]*schema.Schema{
"groups": {
Type: schema.TypeList,
Computed: true,
Description: `List of Cloud Identity groups.`,
Elem: &schema.Resource{
Schema: dsSchema,
},
},
"parent": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: `The resource name of the entity under which this Group resides in the
Cloud Identity resource hierarchy.
Must be of the form identitysources/{identity_source_id} for external-identity-mapped
groups or customers/{customer_id} for Google Groups.`,
},
},
}
}

func dataSourceGoogleCloudIdentityGroupsRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)

resp, err := config.clientCloudIdentity.Groups.List().Parent(d.Get("parent").(string)).View("FULL").Do()
if err != nil {
return handleNotFoundError(err, d, fmt.Sprintf("CloudIdentityGroups %q", d.Id()))
}

result := []map[string]interface{}{}
for _, group := range resp.Groups {
result = append(result, map[string]interface{}{
"name": group.Name,
"display_name": group.DisplayName,
"labels": group.Labels,
"description": group.Description,
"group_key": flattenCloudIdentityGroupsEntityKey(group.GroupKey),
})
}

d.Set("groups", result)
d.SetId(time.Now().UTC().String())
return nil
}

func flattenCloudIdentityGroupsEntityKey(entityKey *cloudidentity.EntityKey) []interface{} {
transformed := map[string]interface{}{
"id": entityKey.Id,
"namespace": entityKey.Namespace,
}
return []interface{}{transformed}
}
44 changes: 44 additions & 0 deletions google-beta/data_source_cloud_identity_groups_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package google

import (
"regexp"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
)

func TestAccDataSourceCloudIdentityGroups_basic(t *testing.T) {

context := map[string]interface{}{
"org_domain": getTestOrgDomainFromEnv(t),
"cust_id": getTestCustIdFromEnv(t),
"random_suffix": randString(t, 10),
}

vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProvidersOiCS,
Steps: []resource.TestStep{
{
Config: testAccCloudIdentityGroupConfig(context),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("data.google_cloud_identity_groups.groups",
"groups.#"),
resource.TestMatchResourceAttr("data.google_cloud_identity_groups.groups",
"groups.0.name", regexp.MustCompile("^groups/.*$")),
),
},
},
})
}

func testAccCloudIdentityGroupConfig(context map[string]interface{}) string {
return testAccCloudIdentityGroup_cloudIdentityGroupsBasicExample(context) + Nprintf(`
data "google_cloud_identity_groups" "groups" {
provider = google-beta
parent = google_cloud_identity_group.cloud_identity_group_basic.parent
}
`, context)
}
2 changes: 2 additions & 0 deletions google-beta/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,8 @@ func Provider() terraform.ResourceProvider {
"google_client_config": dataSourceGoogleClientConfig(),
"google_client_openid_userinfo": dataSourceGoogleClientOpenIDUserinfo(),
"google_cloudfunctions_function": dataSourceGoogleCloudFunctionsFunction(),
"google_cloud_identity_groups": dataSourceGoogleCloudIdentityGroups(),
"google_cloud_identity_group_memberships": dataSourceGoogleCloudIdentityGroupMemberships(),
"google_composer_image_versions": dataSourceGoogleComposerImageVersions(),
"google_compute_address": dataSourceGoogleComputeAddress(),
"google_compute_backend_service": dataSourceGoogleComputeBackendService(),
Expand Down
74 changes: 74 additions & 0 deletions website/docs/d/cloud_identity_group_membership.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
subcategory: "Cloud Identity"
layout: "google"
page_title: "Google: google_cloud_identity_group_memberships"
sidebar_current: "docs-google-datasource-cloud-identity-group-memberships"
description: |-
Get list of the Cloud Identity Group Memberships within a Group.
---

# google_cloud_identity_group_memberships

Use this data source to get list of the Cloud Identity Group Memberships within a given Group.

https://cloud.google.com/identity/docs/concepts/overview#memberships

## Example Usage

```tf
data "google_cloud_identity_group_memberships" "members" {
group = "groups/123eab45c6defghi"
}
```

## Argument Reference

* `group` - The parent Group resource under which to lookup the Membership names. Must be of the form groups/{group_id}.

## Attributes Reference

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

* `memberships` - The list of memberships under the given group. Structure is documented below.

The `memberships` block contains:

* `name` -
The resource name of the Membership, of the form groups/{group_id}/memberships/{membership_id}.

* `roles` - The MembershipRoles that apply to the Membership. Structure is documented below.

* `member_key` -
(Optional)
EntityKey of the member. Structure is documented below.

* `preferred_member_key` -
(Optional)
EntityKey of the member. Structure is documented below.

The `roles` block supports:

* `name` - The name of the MembershipRole. One of OWNER, MANAGER, MEMBER.


The `member_key` block supports:

* `id` - The ID of the entity. For Google-managed entities, the id is the email address of an existing
group or user. For external-identity-mapped entities, the id is a string conforming
to the Identity Source's requirements.

* `namespace` - The namespace in which the entity exists.
If not populated, the EntityKey represents a Google-managed entity
such as a Google user or a Google Group.
If populated, the EntityKey represents an external-identity-mapped group.

The `preferred_member_key` block supports:

* `id` - The ID of the entity. For Google-managed entities, the id is the email address of an existing
group or user. For external-identity-mapped entities, the id is a string conforming
to the Identity Source's requirements.

* `namespace` - The namespace in which the entity exists.
If not populated, the EntityKey represents a Google-managed entity
such as a Google user or a Google Group.
If populated, the EntityKey represents an external-identity-mapped group.
Loading

0 comments on commit 0eddadb

Please sign in to comment.