mirror of https://github.com/hashicorp/boundary
parent
de88a871c6
commit
35a2296092
@ -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 }
|
||||
)
|
||||
Loading…
Reference in new issue