diff --git a/docs/resources/organization_member.md b/docs/resources/organization_member.md index 8730afcb9..dc17fd95d 100644 --- a/docs/resources/organization_member.md +++ b/docs/resources/organization_member.md @@ -59,11 +59,9 @@ resource "auth0_organization_member" "my_org_member" { Import is supported using the following syntax: ```shell -# As this is not a resource identifiable by an ID within the Auth0 Management API, -# organization members can be imported using a random string. -# -# We recommend [Version 4 UUID](https://www.uuidgenerator.net/version4) +# This resource can be imported by specifying the +# organization ID and user ID separated by ":". # # Example: -terraform import auth0_organization_member.my_org_member 11f4a21b-011a-312d-9217-e291caca36c5 +terraform import auth0_organization_member.my_org_member "org_XXXXX:auth0|XXXXX" ``` diff --git a/examples/resources/auth0_organization_member/import.sh b/examples/resources/auth0_organization_member/import.sh index 11eb55f5d..1e33e6b18 100644 --- a/examples/resources/auth0_organization_member/import.sh +++ b/examples/resources/auth0_organization_member/import.sh @@ -1,7 +1,5 @@ -# As this is not a resource identifiable by an ID within the Auth0 Management API, -# organization members can be imported using a random string. -# -# We recommend [Version 4 UUID](https://www.uuidgenerator.net/version4) +# This resource can be imported by specifying the +# organization ID and user ID separated by ":". # # Example: -terraform import auth0_organization_member.my_org_member 11f4a21b-011a-312d-9217-e291caca36c5 +terraform import auth0_organization_member.my_org_member "org_XXXXX:auth0|XXXXX" diff --git a/internal/provider/resource_auth0_organization_member.go b/internal/provider/resource_auth0_organization_member.go index 342efff1e..632b8262e 100644 --- a/internal/provider/resource_auth0_organization_member.go +++ b/internal/provider/resource_auth0_organization_member.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/http" + "strings" "github.com/auth0/go-auth0/management" "github.com/hashicorp/go-multierror" @@ -12,6 +13,11 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) +var ( + errEmptyOrganizationMemberID = fmt.Errorf("ID cannot be empty") + errInvalidOrganizationMemberIDFormat = fmt.Errorf("ID must be formated as :") +) + func newOrganizationMember() *schema.Resource { return &schema.Resource{ Description: "This resource is used to manage the assignment of members and their roles within an organization.", @@ -20,7 +26,7 @@ func newOrganizationMember() *schema.Resource { UpdateContext: updateOrganizationMember, DeleteContext: deleteOrganizationMember, Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, + StateContext: importOrganizationMember, }, Schema: map[string]*schema.Schema{ "organization_id": { @@ -43,6 +49,35 @@ func newOrganizationMember() *schema.Resource { } } +func importOrganizationMember( + _ context.Context, + data *schema.ResourceData, + _ interface{}, +) ([]*schema.ResourceData, error) { + rawID := data.Id() + if rawID == "" { + return nil, errEmptyOrganizationMemberID + } + + if !strings.Contains(rawID, ":") { + return nil, errInvalidOrganizationMemberIDFormat + } + + idPair := strings.Split(rawID, ":") + if len(idPair) != 2 { + return nil, errInvalidOrganizationMemberIDFormat + } + + result := multierror.Append( + data.Set("organization_id", idPair[0]), + data.Set("user_id", idPair[1]), + ) + + data.SetId(resource.UniqueId()) + + return []*schema.ResourceData{data}, result.ErrorOrNil() +} + func createOrganizationMember(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { userID := d.Get("user_id").(string) orgID := d.Get("organization_id").(string) @@ -106,7 +141,7 @@ func removeMemberRoles(orgID string, userID string, roles []interface{}, m inter func addMemberRoles(orgID string, userID string, roles []interface{}, m interface{}) error { api := m.(*management.Management) - rolesToAssign := []string{} + var rolesToAssign []string for _, r := range roles { rolesToAssign = append(rolesToAssign, r.(string)) } @@ -133,7 +168,7 @@ func readOrganizationMember(ctx context.Context, d *schema.ResourceData, m inter return diag.FromErr(err) } - rolesToSet := []interface{}{} + var rolesToSet []interface{} for _, role := range roles.Roles { rolesToSet = append(rolesToSet, role.ID) } diff --git a/internal/provider/resource_auth0_organization_member_test.go b/internal/provider/resource_auth0_organization_member_test.go index 64fdec260..f8e889fe5 100644 --- a/internal/provider/resource_auth0_organization_member_test.go +++ b/internal/provider/resource_auth0_organization_member_test.go @@ -1,10 +1,14 @@ package provider import ( + "context" + "fmt" "strings" "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/stretchr/testify/assert" "github.com/auth0/terraform-provider-auth0/internal/template" ) @@ -115,8 +119,59 @@ resource auth0_user user { password = "MyPass123$" } -resource auth0_organization some_org{ +resource auth0_organization some_org { name = "some-org-{{.testName}}" display_name = "{{.testName}}" } ` + +func TestImportOrganizationMember(t *testing.T) { + var testCases = []struct { + testName string + givenID string + expectedOrganizationID string + expectedUserID string + expectedError error + }{ + { + testName: "it correctly parses the resource ID", + givenID: "org_1234:auth0|62d82", + expectedOrganizationID: "org_1234", + expectedUserID: "auth0|62d82", + }, + { + testName: "it fails when the given ID is empty", + givenID: "", + expectedError: fmt.Errorf("ID cannot be empty"), + }, + { + testName: "it fails when the given ID does not have \":\" as a separator", + givenID: "org_1234auth0|62d82", + expectedError: fmt.Errorf("ID must be formated as :"), + }, + { + testName: "it fails when the given ID has too many separators", + givenID: "org_1234:auth0|62d82:", + expectedError: fmt.Errorf("ID must be formated as :"), + }, + } + + for _, testCase := range testCases { + t.Run(testCase.testName, func(t *testing.T) { + data := schema.TestResourceDataRaw(t, newOrganizationMember().Schema, nil) + data.SetId(testCase.givenID) + + actualData, err := importOrganizationMember(context.Background(), data, nil) + + if testCase.expectedError != nil { + assert.EqualError(t, err, testCase.expectedError.Error()) + assert.Nil(t, actualData) + return + } + + assert.Equal(t, actualData[0].Get("organization_id").(string), testCase.expectedOrganizationID) + assert.Equal(t, actualData[0].Get("user_id").(string), testCase.expectedUserID) + assert.NotEqual(t, actualData[0].Id(), testCase.givenID) + }) + } +}