Skip to content

Commit

Permalink
DXCDT-360: Move connection resource to dedicated pkg (#469)
Browse files Browse the repository at this point in the history
  • Loading branch information
sergiught authored Feb 8, 2023
1 parent 4a29da9 commit f614775
Show file tree
Hide file tree
Showing 15 changed files with 1,040 additions and 985 deletions.

Large diffs are not rendered by default.

607 changes: 607 additions & 0 deletions internal/auth0/connection/flatten.go

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package provider
package connection

import (
"testing"
Expand Down
134 changes: 134 additions & 0 deletions internal/auth0/connection/resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package connection

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"
)

// NewResource will return a new auth0_connection resource.
func NewResource() *schema.Resource {
return &schema.Resource{
CreateContext: createConnection,
ReadContext: readConnection,
UpdateContext: updateConnection,
DeleteContext: deleteConnection,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
Description: "With Auth0, you can define sources of users, otherwise known as connections, " +
"which may include identity providers (such as Google or LinkedIn), databases, or " +
"passwordless authentication methods. This resource allows you to configure " +
"and manage connections to be used with your clients and users.",
Schema: resourceSchema,
SchemaVersion: 2,
StateUpgraders: []schema.StateUpgrader{
{
Type: connectionSchemaV0().CoreConfigSchema().ImpliedType(),
Upgrade: connectionSchemaUpgradeV0,
Version: 0,
},
{
Type: connectionSchemaV1().CoreConfigSchema().ImpliedType(),
Upgrade: connectionSchemaUpgradeV1,
Version: 1,
},
},
}
}

func createConnection(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
api := m.(*management.Management)

connection, diagnostics := expandConnection(d)
if diagnostics.HasError() {
return diagnostics
}

if err := api.Connection.Create(connection); err != nil {
diagnostics = append(diagnostics, diag.FromErr(err)...)
return diagnostics
}

d.SetId(connection.GetID())

diagnostics = append(diagnostics, readConnection(ctx, d, m)...)
return diagnostics
}

func readConnection(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
api := m.(*management.Management)

connection, err := api.Connection.Read(d.Id())
if err != nil {
if mErr, ok := err.(management.Error); ok && mErr.Status() == http.StatusNotFound {
d.SetId("")
return nil
}
return diag.FromErr(err)
}

connectionOptions, diags := flattenConnectionOptions(d, connection.Options)
if diags.HasError() {
return diags
}

result := multierror.Append(
d.Set("name", connection.GetName()),
d.Set("display_name", connection.GetDisplayName()),
d.Set("is_domain_connection", connection.GetIsDomainConnection()),
d.Set("strategy", connection.GetStrategy()),
d.Set("options", connectionOptions),
d.Set("realms", connection.GetRealms()),
d.Set("metadata", connection.GetMetadata()),
)

switch connection.GetStrategy() {
case management.ConnectionStrategyGoogleApps,
management.ConnectionStrategyOIDC,
management.ConnectionStrategyAD,
management.ConnectionStrategyAzureAD,
management.ConnectionStrategySAML,
management.ConnectionStrategyADFS:
result = multierror.Append(result, d.Set("show_as_button", connection.GetShowAsButton()))
}

diags = append(diags, diag.FromErr(result.ErrorOrNil())...)
return diags
}

func updateConnection(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
api := m.(*management.Management)

connection, diagnostics := expandConnection(d)
if diagnostics.HasError() {
return diagnostics
}

if err := api.Connection.Update(d.Id(), connection); err != nil {
diagnostics = append(diagnostics, diag.FromErr(err)...)
return diagnostics
}

diagnostics = append(diagnostics, readConnection(ctx, d, m)...)
return diagnostics
}

func deleteConnection(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
api := m.(*management.Management)

if err := api.Connection.Delete(d.Id()); err != nil {
if mErr, ok := err.(management.Error); ok && mErr.Status() == http.StatusNotFound {
d.SetId("")
return nil
}
return diag.FromErr(err)
}

d.SetId("")
return nil
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
package provider
package connection

import (
"context"
"fmt"
"net/http"
"strings"

"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/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

"github.com/auth0/terraform-provider-auth0/internal/mutex"
)

var (
errEmptyConnectionClientID = fmt.Errorf("ID cannot be empty")
errInvalidConnectionClientIDFormat = fmt.Errorf("ID must be formated as <connectionID>:<clientID>")
)

func newConnectionClient() *schema.Resource {
// NewClientResource will return a new auth0_connection_client resource.
func NewClientResource() *schema.Resource {
return &schema.Resource{
Schema: map[string]*schema.Schema{
"connection_id": {
Expand Down Expand Up @@ -54,42 +56,13 @@ func newConnectionClient() *schema.Resource {
}
}

func importConnectionClient(
_ context.Context,
data *schema.ResourceData,
_ interface{},
) ([]*schema.ResourceData, error) {
rawID := data.Id()
if rawID == "" {
return nil, errEmptyConnectionClientID
}

if !strings.Contains(rawID, ":") {
return nil, errInvalidConnectionClientIDFormat
}

idPair := strings.Split(rawID, ":")
if len(idPair) != 2 {
return nil, errInvalidConnectionClientIDFormat
}

result := multierror.Append(
data.Set("connection_id", idPair[0]),
data.Set("client_id", idPair[1]),
)

data.SetId(resource.UniqueId())

return []*schema.ResourceData{data}, result.ErrorOrNil()
}

func createConnectionClient(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
api := meta.(*management.Management)

connectionID := data.Get("connection_id").(string)

globalMutex.Lock(connectionID)
defer globalMutex.Unlock(connectionID)
mutex.Global.Lock(connectionID)
defer mutex.Global.Unlock(connectionID)

connection, err := api.Connection.Read(connectionID)
if err != nil {
Expand Down Expand Up @@ -150,8 +123,8 @@ func deleteConnectionClient(_ context.Context, data *schema.ResourceData, meta i

connectionID := data.Get("connection_id").(string)

globalMutex.Lock(connectionID)
defer globalMutex.Unlock(connectionID)
mutex.Global.Lock(connectionID)
defer mutex.Global.Unlock(connectionID)

connection, err := api.Connection.Read(connectionID)
if err != nil {
Expand Down
39 changes: 39 additions & 0 deletions internal/auth0/connection/resource_client_import.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package connection

import (
"context"
"strings"

"github.com/hashicorp/go-multierror"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func importConnectionClient(
_ context.Context,
data *schema.ResourceData,
_ interface{},
) ([]*schema.ResourceData, error) {
rawID := data.Id()
if rawID == "" {
return nil, errEmptyConnectionClientID
}

if !strings.Contains(rawID, ":") {
return nil, errInvalidConnectionClientIDFormat
}

idPair := strings.Split(rawID, ":")
if len(idPair) != 2 {
return nil, errInvalidConnectionClientIDFormat
}

result := multierror.Append(
data.Set("connection_id", idPair[0]),
data.Set("client_id", idPair[1]),
)

data.SetId(resource.UniqueId())

return []*schema.ResourceData{data}, result.ErrorOrNil()
}
61 changes: 61 additions & 0 deletions internal/auth0/connection/resource_client_import_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package connection

import (
"context"
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/stretchr/testify/assert"
)

func TestImportConnectionClient(t *testing.T) {
var testCases = []struct {
testName string
givenID string
expectedConnectionID string
expectedClientID string
expectedError error
}{
{
testName: "it correctly parses the resource ID",
givenID: "conn_5678:client_1234",
expectedConnectionID: "conn_5678",
expectedClientID: "client_1234",
},
{
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: "client_1234conn_5678",
expectedError: fmt.Errorf("ID must be formated as <connectionID>:<clientID>"),
},
{
testName: "it fails when the given ID has too many separators",
givenID: "client_1234:conn_5678:",
expectedError: fmt.Errorf("ID must be formated as <connectionID>:<clientID>"),
},
}

for _, testCase := range testCases {
t.Run(testCase.testName, func(t *testing.T) {
data := schema.TestResourceDataRaw(t, NewClientResource().Schema, nil)
data.SetId(testCase.givenID)

actualData, err := importConnectionClient(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("connection_id").(string), testCase.expectedConnectionID)
assert.Equal(t, actualData[0].Get("client_id").(string), testCase.expectedClientID)
assert.NotEqual(t, actualData[0].Id(), testCase.givenID)
})
}
}
Loading

0 comments on commit f614775

Please sign in to comment.