Skip to content
This repository has been archived by the owner on Jun 27, 2021. It is now read-only.

New Resource: gsuite_user_alias #184

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
17 changes: 17 additions & 0 deletions examples/alias/basic_example.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
resource "gsuite_user" "test" {
name = {
family_name = "TestAcc_replaceWithUuid"
given_name = "Test"
}

primary_email = "[email protected]"

lifecycle {
ignore = [aliases]
}
}

resource "gsuite_user_alias" "test" {
user_id = gsuite_user.test.primary_email
alias = "[email protected]"
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.15

require (
cloud.google.com/go v0.79.0
github.com/cenkalti/backoff/v4 v4.1.1
github.com/golang/protobuf v1.5.2 // indirect
github.com/hashicorp/terraform-plugin-sdk v1.13.0
github.com/pkg/errors v0.9.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1U
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ=
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
Expand Down
1 change: 1 addition & 0 deletions gsuite/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ func Provider() *schema.Provider {
"gsuite_group_members": resourceGroupMembers(),
"gsuite_group_settings": resourceGroupSettings(),
"gsuite_user": resourceUser(),
"gsuite_user_alias": resourceUserAlias(),
"gsuite_user_attributes": resourceUserAttributes(),
"gsuite_user_schema": resourceUserSchema(),
},
Expand Down
153 changes: 153 additions & 0 deletions gsuite/resource_user_alias.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package gsuite

import (
"fmt"
"log"
"reflect"
"strings"
"time"

"github.com/cenkalti/backoff/v4"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
admin "google.golang.org/api/admin/directory/v1"
)

func resourceUserAlias() *schema.Resource {
return &schema.Resource{
Create: resourceUserAliasCreate,
Read: resourceUserAliasRead,
Update: nil,
Delete: resourceUserAliasDelete,
Importer: &schema.ResourceImporter{
State: resourceUserAliasImport,
},
Schema: map[string]*schema.Schema{
"user_id": {
Type: schema.TypeString,
Description: "ID (userKey) of the user the alias should be applied to.",
Required: true,
ForceNew: true,
},
"alias": {
Type: schema.TypeString,
Description: "Email alias which should be applied to the user.",
Required: true,
ForceNew: true,
ValidateFunc: validateEmail,
},
},
}
}

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

userId := d.Get("user_id").(string)
setAlias := d.Get("alias").(string)

alias := &admin.Alias{
Alias: setAlias,
}
resp, err := config.directory.Users.Aliases.Insert(userId, alias).Do()
if err != nil {
return fmt.Errorf("[ERROR] failed to add alias for user (%s): %v", userId, err)
}

bOff := backoff.NewExponentialBackOff()
bOff.MaxElapsedTime = time.Duration(config.TimeoutMinutes) * time.Minute
bOff.InitialInterval = time.Second

err = backoff.Retry(func() error {
resp, err := config.directory.Users.Aliases.List(userId).Do()
if err != nil {
return backoff.Permanent(fmt.Errorf("[ERROR] could not retrieve aliases for user (%s): %v", userId, err))
}

_, ok := doesAliasExist(resp, setAlias)
if ok {
return nil
}
return fmt.Errorf(fmt.Sprintf("[WARN] no matching alias (%s) found for user (%s).", setAlias, userId))

}, bOff)

d.SetId(fmt.Sprintf("%s/%s", resp.PrimaryEmail, resp.Alias))
return resourceUserAliasRead(d, meta)
}

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

userId := d.Get("user_id").(string)
expectedAlias := d.Get("alias").(string)

resp, err := config.directory.Users.Aliases.List(userId).Do()
if err != nil {
return fmt.Errorf("[ERROR] could not retrieve aliases for user (%s): %v", userId, err)
}

alias, ok := doesAliasExist(resp, expectedAlias)
if !ok {
log.Println(fmt.Sprintf("[WARN] no matching alias (%s) found for user (%s).", expectedAlias, userId))
d.SetId("")
return nil
}
d.SetId(fmt.Sprintf("%s/%s", userId, alias))
d.Set("user_id", userId)
d.Set("alias", alias)
return nil
}

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

userId := d.Get("user_id").(string)
alias := d.Get("alias").(string)

err := config.directory.Users.Aliases.Delete(userId, alias).Do()
if err != nil {
return fmt.Errorf("[ERROR] unable to remove alias (%s) from user (%s): %v", alias, userId, err)
}

d.SetId("")
return nil
}

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

userId := strings.Split(d.Id(), "/")[0]
expectedAlias := strings.Split(d.Id(), "/")[1]

resp, err := config.directory.Users.Aliases.List(userId).Do()
if err != nil {
return nil, fmt.Errorf("[ERROR] could not retrieve aliases for user (%s): %v", userId, err)
}

alias, ok := doesAliasExist(resp, expectedAlias)
if !ok {
return nil, fmt.Errorf("[ERROR] no matching alias (%s) found for user (%s).", expectedAlias, userId)
}
d.SetId(fmt.Sprintf("%s/%s", userId, alias))
d.Set("user_id", userId)
d.Set("alias", alias)

return []*schema.ResourceData{d}, nil
}

func doesAliasExist(aliasesResp *admin.Aliases, expectedAlias string) (string, bool) {
for _, aliasInt := range aliasesResp.Aliases {
alias, ok := aliasInt.(map[string]interface{})
if ok {
value := alias["alias"].(string)
if expectedAlias == alias["alias"].(string) {
return value, true
}
}
if !ok {
log.Println(fmt.Sprintf("[ERROR] alias format in response did not match sdk struct, this indicates a probelm with provider or sdk handling: %v", reflect.TypeOf(aliasInt)))
return "", false
}
}
return "", false
}
39 changes: 39 additions & 0 deletions website/docs/r/user_alias.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
layout: "gsuite"
page_title: "G Suite: gsuite_alias"
sidebar_current: "docs-gsuite-resource-user-alias"
description: |-
Managing a G Suite User Alias.
---

# gsuite_user_alias

Provides a resource for creating and managing an email alias for a GSuite user account.

## Example Usage

```hcl
resource "gsuite_user_alias" "test" {
user_id = "[email protected]"
alias = "[email protected]"
}
```

## Argument Reference

* `user_id` (Required) Primary email (userKey) of the user who will have the alias applied to them.
* `alias` (Required) Email alias to be applied to the user.


## Attribute Reference

N/A apart from the included arguments

## Import

An alias can be imported by passing the ID format of "{user_id}/{alias}"

For example:
```
terraform import gsuite_user_alias.test "[email protected]/[email protected]"
```