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

PLTCONN-3577: Commands to manage connector customizers Part 1 #96

Merged
merged 8 commits into from
Sep 7, 2023
6 changes: 5 additions & 1 deletion cmd/connector/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ import (
)

const (
connectorsEndpoint = "/beta/platform-connectors"
connectorsEndpoint = "/beta/platform-connectors"
connectorInstancesEndpoint = "/beta/connector-instances"
connectorCustomizersEndpoint = "/beta/connector-customizers"
)

func NewConnCmd(term terminal.Terminal) *cobra.Command {
Expand Down Expand Up @@ -53,6 +55,8 @@ func NewConnCmd(term terminal.Terminal) *cobra.Command {
newConnLogsCmd(Client),
newConnStatsCmd(Client),
newConnDeleteCmd(Client),
newConnCustomizersCmd(Client),
newConnInstancesCmd(Client),
)

return conn
Expand Down
6 changes: 3 additions & 3 deletions cmd/connector/conn_invoke_change_password_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func TestChangePasswordWithoutInput(t *testing.T) {
defer ctrl.Finish()

client := mocks.NewMockClient(ctrl)
term := mocks.NewMockTerm(ctrl)
term := mocks.NewMockTerminal(ctrl)

cmd := newConnInvokeChangePasswordCmd(client, term)
addRequiredFlagsFromParentCmd(cmd)
Expand All @@ -43,7 +43,7 @@ func TestChangePasswordWithIdentityAndPassword(t *testing.T) {
Post(gomock.Any(), gomock.Any(), "application/json", bytes.NewReader([]byte(i))).
Return(&http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(bytes.NewReader([]byte("{}")))}, nil)

term := mocks.NewMockTerm(ctrl)
term := mocks.NewMockTerminal(ctrl)
term.EXPECT().
PromptPassword(gomock.Any()).
Return("password", nil)
Expand Down Expand Up @@ -73,7 +73,7 @@ func TestChangePasswordWithIdentityAndPasswordAndUniqueId(t *testing.T) {
Post(gomock.Any(), gomock.Any(), "application/json", bytes.NewReader([]byte(i))).
Return(&http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(bytes.NewReader([]byte("{}")))}, nil)

term := mocks.NewMockTerm(ctrl)
term := mocks.NewMockTerminal(ctrl)
term.EXPECT().
PromptPassword(gomock.Any()).
Return("password", nil)
Expand Down
2 changes: 1 addition & 1 deletion cmd/connector/conn_invoke_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func TestNewConnInvokeCmd_noArgs(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

cmd := newConnInvokeCmd(mocks.NewMockClient(ctrl), mocks.NewMockTerm(ctrl))
cmd := newConnInvokeCmd(mocks.NewMockClient(ctrl), mocks.NewMockTerminal(ctrl))
if len(cmd.Commands()) != numConnInvokeSubcommands {
t.Fatalf("expected: %d, actual: %d", len(cmd.Commands()), numConnInvokeSubcommands)
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/connector/conn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
// Unit tests for conn.go

// Expected number of subcommands to `connectors`
const numConnSubcommands = 14
const numConnSubcommands = 16

func TestConnResourceUrl(t *testing.T) {
testEndpoint := "http://localhost:7100/resources"
Expand All @@ -33,7 +33,7 @@ func TestNewConnCmd_noArgs(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

cmd := NewConnCmd(mocks.NewMockTerm(ctrl))
cmd := NewConnCmd(mocks.NewMockTerminal(ctrl))
if len(cmd.Commands()) != numConnSubcommands {
t.Fatalf("expected: %d, actual: %d", len(cmd.Commands()), numConnSubcommands)
}
Expand Down
32 changes: 32 additions & 0 deletions cmd/connector/customizer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (c) 2023, SailPoint Technologies, Inc. All rights reserved.
package connector

import (
"fmt"

"github.com/sailpoint-oss/sailpoint-cli/internal/client"
"github.com/spf13/cobra"
)

func newConnCustomizersCmd(client client.Client) *cobra.Command {
cmd := &cobra.Command{
Use: "customizers",
Short: "Manage connector customizers",
Run: func(cmd *cobra.Command, args []string) {
_, _ = fmt.Fprintf(cmd.OutOrStdout(), cmd.UsageString())
},
}

cmd.AddCommand(
newCustomizerListCmd(client),
newCustomizerCreateCmd(client),
newCustomizerGetCmd(client),
newCustomizerUpdateCmd(client),
newCustomizerDeleteCmd(client),
newCustomizerCreateVersionCmd(client),
newCustomizerLinkCmd(client),
newCustomizerUnlinkCmd(client),
)

return cmd
}
58 changes: 58 additions & 0 deletions cmd/connector/customizer_create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (c) 2023, SailPoint Technologies, Inc. All rights reserved.
package connector

import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"

"github.com/olekukonko/tablewriter"
"github.com/sailpoint-oss/sailpoint-cli/internal/client"
"github.com/sailpoint-oss/sailpoint-cli/internal/util"
"github.com/spf13/cobra"
)

func newCustomizerCreateCmd(client client.Client) *cobra.Command {
cmd := &cobra.Command{
Use: "create <customizer-name>",
Short: "Create connector customizer",
Example: "sail conn customizers create \"My Customizer\"",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
raw, err := json.Marshal(customizer{Name: args[0]})
if err != nil {
return err
}

resp, err := client.Post(cmd.Context(), util.ResourceUrl(connectorCustomizersEndpoint), "application/json", bytes.NewReader(raw))
if err != nil {
return err
}
defer func(Body io.ReadCloser) {
_ = Body.Close()
}(resp.Body)

if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("create customizer failed. status: %s\nbody: %s", resp.Status, string(body))
}

var cus customizer
err = json.NewDecoder(resp.Body).Decode(&cus)
if err != nil {
return err
}

table := tablewriter.NewWriter(cmd.OutOrStdout())
table.SetHeader(customizerColumns)
table.Append(cus.columns())
table.Render()

return nil
},
}

return cmd
}
83 changes: 83 additions & 0 deletions cmd/connector/customizer_create_version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright (c) 2023, SailPoint Technologies, Inc. All rights reserved.
package connector

import (
"archive/zip"
"encoding/json"
"fmt"
"io"
"net/http"
"os"

"github.com/olekukonko/tablewriter"
"github.com/sailpoint-oss/sailpoint-cli/internal/client"
"github.com/sailpoint-oss/sailpoint-cli/internal/util"
"github.com/spf13/cobra"
)

func newCustomizerCreateVersionCmd(client client.Client) *cobra.Command {
cmd := &cobra.Command{
Use: "upload",
Short: "Upload connector customizer",
Example: "sail conn customizers upload -c 1234 -f path/to/zip/archive.zip",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
id := cmd.Flags().Lookup("id").Value.String()
archivePath := cmd.Flags().Lookup("file").Value.String()

f, err := os.Open(archivePath)
if err != nil {
return err
}

info, err := f.Stat()
if err != nil {
return err
}

_, err = zip.NewReader(f, info.Size())
if err != nil {
return err
}

_, err = f.Seek(0, io.SeekStart)
if err != nil {
return err
}

resp, err := client.Post(cmd.Context(), util.ResourceUrl(connectorCustomizersEndpoint, id, "versions"), "application/zip", f)
if err != nil {
return err
}
defer func(Body io.ReadCloser) {
_ = Body.Close()
}(resp.Body)

if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("upload customizer failed. status: %s\nbody: %s", resp.Status, string(body))
}

var cv customizerVersion
err = json.NewDecoder(resp.Body).Decode(&cv)
if err != nil {
return err
}

table := tablewriter.NewWriter(cmd.OutOrStdout())
table.SetHeader(customizerVersionColumns)
table.Append(cv.columns())
table.Render()

return nil
},
}

cmd.Flags().StringP("id", "c", "", "Connector customizer ID")
_ = cmd.MarkFlagRequired("id")

cmd.Flags().StringP("file", "f", "", "ZIP Archive")
_ = cmd.MarkFlagRequired("file")

return cmd
}
46 changes: 46 additions & 0 deletions cmd/connector/customizer_delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) 2023, SailPoint Technologies, Inc. All rights reserved.
package connector

import (
"fmt"
"io"
"net/http"

"github.com/sailpoint-oss/sailpoint-cli/internal/client"
"github.com/sailpoint-oss/sailpoint-cli/internal/util"
"github.com/spf13/cobra"
)

func newCustomizerDeleteCmd(client client.Client) *cobra.Command {
cmd := &cobra.Command{
Use: "delete",
Short: "Delete connector customizer",
Example: "sail conn customizers delete -c 1234",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
id := cmd.Flags().Lookup("id").Value.String()

q := map[string]string{"type": "hard-delete"}
resp, err := client.Delete(cmd.Context(), util.ResourceUrl(connectorCustomizersEndpoint, id), q)
if err != nil {
return err
}
defer func() {
_ = resp.Body.Close()
}()

if resp.StatusCode != http.StatusNoContent {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("delete customizer failed. status: %s\nbody: %s", resp.Status, string(body))
}

_, _ = fmt.Fprintf(cmd.OutOrStdout(), "connector customizer %s deleted.\n", id)
return nil
},
}

cmd.Flags().StringP("id", "c", "", "Connector customizer ID")
_ = cmd.MarkFlagRequired("id")

return cmd
}
57 changes: 57 additions & 0 deletions cmd/connector/customizer_get.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright (c) 2023, SailPoint Technologies, Inc. All rights reserved.
package connector

import (
"encoding/json"
"fmt"
"io"
"net/http"

"github.com/olekukonko/tablewriter"
"github.com/sailpoint-oss/sailpoint-cli/internal/client"
"github.com/sailpoint-oss/sailpoint-cli/internal/util"
"github.com/spf13/cobra"
)

func newCustomizerGetCmd(client client.Client) *cobra.Command {
cmd := &cobra.Command{
Use: "get",
Short: "Get connector customizer",
Example: "sail conn customizers update -c 1234",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
id := cmd.Flags().Lookup("id").Value.String()

resp, err := client.Get(cmd.Context(), util.ResourceUrl(connectorCustomizersEndpoint, id))
if err != nil {
return err
}
defer func(Body io.ReadCloser) {
_ = Body.Close()
}(resp.Body)

if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("create customizer failed. status: %s\nbody: %s", resp.Status, string(body))
}

var cus customizer
err = json.NewDecoder(resp.Body).Decode(&cus)
if err != nil {
return err
}

table := tablewriter.NewWriter(cmd.OutOrStdout())
table.SetHeader(customizerColumns)
table.Append(cus.columns())
table.Render()

return nil
},
}

cmd.Flags().StringP("id", "c", "", "Connector customizer ID")
_ = cmd.MarkFlagRequired("id")

return cmd
}
Loading
Loading