feat(cli): add session recordings: read and list cmds
This commit is contained in:
1 parent
de88a871c6
commit
35a2296092
12 files changed
+655
-26
No files matched your search
@@ -6,14 +6,16 @@ package sessionrecordings
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/api"
|
||||
)
|
||||
|
||||
type ChannelRecording struct {
|
||||
Id string `json:"id,omitempty"`
|
||||
BytesUp uint64 `json:"bytes_up,omitempty"`
|
||||
BytesDown uint64 `json:"bytes_down,omitempty"`
|
||||
StartTime time.Time `json:"start_time,omitempty"`
|
||||
EndTime time.Time `json:"end_time,omitempty"`
|
||||
Duration time.Duration `json:"duration,omitempty"`
|
||||
MimeTypes []string `json:"mime_types,omitempty"`
|
||||
Id string `json:"id,omitempty"`
|
||||
BytesUp uint64 `json:"bytes_up,string,omitempty"`
|
||||
BytesDown uint64 `json:"bytes_down,string,omitempty"`
|
||||
StartTime time.Time `json:"start_time,omitempty"`
|
||||
EndTime time.Time `json:"end_time,omitempty"`
|
||||
Duration api.Duration `json:"duration,omitempty"`
|
||||
MimeTypes []string `json:"mime_types,omitempty"`
|
||||
}
|
||||
@@ -6,16 +6,18 @@ package sessionrecordings
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/api"
|
||||
)
|
||||
|
||||
type ConnectionRecording struct {
|
||||
Id string `json:"id,omitempty"`
|
||||
ConnectionId string `json:"connection_id,omitempty"`
|
||||
BytesUp uint64 `json:"bytes_up,omitempty"`
|
||||
BytesDown uint64 `json:"bytes_down,omitempty"`
|
||||
BytesUp uint64 `json:"bytes_up,string,omitempty"`
|
||||
BytesDown uint64 `json:"bytes_down,string,omitempty"`
|
||||
StartTime time.Time `json:"start_time,omitempty"`
|
||||
EndTime time.Time `json:"end_time,omitempty"`
|
||||
Duration time.Duration `json:"duration,omitempty"`
|
||||
Duration api.Duration `json:"duration,omitempty"`
|
||||
MimeTypes []string `json:"mime_types,omitempty"`
|
||||
ChannelRecordings []*ChannelRecording `json:"channel_recordings,omitempty"`
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
package sessionrecordings
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/boundary/api"
|
||||
@@ -25,6 +26,7 @@ type options struct {
|
||||
withAutomaticVersioning bool
|
||||
withSkipCurlOutput bool
|
||||
withFilter string
|
||||
withRecursive bool
|
||||
}
|
||||
|
||||
func getDefaultOptions() options {
|
||||
@@ -48,6 +50,9 @@ func getOpts(opt ...Option) (options, []api.Option) {
|
||||
if opts.withFilter != "" {
|
||||
opts.queryMap["filter"] = opts.withFilter
|
||||
}
|
||||
if opts.withRecursive {
|
||||
opts.queryMap["recursive"] = strconv.FormatBool(opts.withRecursive)
|
||||
}
|
||||
return opts, apiOpts
|
||||
}
|
||||
|
||||
@@ -67,3 +72,11 @@ func WithFilter(filter string) Option {
|
||||
o.withFilter = strings.TrimSpace(filter)
|
||||
}
|
||||
}
|
||||
|
||||
// WithRecursive tells the API to use recursion for listing operations on this
|
||||
// resource
|
||||
func WithRecursive(recurse bool) Option {
|
||||
return func(o *options) {
|
||||
o.withRecursive = true
|
||||
}
|
||||
}
|
||||
@@ -19,11 +19,11 @@ type SessionRecording struct {
|
||||
Scope *scopes.ScopeInfo `json:"scope,omitempty"`
|
||||
SessionId string `json:"session_id,omitempty"`
|
||||
StorageBucketId string `json:"storage_bucket_id,omitempty"`
|
||||
BytesUp uint64 `json:"bytes_up,omitempty"`
|
||||
BytesDown uint64 `json:"bytes_down,omitempty"`
|
||||
BytesUp uint64 `json:"bytes_up,string,omitempty"`
|
||||
BytesDown uint64 `json:"bytes_down,string,omitempty"`
|
||||
StartTime time.Time `json:"start_time,omitempty"`
|
||||
EndTime time.Time `json:"end_time,omitempty"`
|
||||
Duration time.Duration `json:"duration,omitempty"`
|
||||
Duration api.Duration `json:"duration,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
State string `json:"state,omitempty"`
|
||||
ErrorDetails string `json:"error_details,omitempty"`
|
||||
|
||||
@@ -24,6 +24,11 @@ func TestTypes(t *testing.T) {
|
||||
json: `"12345s"`,
|
||||
want: Duration{Duration: 12345000000000},
|
||||
},
|
||||
{
|
||||
name: "Duration-valid-with-float",
|
||||
json: `"1.2345s"`,
|
||||
want: Duration{Duration: 1234500000},
|
||||
},
|
||||
{
|
||||
name: "Duration-valid",
|
||||
json: `"1h"`,
|
||||
|
||||
@@ -74,3 +74,17 @@ All that's left is to incorporate it into Boundary's CLI for the appropriate com
|
||||
* Run `make cli` and `make install`, before attempting to test cli changes
|
||||
|
||||
[test example]: tests/api/authmethods/classification_test.go
|
||||
|
||||
## Additional steps for new API/CLI commands:
|
||||
|
||||
* After building out the gRPC service, add the new API service definition to the
|
||||
`inputStructs` for API generation: `internal/api/genapi` then run `make api`
|
||||
or `make gen`
|
||||
* Add the new CLI command definition to the `inputStructs` for CLI generation:
|
||||
`internal/cmd/gencli` then run `make cli` or `make gen`
|
||||
* Add the new `cli.CommandFactory` to the `cmd.initCommands(...)`:
|
||||
`internal/cmd` then run `make cli` or `make gen`
|
||||
* Fill out the required funcs in the command's `func.go` following the same
|
||||
suggestion to define consts for field names and reuse them everywhere they are
|
||||
required.
|
||||
* Run `make cli` and `make install`, before attempting to test cli changes
|
||||
@@ -1008,19 +1008,6 @@ var inputStructs = []*structInfo{
|
||||
versionEnabled: true,
|
||||
recursiveListing: true,
|
||||
},
|
||||
{
|
||||
inProto: &session_recordings.SessionRecording{},
|
||||
outFile: "sessionrecordings/session_recording.gen.go",
|
||||
templates: []*template.Template{
|
||||
clientTemplate,
|
||||
readTemplate,
|
||||
listTemplate,
|
||||
},
|
||||
pluralResourceName: "session-recordings",
|
||||
createResponseTypes: []string{ReadResponseType, ListResponseType},
|
||||
recursiveListing: true,
|
||||
versionEnabled: false,
|
||||
},
|
||||
{
|
||||
inProto: &session_recordings.User{},
|
||||
outFile: "sessionrecordings/user.gen.go",
|
||||
@@ -1040,10 +1027,47 @@ var inputStructs = []*structInfo{
|
||||
{
|
||||
inProto: &session_recordings.ConnectionRecording{},
|
||||
outFile: "sessionrecordings/connection_recording.gen.go",
|
||||
fieldOverrides: []fieldInfo{
|
||||
// int64 fields get marshalled by protobuf as strings, so we have
|
||||
// to tell the json parser that their json representation is a
|
||||
// string but they go into Go int64 types.
|
||||
{Name: "BytesUp", JsonTags: []string{"string"}},
|
||||
{Name: "BytesDown", JsonTags: []string{"string"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
inProto: &session_recordings.ChannelRecording{},
|
||||
outFile: "sessionrecordings/channel_recording.gen.go",
|
||||
fieldOverrides: []fieldInfo{
|
||||
// int64 fields get marshalled by protobuf as strings, so we have
|
||||
// to tell the json parser that their json representation is a
|
||||
// string but they go into Go int64 types.
|
||||
{Name: "BytesUp", JsonTags: []string{"string"}},
|
||||
{Name: "BytesDown", JsonTags: []string{"string"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
// this must be the last block of session recording blocks, otherwise
|
||||
// the bits beyond inProto and outFile will get overwritten by
|
||||
// subsequent session recording blocks
|
||||
inProto: &session_recordings.SessionRecording{},
|
||||
outFile: "sessionrecordings/session_recording.gen.go",
|
||||
templates: []*template.Template{
|
||||
clientTemplate,
|
||||
readTemplate,
|
||||
listTemplate,
|
||||
},
|
||||
pluralResourceName: "session-recordings",
|
||||
createResponseTypes: []string{ReadResponseType, ListResponseType},
|
||||
recursiveListing: true,
|
||||
versionEnabled: false,
|
||||
fieldOverrides: []fieldInfo{
|
||||
// int64 fields get marshalled by protobuf as strings, so we have
|
||||
// to tell the json parser that their json representation is a
|
||||
// string but they go into Go int64 types.
|
||||
{Name: "BytesUp", JsonTags: []string{"string"}},
|
||||
{Name: "BytesDown", JsonTags: []string{"string"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
inProto: &workers.Certificate{},
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/rolescmd"
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/scopescmd"
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/server"
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/sessionrecordingscmd"
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/sessionscmd"
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/storagebucketscmd"
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/targetscmd"
|
||||
@@ -1024,6 +1025,24 @@ func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) {
|
||||
}, nil
|
||||
},
|
||||
|
||||
"session-recordings": func() (cli.Command, error) {
|
||||
return &sessionrecordingscmd.Command{
|
||||
Command: base.NewCommand(ui),
|
||||
}, nil
|
||||
},
|
||||
"session-recordings read": func() (cli.Command, error) {
|
||||
return &sessionrecordingscmd.Command{
|
||||
Command: base.NewCommand(ui),
|
||||
Func: "read",
|
||||
}, nil
|
||||
},
|
||||
"session-recordings list": func() (cli.Command, error) {
|
||||
return &sessionrecordingscmd.Command{
|
||||
Command: base.NewCommand(ui),
|
||||
Func: "list",
|
||||
}, nil
|
||||
},
|
||||
|
||||
"storage-buckets": func() (cli.Command, error) {
|
||||
return &storagebucketscmd.Command{
|
||||
Command: base.NewCommand(ui),
|
||||
|
||||
@@ -718,6 +718,7 @@ func (c *Command) Run(args []string) int {
|
||||
c.DevLoopbackPluginId = "pl_1234567890"
|
||||
c.EnabledPlugins = append(c.EnabledPlugins, base.EnabledPluginLoopback)
|
||||
c.Config.Controller.Scheduler.JobRunIntervalDuration = 100 * time.Millisecond
|
||||
c.Info["Generated Dev Loopback plugin id"] = c.DevLoopbackPluginId
|
||||
}
|
||||
switch c.flagDatabaseUrl {
|
||||
case "":
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package sessionrecordingscmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/api"
|
||||
"github.com/hashicorp/boundary/api/sessionrecordings"
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
)
|
||||
|
||||
type extraCmdVars struct{}
|
||||
|
||||
func (c *Command) extraHelpFunc(helpMap map[string]func() string) string {
|
||||
var helpStr string
|
||||
switch c.Func {
|
||||
case "":
|
||||
return base.WrapForHelpText([]string{
|
||||
"Usage: boundary session-recordings [sub command] [options] [args]",
|
||||
"",
|
||||
" This command allows operations on Boundary session recordings.",
|
||||
"",
|
||||
" Read a session recording:",
|
||||
"",
|
||||
` $ boundary session-recordings read -id s_1234567890`,
|
||||
"",
|
||||
" Please see the sessions subcommand help for detailed usage information.",
|
||||
})
|
||||
|
||||
default:
|
||||
helpStr = helpMap["base"]()
|
||||
}
|
||||
|
||||
return helpStr + c.Flags().Help()
|
||||
}
|
||||
|
||||
func (c *Command) printListTable(items []*sessionrecordings.SessionRecording) string {
|
||||
if len(items) == 0 {
|
||||
return "No session recordings found"
|
||||
}
|
||||
var output []string
|
||||
output = []string{
|
||||
"",
|
||||
"Session Recording information:",
|
||||
}
|
||||
for i, item := range items {
|
||||
if i > 0 {
|
||||
output = append(output, "")
|
||||
}
|
||||
if item.Id != "" {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" ID: %s", item.Id),
|
||||
)
|
||||
} else {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" ID: %s", "(not available)"),
|
||||
)
|
||||
}
|
||||
if c.FlagRecursive && item.Scope.Id != "" {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" Scope ID: %s", item.Scope.Id),
|
||||
)
|
||||
}
|
||||
if item.SessionId != "" {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" Session ID: %s", item.SessionId),
|
||||
)
|
||||
}
|
||||
if item.StorageBucketId != "" {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" Storage Bucket ID: %s", item.StorageBucketId),
|
||||
)
|
||||
}
|
||||
if !item.StartTime.IsZero() {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" Start Time: %s", item.StartTime.Local().Format(time.RFC1123)),
|
||||
)
|
||||
}
|
||||
if !item.EndTime.IsZero() {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" End Time: %s", item.EndTime.Local().Format(time.RFC1123)),
|
||||
)
|
||||
}
|
||||
if item.Type != "" {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" Type: %s", item.Type),
|
||||
)
|
||||
}
|
||||
if item.State != "" {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" State: %s", item.State),
|
||||
)
|
||||
}
|
||||
if len(item.AuthorizedActions) > 0 {
|
||||
output = append(output,
|
||||
" Authorized Actions:",
|
||||
base.WrapSlice(6, item.AuthorizedActions),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return base.WrapForHelpText(output)
|
||||
}
|
||||
|
||||
func printItemTable(item *sessionrecordings.SessionRecording, resp *api.Response) string {
|
||||
const (
|
||||
durationKey = "Duration (Seconds)"
|
||||
)
|
||||
nonAttributeMap := map[string]any{}
|
||||
if item.Id != "" {
|
||||
nonAttributeMap["ID"] = item.Id
|
||||
}
|
||||
if item.Scope.Id != "" {
|
||||
nonAttributeMap["Scope ID"] = item.Scope.Id
|
||||
}
|
||||
if item.SessionId != "" {
|
||||
nonAttributeMap["Session ID"] = item.SessionId
|
||||
}
|
||||
if item.StorageBucketId != "" {
|
||||
nonAttributeMap["Storage Bucket ID"] = item.StorageBucketId
|
||||
}
|
||||
if item.BytesUp != 0 {
|
||||
nonAttributeMap["Bytes Up"] = item.BytesUp
|
||||
}
|
||||
if item.BytesDown != 0 {
|
||||
nonAttributeMap["Bytes Down"] = item.BytesDown
|
||||
}
|
||||
if !item.StartTime.IsZero() {
|
||||
nonAttributeMap["Start Time"] = item.StartTime.Local().Format(time.RFC1123)
|
||||
}
|
||||
if !item.EndTime.IsZero() {
|
||||
nonAttributeMap["Updated Time"] = item.EndTime.Local().Format(time.RFC1123)
|
||||
}
|
||||
if item.Duration.Duration != 0 {
|
||||
nonAttributeMap[durationKey] = item.Duration.Seconds()
|
||||
}
|
||||
if item.Type != "" {
|
||||
nonAttributeMap["Type"] = item.Type
|
||||
}
|
||||
if item.State != "" {
|
||||
nonAttributeMap["State"] = item.State
|
||||
}
|
||||
if item.ErrorDetails != "" {
|
||||
nonAttributeMap["Error Details"] = item.ErrorDetails
|
||||
}
|
||||
if len(item.MimeTypes) > 0 {
|
||||
nonAttributeMap["Mime Types"] = strings.Join(item.MimeTypes, ", ")
|
||||
}
|
||||
if item.Endpoint != "" {
|
||||
nonAttributeMap["Endpoint"] = item.Endpoint
|
||||
}
|
||||
|
||||
maxLength := base.MaxAttributesLength(nonAttributeMap, nil, nil)
|
||||
|
||||
ret := []string{
|
||||
"",
|
||||
"Session Recording information:",
|
||||
base.WrapMap(2, maxLength+2, nonAttributeMap),
|
||||
}
|
||||
|
||||
if item.Scope != nil {
|
||||
ret = append(ret,
|
||||
"",
|
||||
" Scope:",
|
||||
base.ScopeInfoForOutput(item.Scope, maxLength),
|
||||
)
|
||||
}
|
||||
|
||||
if len(item.AuthorizedActions) > 0 {
|
||||
ret = append(ret,
|
||||
"",
|
||||
" Authorized Actions:",
|
||||
base.WrapSlice(4, item.AuthorizedActions),
|
||||
)
|
||||
}
|
||||
|
||||
if len(item.ConnectionRecordings) > 0 {
|
||||
maxAttrLen := len(durationKey)
|
||||
ret = append(ret,
|
||||
"",
|
||||
" Connections Recordings:",
|
||||
)
|
||||
for _, cr := range item.ConnectionRecordings {
|
||||
cm := map[string]any{
|
||||
"ID": cr.Id,
|
||||
"Connection ID": cr.ConnectionId,
|
||||
}
|
||||
if cr.BytesUp != 0 {
|
||||
cm["Bytes Up"] = cr.BytesUp
|
||||
}
|
||||
if cr.BytesDown != 0 {
|
||||
cm["Bytes Down"] = cr.BytesDown
|
||||
}
|
||||
if !cr.StartTime.IsZero() {
|
||||
cm["Start Time"] = cr.StartTime.Local().Format(time.RFC1123)
|
||||
}
|
||||
if !cr.EndTime.IsZero() {
|
||||
cm["End Time"] = cr.EndTime.Local().Format(time.RFC1123)
|
||||
}
|
||||
if cr.Duration.Duration != 0 {
|
||||
cm[durationKey] = cr.Duration.Seconds()
|
||||
}
|
||||
if len(cr.MimeTypes) > 0 {
|
||||
cm["Mime Types"] = strings.Join(cr.MimeTypes, ", ")
|
||||
}
|
||||
ret = append(ret,
|
||||
base.WrapMap(4, maxAttrLen, cm),
|
||||
"",
|
||||
)
|
||||
|
||||
if len(cr.ChannelRecordings) > 0 {
|
||||
var channelRecordings []map[string]any
|
||||
for _, chr := range cr.ChannelRecordings {
|
||||
chrm := map[string]any{
|
||||
"ID": chr.Id,
|
||||
}
|
||||
if chr.BytesUp != 0 {
|
||||
chrm["Bytes Up"] = chr.BytesUp
|
||||
}
|
||||
if chr.BytesDown != 0 {
|
||||
chrm["Bytes Down"] = chr.BytesDown
|
||||
}
|
||||
if !chr.StartTime.IsZero() {
|
||||
chrm["Start Time"] = chr.StartTime.Local().Format(time.RFC1123)
|
||||
}
|
||||
if !chr.EndTime.IsZero() {
|
||||
chrm["End Time"] = chr.EndTime.Local().Format(time.RFC1123)
|
||||
}
|
||||
if chr.Duration.Duration != 0 {
|
||||
chrm[durationKey] = chr.Duration.Seconds()
|
||||
}
|
||||
if len(chr.MimeTypes) > 0 {
|
||||
chrm["Mine Types"] = strings.Join(chr.MimeTypes, ", ")
|
||||
}
|
||||
channelRecordings = append(channelRecordings, chrm)
|
||||
}
|
||||
ret = append(ret,
|
||||
"",
|
||||
" Channel Recordings:",
|
||||
)
|
||||
for _, cr := range channelRecordings {
|
||||
ret = append(ret,
|
||||
base.WrapMap(6, maxAttrLen, cr),
|
||||
"",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return base.WrapForHelpText(ret)
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
// Code generated by "make cli"; DO NOT EDIT.
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package sessionrecordingscmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/boundary/api"
|
||||
"github.com/hashicorp/boundary/api/sessionrecordings"
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
"github.com/hashicorp/boundary/internal/cmd/common"
|
||||
"github.com/hashicorp/go-secure-stdlib/strutil"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/posener/complete"
|
||||
)
|
||||
|
||||
func initFlags() {
|
||||
flagsOnce.Do(func() {
|
||||
extraFlags := extraActionsFlagsMapFunc()
|
||||
for k, v := range extraFlags {
|
||||
flagsMap[k] = append(flagsMap[k], v...)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var (
|
||||
_ cli.Command = (*Command)(nil)
|
||||
_ cli.CommandAutocomplete = (*Command)(nil)
|
||||
)
|
||||
|
||||
type Command struct {
|
||||
*base.Command
|
||||
|
||||
Func string
|
||||
|
||||
plural string
|
||||
|
||||
extraCmdVars
|
||||
}
|
||||
|
||||
func (c *Command) AutocompleteArgs() complete.Predictor {
|
||||
initFlags()
|
||||
return complete.PredictAnything
|
||||
}
|
||||
|
||||
func (c *Command) AutocompleteFlags() complete.Flags {
|
||||
initFlags()
|
||||
return c.Flags().Completions()
|
||||
}
|
||||
|
||||
func (c *Command) Synopsis() string {
|
||||
if extra := extraSynopsisFunc(c); extra != "" {
|
||||
return extra
|
||||
}
|
||||
|
||||
synopsisStr := "session recording"
|
||||
|
||||
return common.SynopsisFunc(c.Func, synopsisStr)
|
||||
}
|
||||
|
||||
func (c *Command) Help() string {
|
||||
initFlags()
|
||||
|
||||
var helpStr string
|
||||
helpMap := common.HelpMap("session recording")
|
||||
|
||||
switch c.Func {
|
||||
|
||||
case "read":
|
||||
helpStr = helpMap[c.Func]() + c.Flags().Help()
|
||||
|
||||
case "list":
|
||||
helpStr = helpMap[c.Func]() + c.Flags().Help()
|
||||
|
||||
default:
|
||||
|
||||
helpStr = c.extraHelpFunc(helpMap)
|
||||
|
||||
}
|
||||
|
||||
// Keep linter from complaining if we don't actually generate code using it
|
||||
_ = helpMap
|
||||
return helpStr
|
||||
}
|
||||
|
||||
var flagsMap = map[string][]string{
|
||||
|
||||
"read": {"id"},
|
||||
|
||||
"list": {"scope-id", "filter", "recursive"},
|
||||
}
|
||||
|
||||
func (c *Command) Flags() *base.FlagSets {
|
||||
if len(flagsMap[c.Func]) == 0 {
|
||||
return c.FlagSet(base.FlagSetNone)
|
||||
}
|
||||
|
||||
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
common.PopulateCommonFlags(c.Command, f, "session recording", flagsMap, c.Func)
|
||||
|
||||
extraFlagsFunc(c, set, f)
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
func (c *Command) Run(args []string) int {
|
||||
initFlags()
|
||||
|
||||
switch c.Func {
|
||||
case "":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "create":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "update":
|
||||
return cli.RunResultHelp
|
||||
|
||||
}
|
||||
|
||||
c.plural = "session recording"
|
||||
switch c.Func {
|
||||
case "list":
|
||||
c.plural = "session recordings"
|
||||
}
|
||||
|
||||
f := c.Flags()
|
||||
|
||||
if err := f.Parse(args); err != nil {
|
||||
c.PrintCliError(err)
|
||||
return base.CommandUserError
|
||||
}
|
||||
|
||||
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
|
||||
c.PrintCliError(errors.New("ID is required but not passed in via -id"))
|
||||
return base.CommandUserError
|
||||
}
|
||||
|
||||
var opts []sessionrecordings.Option
|
||||
|
||||
if strutil.StrListContains(flagsMap[c.Func], "scope-id") {
|
||||
switch c.Func {
|
||||
|
||||
case "list":
|
||||
if c.FlagScopeId == "" {
|
||||
c.PrintCliError(errors.New("Scope ID must be passed in via -scope-id or BOUNDARY_SCOPE_ID"))
|
||||
return base.CommandUserError
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
client, err := c.Client()
|
||||
if c.WrapperCleanupFunc != nil {
|
||||
defer func() {
|
||||
if err := c.WrapperCleanupFunc(); err != nil {
|
||||
c.PrintCliError(fmt.Errorf("Error cleaning kms wrapper: %w", err))
|
||||
}
|
||||
}()
|
||||
}
|
||||
if err != nil {
|
||||
c.PrintCliError(fmt.Errorf("Error creating API client: %w", err))
|
||||
return base.CommandCliError
|
||||
}
|
||||
sessionrecordingsClient := sessionrecordings.NewClient(client)
|
||||
|
||||
switch c.FlagRecursive {
|
||||
case true:
|
||||
opts = append(opts, sessionrecordings.WithRecursive(true))
|
||||
}
|
||||
|
||||
if c.FlagFilter != "" {
|
||||
opts = append(opts, sessionrecordings.WithFilter(c.FlagFilter))
|
||||
}
|
||||
|
||||
var version uint32
|
||||
|
||||
if ok := extraFlagsHandlingFunc(c, f, &opts); !ok {
|
||||
return base.CommandUserError
|
||||
}
|
||||
|
||||
var resp *api.Response
|
||||
var item *sessionrecordings.SessionRecording
|
||||
|
||||
var items []*sessionrecordings.SessionRecording
|
||||
|
||||
var readResult *sessionrecordings.SessionRecordingReadResult
|
||||
|
||||
var listResult *sessionrecordings.SessionRecordingListResult
|
||||
|
||||
switch c.Func {
|
||||
|
||||
case "read":
|
||||
readResult, err = sessionrecordingsClient.Read(c.Context, c.FlagId, opts...)
|
||||
if exitCode := c.checkFuncError(err); exitCode > 0 {
|
||||
return exitCode
|
||||
}
|
||||
resp = readResult.GetResponse()
|
||||
item = readResult.GetItem()
|
||||
|
||||
case "list":
|
||||
listResult, err = sessionrecordingsClient.List(c.Context, c.FlagScopeId, opts...)
|
||||
if exitCode := c.checkFuncError(err); exitCode > 0 {
|
||||
return exitCode
|
||||
}
|
||||
resp = listResult.GetResponse()
|
||||
items = listResult.GetItems()
|
||||
|
||||
}
|
||||
|
||||
resp, item, items, err = executeExtraActions(c, resp, item, items, err, sessionrecordingsClient, version, opts)
|
||||
if exitCode := c.checkFuncError(err); exitCode > 0 {
|
||||
return exitCode
|
||||
}
|
||||
|
||||
output, err := printCustomActionOutput(c)
|
||||
if err != nil {
|
||||
c.PrintCliError(err)
|
||||
return base.CommandUserError
|
||||
}
|
||||
if output {
|
||||
return base.CommandSuccess
|
||||
}
|
||||
|
||||
switch c.Func {
|
||||
|
||||
case "list":
|
||||
switch base.Format(c.UI) {
|
||||
case "json":
|
||||
if ok := c.PrintJsonItems(resp); !ok {
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
case "table":
|
||||
c.UI.Output(c.printListTable(items))
|
||||
}
|
||||
|
||||
return base.CommandSuccess
|
||||
|
||||
}
|
||||
|
||||
switch base.Format(c.UI) {
|
||||
case "table":
|
||||
c.UI.Output(printItemTable(item, resp))
|
||||
|
||||
case "json":
|
||||
if ok := c.PrintJsonItem(resp); !ok {
|
||||
return base.CommandCliError
|
||||
}
|
||||
}
|
||||
|
||||
return base.CommandSuccess
|
||||
}
|
||||
|
||||
func (c *Command) checkFuncError(err error) int {
|
||||
if err == nil {
|
||||
return 0
|
||||
}
|
||||
if apiErr := api.AsServerError(err); apiErr != nil {
|
||||
c.PrintApiError(apiErr, fmt.Sprintf("Error from controller when performing %s on %s", c.Func, c.plural))
|
||||
return base.CommandApiError
|
||||
}
|
||||
c.PrintCliError(fmt.Errorf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
var (
|
||||
flagsOnce = new(sync.Once)
|
||||
|
||||
extraActionsFlagsMapFunc = func() map[string][]string { return nil }
|
||||
extraSynopsisFunc = func(*Command) string { return "" }
|
||||
extraFlagsFunc = func(*Command, *base.FlagSets, *base.FlagSet) {}
|
||||
extraFlagsHandlingFunc = func(*Command, *base.FlagSets, *[]sessionrecordings.Option) bool { return true }
|
||||
executeExtraActions = func(_ *Command, inResp *api.Response, inItem *sessionrecordings.SessionRecording, inItems []*sessionrecordings.SessionRecording, inErr error, _ *sessionrecordings.Client, _ uint32, _ []sessionrecordings.Option) (*api.Response, *sessionrecordings.SessionRecording, []*sessionrecordings.SessionRecording, error) {
|
||||
return inResp, inItem, inItems, inErr
|
||||
}
|
||||
printCustomActionOutput = func(*Command) (bool, error) { return false, nil }
|
||||
)
|
||||
@@ -566,6 +566,17 @@ var inputStructs = map[string][]*cmdInfo{
|
||||
VersionedActions: []string{"cancel"},
|
||||
},
|
||||
},
|
||||
"sessionrecordings": {
|
||||
{
|
||||
ResourceType: resource.SessionRecording.String(),
|
||||
Pkg: "sessionrecordings",
|
||||
StdActions: []string{"read", "list"},
|
||||
Container: "Scope",
|
||||
HasExtraCommandVars: true,
|
||||
HasExtraHelpFunc: true,
|
||||
HasId: true,
|
||||
},
|
||||
},
|
||||
"storagebuckets": {
|
||||
{
|
||||
ResourceType: resource.StorageBucket.String(),
|
||||
|
||||
Reference in new issue
Block a user