Skip to content
Merged
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
54 changes: 46 additions & 8 deletions otdfctl/cmd/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package cmd
import (
"errors"
"fmt"
"os"
"runtime"
"strconv"
"strings"

osprofiles "github.com/jrschumacher/go-osprofiles"
Expand All @@ -26,6 +28,25 @@ const (
" If that still doesn't work, you can remove all profiles from the filesystem via the `delete-all` command."
)

type profileListOutput struct {
Store string `json:"store"`
Profiles []profileSummary `json:"profiles"`
}

type profileSummary struct {
Name string `json:"name"`
IsDefault bool `json:"is_default"`
}

type profileGetOutput struct {
Profile string `json:"profile"`
Endpoint string `json:"endpoint"`
IsDefault bool `json:"is_default"`
OutputFormat string `json:"output_format"`
AuthType string `json:"auth_type,omitempty"`
ClientID string `json:"client_id,omitempty"`
}

func newProfilerFromCLI(c *cli.Cli) *osprofiles.Profiler {
driverType := getDriverTypeFromUser(c)
profiler, err := profiles.NewProfiler(string(driverType))
Expand Down Expand Up @@ -104,15 +125,24 @@ var profileListCmd = &cobra.Command{
var sb strings.Builder
fmt.Fprintf(&sb, "Listing profiles from %s\n", driverType)

out := profileListOutput{
Store: string(driverType),
Profiles: []profileSummary{},
}
for _, p := range osprofiles.ListProfiles(profiler) {
if p == defaultProfile {
isDefault := p == defaultProfile
out.Profiles = append(out.Profiles, profileSummary{
Name: p,
IsDefault: isDefault,
})
if isDefault {
fmt.Fprintf(&sb, "* %s\n", p)
continue
}
fmt.Fprintf(&sb, " %s\n", p)
}

c.ExitWithMessage(sb.String(), cli.ExitCodeSuccess)
c.ExitWith(sb.String(), out, cli.ExitCodeSuccess, os.Stdout)
},
}

Expand All @@ -130,27 +160,35 @@ var profileGetCmd = &cobra.Command{
cli.ExitWithError("Error loading profile store for profile "+profileName, err)
}

isDefault := "false"
if profileStore.IsDefault() {
isDefault = "true"
}
isDefault := profileStore.IsDefault()

var auth string
authType := ""
clientID := ""
ac := profileStore.GetAuthCredentials()
if ac.AuthType == profiles.AuthTypeClientCredentials {
maskedSecret := "********"
auth = "client-credentials (" + ac.ClientID + ", " + maskedSecret + ")"
authType = ac.AuthType
clientID = ac.ClientID
}

t := cli.NewTabular(
[]string{"Profile", profileStore.Name()},
[]string{"Endpoint", profileStore.GetEndpoint()},
[]string{"Is default", isDefault},
[]string{"Is default", strconv.FormatBool(isDefault)},
[]string{"Output format", profileStore.GetOutputFormat()},
[]string{"Auth type", auth},
)

c.ExitWithMessage(t.View(), cli.ExitCodeSuccess)
c.ExitWith(t.View(), profileGetOutput{
Profile: profileStore.Name(),
Endpoint: profileStore.GetEndpoint(),
IsDefault: isDefault,
OutputFormat: profileStore.GetOutputFormat(),
AuthType: authType,
ClientID: clientID,
}, cli.ExitCodeSuccess, os.Stdout)
},
}

Expand Down
3 changes: 2 additions & 1 deletion otdfctl/e2e/kas-keys.bats
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,8 @@ format_kas_name_as_uri() {
@test "kas-keys: update key (missing id)" {
run_otdfctl_key update --json
assert_failure
assert_output --partial "ERROR Flag '--id' is required"
assert_equal "$(echo "$output" | jq -r .status)" "ERROR"
assert_equal "$(echo "$output" | jq -r .message)" "Flag '--id' is required"
}

# LIST Tests
Expand Down
40 changes: 40 additions & 0 deletions otdfctl/e2e/profile.bats
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,46 @@ teardown() {
refute_output --partial "$target_profile_keyring"
}

@test "profile list supports json output" {
profile1="${PROFILE_TEST_PREFIX}-list-json-1"
profile2="${PROFILE_TEST_PREFIX}-list-json-2"

run_otdfctl create "$profile1" http://localhost:8080
assert_success

run_otdfctl create "$profile2" http://localhost:8080 --set-default
assert_success

run_otdfctl list --json
assert_success
assert_equal "$(echo "$output" | jq -r .store)" "filesystem"
echo "$output" | jq -e --arg profile1 "$profile1" --arg profile2 "$profile2" \
'any(.profiles[]; .name == $profile1 and .is_default == false) and any(.profiles[]; .name == $profile2 and .is_default == true)'
}

@test "profile get supports json output" {
profile="${PROFILE_TEST_PREFIX}-get-json"

run_otdfctl create "$profile" http://localhost:8080 --set-default --output-format json
assert_success

run_otdfctl get "$profile" --json
assert_success
assert_equal "$(echo "$output" | jq -r .profile)" "$profile"
assert_equal "$(echo "$output" | jq -r .endpoint)" "http://localhost:8080"
assert_equal "$(echo "$output" | jq -r .is_default)" "true"
assert_equal "$(echo "$output" | jq -r .output_format)" "json"
}

@test "profile errors support json output" {
profile="${PROFILE_TEST_PREFIX}-missing-json"

run_otdfctl get "$profile" --json
assert_failure
assert_equal "$(echo "$output" | jq -r .status)" "ERROR"
echo "$output" | jq -e --arg profile "$profile" '.message | contains($profile)'
}

@test "profile set-default updates default profile" {
base="${PROFILE_TEST_PREFIX}-set-default"
profile1="${base}-1"
Expand Down
5 changes: 1 addition & 4 deletions otdfctl/pkg/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,7 @@ func New(cmd *cobra.Command, args []string, options ...cliVariadicOption) *Cli {
// Temp wrapper for FlagHelper until we can remove it
cli.FlagHelper = cli.Flags

cli.printer = newPrinter(cli)
if opts.printerJSON {
cli.printer.setJSON(true)
}
cli.printer = newPrinter(opts.printerJSON || cli.Flags.GetOptionalBool("json"))

return cli
}
Expand Down
26 changes: 20 additions & 6 deletions otdfctl/pkg/cli/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cli
import (
"io"
"os"
"strings"

"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
Expand All @@ -15,17 +16,17 @@ const (

func ExitWithError(errMsg string, err error) {
// This is temporary until we can refactor the code to use the Cli struct
(&Cli{printer: &Printer{enabled: true}}).ExitWithError(errMsg, err)
(&Cli{printer: defaultPrinter()}).ExitWithError(errMsg, err)
}

func ExitWithNotFoundError(errMsg string, err error) {
// This is temporary until we can refactor the code to use the Cli struct
(&Cli{printer: &Printer{enabled: true}}).ExitWithNotFoundError(errMsg, err)
(&Cli{printer: defaultPrinter()}).ExitWithNotFoundError(errMsg, err)
}

func ExitWithWarning(warnMsg string) {
// This is temporary until we can refactor the code to use the Cli struct
(&Cli{printer: &Printer{enabled: true}}).ExitWithWarning(warnMsg)
(&Cli{printer: defaultPrinter()}).ExitWithWarning(warnMsg)
}

// ExitWithError prints an error message and exits with a non-zero status code.
Expand Down Expand Up @@ -57,10 +58,16 @@ func (c *Cli) ExitWithSuccess(msg string) {
}

func (c *Cli) ExitWithMessage(msg string, code int) {
if c.printer.enabled {
c.println(os.Stdout, msg)
os.Exit(code)
w := os.Stdout
if code != ExitCodeSuccess {
w = os.Stderr
}
if c.printer.json {
c.printJSON(MessageJSON(statusForExitCode(code), strings.TrimSpace(msg)), w)
} else {
c.println(w, msg)
}
os.Exit(code)
}
Comment thread
jakedoublev marked this conversation as resolved.

func (c *Cli) ExitWithJSON(v interface{}, code int) {
Expand All @@ -80,3 +87,10 @@ func (c *Cli) ExitWith(styledMsg string, jsonMsg interface{}, code int, w io.Wri
}
os.Exit(code)
}

func statusForExitCode(code int) string {
if code == ExitCodeSuccess {
return "SUCCESS"
}
return "ERROR"
}
17 changes: 14 additions & 3 deletions otdfctl/pkg/cli/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,29 @@ import (
"errors"
"fmt"
"io"
"sync/atomic"
)

var ErrPrinterExpectsCommand = errors.New("printer expects a command")

var defaultJSONOutput atomic.Bool

type Printer struct {
enabled bool
json bool
debug bool
}

func newPrinter(cli *Cli) *Printer {
func newPrinter(json bool) *Printer {
p := &Printer{
enabled: true,
json: false,
debug: false,
}

// if json output is enabled, disable the printer
printJSON := cli.Flags.GetOptionalBool("json")
p.setJSON(printJSON)
defaultJSONOutput.Store(json)
p.setJSON(json)

return p
}
Expand Down Expand Up @@ -57,3 +60,11 @@ func (c *Cli) SetJSONOutput(enabled bool) {
}
c.printer.setJSON(enabled)
}

func defaultPrinter() *Printer {
json := defaultJSONOutput.Load()
return &Printer{
enabled: !json,
json: json,
}
}
Loading