Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PingOne Authorize Service for Terraform Export #6

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions internal/connector/common/resources_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"net/http"

"github.com/patrickcping/pingone-go-sdk-v2/authorize"
"github.com/patrickcping/pingone-go-sdk-v2/management"
"github.com/patrickcping/pingone-go-sdk-v2/mfa"
"github.com/patrickcping/pingone-go-sdk-v2/risk"
Expand Down Expand Up @@ -32,6 +33,36 @@ func HandleClientResponse(response *http.Response, err error, apiFunctionName st
return nil
}

// Executes the function apiExecuteFunc for the AuthorizeAPIClient
// Handles err and response if Client call failed
// Returns embedded data if not nil
// Treats nil embedded data as an error
func GetAuthorizeEmbedded(apiExecuteFunc func() (*authorize.EntityArray, *http.Response, error), apiFunctionName string, resourceType string) (*authorize.EntityArrayEmbedded, error) {
l := logger.Get()

entityArray, response, err := apiExecuteFunc()

err = HandleClientResponse(response, err, apiFunctionName, resourceType)
if err != nil {
return nil, err
}

if entityArray == nil {
l.Error().Msgf("Returned %s() entityArray is nil.", apiFunctionName)
l.Error().Msgf("%s Response Code: %s\nResponse Body: %s", apiFunctionName, response.Status, response.Body)
return nil, fmt.Errorf("failed to fetch %s resources via %s()", resourceType, apiFunctionName)
}

embedded, embeddedOk := entityArray.GetEmbeddedOk()
if !embeddedOk {
l.Error().Msgf("Returned %s() embedded data is nil.", apiFunctionName)
l.Error().Msgf("%s Response Code: %s\nResponse Body: %s", apiFunctionName, response.Status, response.Body)
return nil, fmt.Errorf("failed to fetch %s resources via %s()", resourceType, apiFunctionName)
}

return embedded, nil
}

// Executes the function apiExecuteFunc for the ManagementAPIClient
// Handles err and response if Client call failed
// Returns embedded data if not nil
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package authorize

import (
"context"

pingoneGoClient "github.com/patrickcping/pingone-go-sdk-v2/pingone"
"github.com/pingidentity/pingctl/internal/connector"
"github.com/pingidentity/pingctl/internal/connector/common"
"github.com/pingidentity/pingctl/internal/connector/pingone/authorize/resources"
"github.com/pingidentity/pingctl/internal/logger"
)

const (
serviceName = "pingone-authorize"
)

// Verify that the connector satisfies the expected interfaces
var (
_ connector.Exportable = &PingoneAuthorizeConnector{}
_ connector.Authenticatable = &PingoneAuthorizeConnector{}
)

type PingoneAuthorizeConnector struct {
clientInfo connector.PingOneClientInfo
}

// Utility method for creating a PingoneAuthorizeConnector
func AuthorizeConnector(ctx context.Context, apiClient *pingoneGoClient.Client, apiClientId *string, exportEnvironmentID string) *PingoneAuthorizeConnector {
return &PingoneAuthorizeConnector{
clientInfo: connector.PingOneClientInfo{
Context: ctx,
ApiClient: apiClient,
ApiClientId: apiClientId,
ExportEnvironmentID: exportEnvironmentID,
},
}
}

func (c *PingoneAuthorizeConnector) Export(format, outputDir string, overwriteExport bool) error {
l := logger.Get()

l.Debug().Msgf("Exporting all PingOne Authorize Resources...")

exportableResources := []connector.ExportableResource{
resources.AuthorizeAPIService(&c.clientInfo),
resources.AuthorizeAPIServiceDeployment(&c.clientInfo),
resources.AuthorizeAPIServiceOperation(&c.clientInfo),
resources.AuthorizeApplicationRole(&c.clientInfo),
resources.AuthorizeApplicationRolePermission(&c.clientInfo),
resources.AuthorizeDecisionEndpoint(&c.clientInfo),
resources.AuthorizePolicyManagementPolicy(&c.clientInfo),
resources.AuthorizePolicyManagementRule(&c.clientInfo),
resources.AuthorizePolicyManagementStatement(&c.clientInfo),
resources.AuthorizeTrustFrameworkAttribute(&c.clientInfo),
resources.AuthorizeTrustFrameworkCondition(&c.clientInfo),
resources.AuthorizeTrustFrameworkProcessor(&c.clientInfo),
resources.AuthorizeTrustFrameworkService(&c.clientInfo),
}

return common.WriteFiles(exportableResources, format, outputDir, overwriteExport)
}

func (c *PingoneAuthorizeConnector) ConnectorServiceName() string {
return serviceName
}

func (c *PingoneAuthorizeConnector) Login() error {
return nil
}

func (c *PingoneAuthorizeConnector) Logout() error {
return nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package authorize_test

import (
"testing"

"github.com/pingidentity/pingctl/internal/connector"
"github.com/pingidentity/pingctl/internal/connector/pingone/authorize/resources"
"github.com/pingidentity/pingctl/internal/testing/testutils"
"github.com/pingidentity/pingctl/internal/testing/testutils_terraform"
)

func TestAuthorizeTerraformPlan(t *testing.T) {
PingOneClientInfo := testutils.GetPingOneClientInfo(t)

testutils_terraform.InitPingOneTerraform(t)

testCases := []struct {
name string
resource connector.ExportableResource
ignoredErrors []string
}{
{
name: "AuthorizeAPIService",
resource: resources.AuthorizeAPIService(PingOneClientInfo),
ignoredErrors: nil,
},
{
name: "AuthorizeAPIServiceDeployment",
resource: resources.AuthorizeAPIServiceDeployment(PingOneClientInfo),
ignoredErrors: nil,
},
{
name: "AuthorizeAPIServiceOperation",
resource: resources.AuthorizeAPIServiceOperation(PingOneClientInfo),
ignoredErrors: nil,
},
{
name: "AuthorizeApplicationRole",
resource: resources.AuthorizeApplicationRole(PingOneClientInfo),
ignoredErrors: nil,
},
{
name: "AuthorizeApplicationRolePermission",
resource: resources.AuthorizeApplicationRolePermission(PingOneClientInfo),
ignoredErrors: nil,
},
{
name: "AuthorizeDecisionEndpoint",
resource: resources.AuthorizeDecisionEndpoint(PingOneClientInfo),
ignoredErrors: nil,
},
{
name: "AuthorizePolicyManagementPolicy",
resource: resources.AuthorizePolicyManagementPolicy(PingOneClientInfo),
ignoredErrors: nil,
},
{
name: "AuthorizePolicyManagementRule",
resource: resources.AuthorizePolicyManagementRule(PingOneClientInfo),
ignoredErrors: nil,
},
{
name: "AuthorizePolicyManagementStatement",
resource: resources.AuthorizePolicyManagementStatement(PingOneClientInfo),
ignoredErrors: nil,
},
{
name: "AuthorizeTrustFrameworkAttribute",
resource: resources.AuthorizeTrustFrameworkAttribute(PingOneClientInfo),
ignoredErrors: nil,
},
{
name: "AuthorizeTrustFrameworkCondition",
resource: resources.AuthorizeTrustFrameworkCondition(PingOneClientInfo),
ignoredErrors: nil,
},
{
name: "AuthorizeTrustFrameworkProcessor",
resource: resources.AuthorizeTrustFrameworkProcessor(PingOneClientInfo),
ignoredErrors: nil,
},
{
name: "AuthorizeTrustFrameworkService",
resource: resources.AuthorizeTrustFrameworkService(PingOneClientInfo),
ignoredErrors: nil,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
testutils_terraform.ValidateTerraformPlan(t, tc.resource, tc.ignoredErrors)
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package resources

import (
"fmt"

"github.com/pingidentity/pingctl/internal/connector"
"github.com/pingidentity/pingctl/internal/connector/common"
"github.com/pingidentity/pingctl/internal/logger"
)

// Verify that the resource satisfies the exportable resource interface
var (
_ connector.ExportableResource = &PingoneAuthorizeAPIServiceResource{}
)

type PingoneAuthorizeAPIServiceResource struct {
clientInfo *connector.PingOneClientInfo
}

// Utility method for creating a PingoneAuthorizeAPIServiceResource
func AuthorizeAPIService(clientInfo *connector.PingOneClientInfo) *PingoneAuthorizeAPIServiceResource {
return &PingoneAuthorizeAPIServiceResource{
clientInfo: clientInfo,
}
}

func (r *PingoneAuthorizeAPIServiceResource) ExportAll() (*[]connector.ImportBlock, error) {
l := logger.Get()

l.Debug().Msgf("Fetching all %s resources...", r.ResourceType())

apiExecuteFunc := r.clientInfo.ApiClient.AuthorizeAPIClient.APIServersApi.ReadAllAPIServers(r.clientInfo.Context, r.clientInfo.ExportEnvironmentID).Execute
apiFunctionName := "ReadAllAPIServers"

embedded, err := common.GetAuthorizeEmbedded(apiExecuteFunc, apiFunctionName, r.ResourceType())
if err != nil {
return nil, err
}

importBlocks := []connector.ImportBlock{}

l.Debug().Msgf("Generating Import Blocks for all %s resources...", r.ResourceType())

for _, apiServer := range embedded.GetApiServers() {
apiServerName, apiServerNameOk := apiServer.GetNameOk()
apiServerId, apiServerIdOk := apiServer.GetIdOk()

if apiServerNameOk && apiServerIdOk {
commentData := map[string]string{
"Resource Type": r.ResourceType(),
"Authorize API Service Name": *apiServerName,
"Export Environment ID": r.clientInfo.ExportEnvironmentID,
"Authorize API Service ID": *apiServerId,
}

importBlocks = append(importBlocks, connector.ImportBlock{
ResourceType: r.ResourceType(),
ResourceName: *apiServerName,
ResourceID: fmt.Sprintf("%s/%s", r.clientInfo.ExportEnvironmentID, *apiServerId),
CommentInformation: common.GenerateCommentInformation(commentData),
})
}
}

return &importBlocks, nil
}

func (r *PingoneAuthorizeAPIServiceResource) ResourceType() string {
return "pingone_authorize_api_service"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package resources

import (
"fmt"

"github.com/pingidentity/pingctl/internal/connector"
"github.com/pingidentity/pingctl/internal/connector/common"
"github.com/pingidentity/pingctl/internal/logger"
)

// Verify that the resource satisfies the exportable resource interface
var (
_ connector.ExportableResource = &PingoneAuthorizeAPIServiceDeploymentResource{}
)

type PingoneAuthorizeAPIServiceDeploymentResource struct {
clientInfo *connector.PingOneClientInfo
}

// Utility method for creating a PingoneAuthorizeAPIServiceDeploymentResource
func AuthorizeAPIServiceDeployment(clientInfo *connector.PingOneClientInfo) *PingoneAuthorizeAPIServiceDeploymentResource {
return &PingoneAuthorizeAPIServiceDeploymentResource{
clientInfo: clientInfo,
}
}

func (r *PingoneAuthorizeAPIServiceDeploymentResource) ExportAll() (*[]connector.ImportBlock, error) {
l := logger.Get()

l.Debug().Msgf("Fetching all %s resources...", r.ResourceType())

apiExecuteFunc := r.clientInfo.ApiClient.AuthorizeAPIClient.APIServersApi.ReadAllAPIServers(r.clientInfo.Context, r.clientInfo.ExportEnvironmentID).Execute
apiFunctionName := "ReadAllAPIServers"

embedded, err := common.GetAuthorizeEmbedded(apiExecuteFunc, apiFunctionName, r.ResourceType())
if err != nil {
return nil, err
}

importBlocks := []connector.ImportBlock{}

l.Debug().Msgf("Generating Import Blocks for all %s resources...", r.ResourceType())

for _, apiServer := range embedded.GetApiServers() {
var (
apiServerId *string
apiServerIdOk bool
apiServerName *string
apiServerNameOk bool
)

apiServerId, apiServerIdOk = apiServer.GetIdOk()
apiServerName, apiServerNameOk = apiServer.GetNameOk()

if apiServerIdOk && apiServerNameOk {

_, response, err := r.clientInfo.ApiClient.AuthorizeAPIClient.APIServerDeploymentApi.ReadDeploymentStatus(r.clientInfo.Context, r.clientInfo.ExportEnvironmentID, *apiServerId).Execute()
err = common.HandleClientResponse(response, err, "ReadDeploymentStatus", r.ResourceType())
if err != nil {
return nil, err
}

importBlocks := []connector.ImportBlock{}

l.Debug().Msgf("Generating Import Blocks for all %s resources...", r.ResourceType())

if response.StatusCode == 204 {
l.Debug().Msgf("No exportable %s resource found", r.ResourceType())
return &importBlocks, nil
}

commentData := map[string]string{
"Resource Type": r.ResourceType(),
"Authorize API Service Name": *apiServerName,
"Authorize API Service ID": *apiServerId,
"Export Environment ID": r.clientInfo.ExportEnvironmentID,
}

importBlocks = append(importBlocks, connector.ImportBlock{
ResourceType: r.ResourceType(),
ResourceName: *apiServerName,
ResourceID: fmt.Sprintf("%s/%s", r.clientInfo.ExportEnvironmentID, *apiServerId),
CommentInformation: common.GenerateCommentInformation(commentData),
})

return &importBlocks, nil
}
}

return &importBlocks, nil
}

func (r *PingoneAuthorizeAPIServiceDeploymentResource) ResourceType() string {
return "pingone_authorize_api_service_deployment"
}
Loading
Loading