Skip to content

Commit

Permalink
DXCDT-439: Add new auth0_organization_member_role resource (#622)
Browse files Browse the repository at this point in the history
  • Loading branch information
sergiught authored Jun 9, 2023
1 parent 4b35bee commit c04911d
Show file tree
Hide file tree
Showing 9 changed files with 5,831 additions and 0 deletions.
16 changes: 16 additions & 0 deletions MIGRATION_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,27 @@ resource "auth0_organization_member" "my_org_member" {
}
}
# Use the auth0_organization_member_roles to manage a 1:many
# relationship between the organization member and its roles.
resource "auth0_organization_member_roles" "my_org_member_roles" {
organization_id = auth0_organization.my_org.id
user_id = auth0_user.user.id
roles = [ auth0_role.reader.id, auth0_role.writer.id ]
}
# Use the auth0_organization_member_role to manage a 1:1
# relationship between the organization member and its roles.
resource "auth0_organization_member_role" "role1" {
organization_id = auth0_organization.my_org.id
user_id = auth0_user.user.id
role_id = auth0_role.reader.id
}
resource "auth0_organization_member_role" "role2" {
organization_id = auth0_organization.my_org.id
user_id = auth0_user.user.id
role_id = auth0_role.writer.id
}
```

</td>
Expand Down
76 changes: 76 additions & 0 deletions docs/resources/organization_member_role.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
---
page_title: "Resource: auth0_organization_member_role"
description: |-
This resource is used to manage the roles assigned to an organization member.
---

# Resource: auth0_organization_member_role

This resource is used to manage the roles assigned to an organization member.

## Example Usage

```terraform
resource "auth0_role" "reader" {
name = "Reader"
}
resource "auth0_role" "writer" {
name = "Writer"
}
resource "auth0_user" "user" {
connection_name = "Username-Password-Authentication"
email = "[email protected]"
password = "MyPass123$"
}
resource "auth0_organization" "my_org" {
name = "some-org"
display_name = "Some Org"
}
resource "auth0_organization_member" "my_org_member" {
organization_id = auth0_organization.my_org.id
user_id = auth0_user.user.id
}
resource "auth0_organization_member_role" "role1" {
organization_id = auth0_organization.my_org.id
user_id = auth0_user.user.id
role_id = auth0_role.reader.id
}
resource "auth0_organization_member_role" "role2" {
organization_id = auth0_organization.my_org.id
user_id = auth0_user.user.id
role_id = auth0_role.writer.id
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `organization_id` (String) The ID of the organization.
- `role_id` (String) The role ID to assign to the organization member.
- `user_id` (String) The user ID of the organization member.

### Read-Only

- `id` (String) The ID of this resource.
- `role_description` (String) Description of the role.
- `role_name` (String) Name of the role.

## Import

Import is supported using the following syntax:

```shell
# This resource can be imported by specifying the
# organization ID, user ID and role ID separated by "::".
#
# Example:
terraform import auth0_organization_member_role.my_org_member_role "org_XXXXX::auth0|XXXXX::role_XXXX"
```
5 changes: 5 additions & 0 deletions examples/resources/auth0_organization_member_role/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# This resource can be imported by specifying the
# organization ID, user ID and role ID separated by "::".
#
# Example:
terraform import auth0_organization_member_role.my_org_member_role "org_XXXXX::auth0|XXXXX::role_XXXX"
35 changes: 35 additions & 0 deletions examples/resources/auth0_organization_member_role/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
resource "auth0_role" "reader" {
name = "Reader"
}

resource "auth0_role" "writer" {
name = "Writer"
}

resource "auth0_user" "user" {
connection_name = "Username-Password-Authentication"
email = "[email protected]"
password = "MyPass123$"
}

resource "auth0_organization" "my_org" {
name = "some-org"
display_name = "Some Org"
}

resource "auth0_organization_member" "my_org_member" {
organization_id = auth0_organization.my_org.id
user_id = auth0_user.user.id
}

resource "auth0_organization_member_role" "role1" {
organization_id = auth0_organization.my_org.id
user_id = auth0_user.user.id
role_id = auth0_role.reader.id
}

resource "auth0_organization_member_role" "role2" {
organization_id = auth0_organization.my_org.id
user_id = auth0_user.user.id
role_id = auth0_role.writer.id
}
22 changes: 22 additions & 0 deletions internal/acctest/resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package acctest

import (
"fmt"

"github.com/hashicorp/terraform-plugin-testing/terraform"
)

// ExtractResourceAttributeFromState extracts the value of a resource's attribute into the target.
func ExtractResourceAttributeFromState(state *terraform.State, name, key string) (string, error) {
tfResource, ok := state.RootModule().Resources[name]
if !ok {
return "", fmt.Errorf("extract resource attribute: failed to find resource with name: %q", name)
}

attribute, ok := tfResource.Primary.Attributes[key]
if !ok {
return "", fmt.Errorf("extract resource attribute: failed to find attribute with name: %q", key)
}

return attribute, nil
}
134 changes: 134 additions & 0 deletions internal/auth0/organization/resource_member_role.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package organization

import (
"context"
"net/http"

"github.com/auth0/go-auth0/management"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

"github.com/auth0/terraform-provider-auth0/internal/config"
internalSchema "github.com/auth0/terraform-provider-auth0/internal/schema"
)

// NewMemberRoleResource will return a new auth0_organization_member_role (1:1) resource.
func NewMemberRoleResource() *schema.Resource {
return &schema.Resource{
Description: "This resource is used to manage the roles assigned to an organization member.",
CreateContext: createOrganizationMemberRole,
ReadContext: readOrganizationMemberRole,
DeleteContext: deleteOrganizationMemberRole,
Importer: &schema.ResourceImporter{
StateContext: internalSchema.ImportResourceGroupID(internalSchema.SeparatorDoubleColon, "organization_id", "user_id", "role_id"),
},
Schema: map[string]*schema.Schema{
"organization_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "The ID of the organization.",
},
"user_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "The user ID of the organization member.",
},
"role_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "The role ID to assign to the organization member.",
},
"role_name": {
Type: schema.TypeString,
Computed: true,
Description: "Name of the role.",
},
"role_description": {
Type: schema.TypeString,
Computed: true,
Description: "Description of the role.",
},
},
}
}

func createOrganizationMemberRole(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
api := meta.(*config.Config).GetAPI()
mutex := meta.(*config.Config).GetMutex()

organizationID := data.Get("organization_id").(string)
userID := data.Get("user_id").(string)
roleID := data.Get("role_id").(string)

mutex.Lock(organizationID)
defer mutex.Unlock(organizationID)

if err := api.Organization.AssignMemberRoles(organizationID, userID, []string{roleID}); err != nil {
if err, ok := err.(management.Error); ok && err.Status() == http.StatusNotFound {
return nil
}

return diag.FromErr(err)
}

data.SetId(organizationID + internalSchema.SeparatorDoubleColon + userID + internalSchema.SeparatorDoubleColon + roleID)

return readOrganizationMemberRole(ctx, data, meta)
}

func readOrganizationMemberRole(_ context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
api := meta.(*config.Config).GetAPI()

organizationID := data.Get("organization_id").(string)
userID := data.Get("user_id").(string)

memberRoles, err := api.Organization.MemberRoles(organizationID, userID)
if err != nil {
if err, ok := err.(management.Error); ok && err.Status() == http.StatusNotFound {
data.SetId("")
return nil
}

return diag.FromErr(err)
}

roleID := data.Get("role_id").(string)
for _, role := range memberRoles.Roles {
if role.GetID() == roleID {
result := multierror.Append(
data.Set("role_name", role.GetName()),
data.Set("role_description", role.GetDescription()),
)
return diag.FromErr(result.ErrorOrNil())
}
}

data.SetId("")
return nil
}

func deleteOrganizationMemberRole(_ context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
api := meta.(*config.Config).GetAPI()
mutex := meta.(*config.Config).GetMutex()

organizationID := data.Get("organization_id").(string)
userID := data.Get("user_id").(string)
roleID := data.Get("role_id").(string)

mutex.Lock(organizationID)
defer mutex.Unlock(organizationID)

if err := api.Organization.DeleteMemberRoles(organizationID, userID, []string{roleID}); err != nil {
if err, ok := err.(management.Error); ok && err.Status() == http.StatusNotFound {
return nil
}

return diag.FromErr(err)
}

return nil
}
Loading

0 comments on commit c04911d

Please sign in to comment.