diff --git a/internal/cmd/base/format.go b/internal/cmd/base/format.go index a0188ea48e..28f4ec0e11 100644 --- a/internal/cmd/base/format.go +++ b/internal/cmd/base/format.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "os" + "sort" "strings" "unicode" "unicode/utf8" @@ -45,24 +46,40 @@ func WrapForHelpText(lines []string) string { return strings.Join(ret, "\n") } +func WrapSlice(prefixSpaces int, input []string) string { + var ret []string + for _, v := range input { + ret = append(ret, fmt.Sprintf("%s%s", + strings.Repeat(" ", prefixSpaces), + fmt.Sprintf("%s: ", v), + )) + } + + return strings.Join(ret, "\n") +} + func WrapMap(prefixSpaces, maxLengthOverride int, input map[string]interface{}) string { maxKeyLength := maxLengthOverride + var sortedKeys []string if maxKeyLength == 0 { for k := range input { + sortedKeys = append(sortedKeys, k) if len(k) > maxKeyLength { maxKeyLength = len(k) } } } + sort.Strings(sortedKeys) var ret []string - for k, v := range input { + for _, k := range sortedKeys { + v := input[k] spaces := maxKeyLength - len(k) ret = append(ret, fmt.Sprintf("%s%s%s%s", strings.Repeat(" ", prefixSpaces), fmt.Sprintf("%s: ", k), strings.Repeat(" ", spaces), - fmt.Sprintf("%v", v)), - ) + fmt.Sprintf("%v", v), + )) } return strings.Join(ret, "\n") diff --git a/internal/cmd/commands.go b/internal/cmd/commands.go index 64f9756913..206915708f 100644 --- a/internal/cmd/commands.go +++ b/internal/cmd/commands.go @@ -15,6 +15,7 @@ import ( "github.com/hashicorp/boundary/internal/cmd/commands/groups" "github.com/hashicorp/boundary/internal/cmd/commands/hostcatalogs" "github.com/hashicorp/boundary/internal/cmd/commands/hosts" + "github.com/hashicorp/boundary/internal/cmd/commands/hostsets" "github.com/hashicorp/boundary/internal/cmd/commands/roles" "github.com/hashicorp/boundary/internal/cmd/commands/scopes" "github.com/hashicorp/boundary/internal/cmd/commands/users" @@ -252,6 +253,49 @@ func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) { }, nil }, + "host-sets": func() (cli.Command, error) { + return &hostsets.Command{ + Command: base.NewCommand(ui), + }, nil + }, + "host-sets read": func() (cli.Command, error) { + return &hostsets.Command{ + Command: base.NewCommand(ui), + Func: "read", + }, nil + }, + "host-sets delete": func() (cli.Command, error) { + return &hostsets.Command{ + Command: base.NewCommand(ui), + Func: "delete", + }, nil + }, + "host-sets list": func() (cli.Command, error) { + return &hostsets.Command{ + Command: base.NewCommand(ui), + Func: "list", + }, nil + }, + "host-sets static": func() (cli.Command, error) { + return &hostsets.Command{ + Command: base.NewCommand(ui), + Func: "static", + }, nil + }, + "host-sets static create": func() (cli.Command, error) { + return &hostsets.StaticCommand{ + Command: base.NewCommand(ui), + Func: "create", + }, nil + }, + + "host-sets static update": func() (cli.Command, error) { + return &hostsets.StaticCommand{ + Command: base.NewCommand(ui), + Func: "update", + }, nil + }, + "hosts create": func() (cli.Command, error) { return &hosts.CreateCommand{ Command: base.NewCommand(ui), diff --git a/internal/cmd/commands/authenticate/password.go b/internal/cmd/commands/authenticate/password.go index 1eb490b5d5..f2154d7b59 100644 --- a/internal/cmd/commands/authenticate/password.go +++ b/internal/cmd/commands/authenticate/password.go @@ -136,9 +136,9 @@ func (c *PasswordCommand) Run(args []string) int { c.UI.Output(base.WrapForHelpText([]string{ "", "Authentication information:", + fmt.Sprintf(" Expiration Time: %s", result.ExpirationTime.Local().Format(time.RFC3339)), fmt.Sprintf(" Token: %s", result.Token), fmt.Sprintf(" User ID: %s", result.UserId), - fmt.Sprintf(" Expiration Time: %s", result.ExpirationTime.Local().Format(time.RFC3339)), })) } diff --git a/internal/cmd/commands/authmethods/authmethod.go b/internal/cmd/commands/authmethods/authmethod.go index d0005eecfc..f9507369e6 100644 --- a/internal/cmd/commands/authmethods/authmethod.go +++ b/internal/cmd/commands/authmethods/authmethod.go @@ -204,8 +204,11 @@ func (c *Command) Run(args []string) int { if true { output = append(output, fmt.Sprintf(" ID: %s", m.Id), - fmt.Sprintf(" Version: %d", m.Version), - fmt.Sprintf(" Type: %s", m.Type), + ) + } + if m.Description != "" { + output = append(output, + fmt.Sprintf(" Description: %s", m.Description), ) } if m.Name != "" { @@ -213,9 +216,10 @@ func (c *Command) Run(args []string) int { fmt.Sprintf(" Name: %s", m.Name), ) } - if m.Description != "" { + if true { output = append(output, - fmt.Sprintf(" Description: %s", m.Description), + fmt.Sprintf(" Type: %s", m.Type), + fmt.Sprintf(" Version: %d", m.Version), ) } } diff --git a/internal/cmd/commands/authtokens/authtokens.go b/internal/cmd/commands/authtokens/authtokens.go index 7b63ff7a1d..561b7d800b 100644 --- a/internal/cmd/commands/authtokens/authtokens.go +++ b/internal/cmd/commands/authtokens/authtokens.go @@ -159,12 +159,12 @@ func (c *Command) Run(args []string) int { } output = append(output, fmt.Sprintf(" ID: %s", t.Id), - fmt.Sprintf(" Auth Method ID: %s", t.AuthMethodId), - fmt.Sprintf(" User ID: %s", t.UserId), - fmt.Sprintf(" Expiration Time: %s", t.ExpirationTime.Local().Format(time.RFC3339)), fmt.Sprintf(" Approximate Last Used Time: %s", t.ApproximateLastUsedTime.Local().Format(time.RFC3339)), + fmt.Sprintf(" Auth Method ID: %s", t.AuthMethodId), fmt.Sprintf(" Created Time: %s", t.CreatedTime.Local().Format(time.RFC3339)), + fmt.Sprintf(" Expiration Time: %s", t.ExpirationTime.Local().Format(time.RFC3339)), fmt.Sprintf(" Updated Time: %s", t.UpdatedTime.Local().Format(time.RFC3339)), + fmt.Sprintf(" User ID: %s", t.UserId), ) } c.UI.Output(base.WrapForHelpText(output)) diff --git a/internal/cmd/commands/authtokens/funcs.go b/internal/cmd/commands/authtokens/funcs.go index 1a7b6fc1f6..81b8493386 100644 --- a/internal/cmd/commands/authtokens/funcs.go +++ b/internal/cmd/commands/authtokens/funcs.go @@ -13,14 +13,14 @@ func generateAuthTokenTableOutput(in *authtokens.AuthToken) string { ret = append(ret, []string{ "", "Auth Token information:", - fmt.Sprintf(" ID: %s", in.Id), - fmt.Sprintf(" Scope ID: %s", in.Scope.Id), - fmt.Sprintf(" Auth Method ID: %s", in.AuthMethodId), - fmt.Sprintf(" User ID: %s", in.UserId), - fmt.Sprintf(" Expiration Time: %s", in.ExpirationTime.Local().Format(time.RFC3339)), fmt.Sprintf(" Approximate Last Used Time: %s", in.ApproximateLastUsedTime.Local().Format(time.RFC3339)), + fmt.Sprintf(" Auth Method ID: %s", in.AuthMethodId), fmt.Sprintf(" Created Time: %s", in.CreatedTime.Local().Format(time.RFC3339)), + fmt.Sprintf(" Expiration Time: %s", in.ExpirationTime.Local().Format(time.RFC3339)), + fmt.Sprintf(" ID: %s", in.Id), + fmt.Sprintf(" Scope ID: %s", in.Scope.Id), fmt.Sprintf(" Updated Time: %s", in.UpdatedTime.Local().Format(time.RFC3339)), + fmt.Sprintf(" User ID: %s", in.UserId), }..., ) diff --git a/internal/cmd/commands/groups/funcs.go b/internal/cmd/commands/groups/funcs.go index ce25e07bf6..adde48ffd6 100644 --- a/internal/cmd/commands/groups/funcs.go +++ b/internal/cmd/commands/groups/funcs.go @@ -70,38 +70,39 @@ func populateFlags(c *Command, f *base.FlagSet, flagNames []string) { } } -func generateGroupTableOutput(group *groups.Group) string { - var output []string - if true { - output = []string{ - "", - "Group information:", - fmt.Sprintf(" ID: %s", group.Id), - fmt.Sprintf(" Version: %d", group.Version), - fmt.Sprintf(" Created At: %s", group.CreatedTime.Local().Format(time.RFC3339)), - fmt.Sprintf(" Updated At: %s", group.UpdatedTime.Local().Format(time.RFC3339)), - } +func generateGroupTableOutput(in *groups.Group) string { + var ret []string + + nonAttributeMap := map[string]interface{}{ + "ID": in.Id, + "Version": in.Version, + "Created Time": in.CreatedTime.Local().Format(time.RFC3339), + "Updated Time": in.UpdatedTime.Local().Format(time.RFC3339), } - if group.Name != "" { - output = append(output, - fmt.Sprintf(" Name: %s", group.Name), - ) + + if in.Name != "" { + nonAttributeMap["Name"] = in.Name } - if group.Description != "" { - output = append(output, - fmt.Sprintf(" Description: %s", group.Description), - ) + if in.Description != "" { + nonAttributeMap["Description"] = in.Description } - if len(group.Members) > 0 { - output = append(output, + + ret = append(ret, "", "Group information:") + + ret = append(ret, + base.WrapMap(2, 0, nonAttributeMap), + ) + + if len(in.Members) > 0 { + ret = append(ret, fmt.Sprintf(" Members: %s", ""), ) } - for _, member := range group.Members { - output = append(output, + for _, member := range in.Members { + ret = append(ret, fmt.Sprintf(" ID: %s", member.Id), fmt.Sprintf(" Scope ID: %s", member.ScopeId), ) } - return base.WrapForHelpText(output) + return base.WrapForHelpText(ret) } diff --git a/internal/cmd/commands/hostsets/funcs.go b/internal/cmd/commands/hostsets/funcs.go new file mode 100644 index 0000000000..a58ea3ab7f --- /dev/null +++ b/internal/cmd/commands/hostsets/funcs.go @@ -0,0 +1,82 @@ +package hostsets + +import ( + "fmt" + "time" + + "github.com/hashicorp/boundary/api/hostsets" + "github.com/hashicorp/boundary/internal/cmd/base" +) + +func generateHostSetTableOutput(in *hostsets.HostSet) string { + var ret []string + + nonAttributeMap := map[string]interface{}{ + "ID": in.Id, + "Version": in.Version, + "Type": in.Type, + "Created Time": in.CreatedTime.Local().Format(time.RFC3339), + "Updated Time": in.UpdatedTime.Local().Format(time.RFC3339), + "Host Catalog ID": in.HostCatalogId, + } + + if in.Name != "" { + nonAttributeMap["Name"] = in.Name + } + if in.Description != "" { + nonAttributeMap["Description"] = in.Description + } + + maxLength := 0 + for k := range nonAttributeMap { + if len(k) > maxLength { + maxLength = len(k) + } + } + if len(in.Attributes) > 0 { + for k, v := range in.Attributes { + if attributeMap[k] != "" { + in.Attributes[attributeMap[k]] = v + delete(in.Attributes, k) + } + } + for k := range in.Attributes { + if len(k) > maxLength { + maxLength = len(k) + } + } + } + + ret = append(ret, "", "Host set information:") + + ret = append(ret, + // We do +2 because there is another +2 offset for attributes below + base.WrapMap(2, maxLength+2, nonAttributeMap), + ) + + if len(in.HostIds) > 0 { + if true { + ret = append(ret, + fmt.Sprintf(" Host IDs:"), + ) + } + ret = append(ret, + base.WrapSlice(4, in.HostIds), + ) + } + + if len(in.Attributes) > 0 { + if true { + ret = append(ret, + fmt.Sprintf(" Attributes: %s", ""), + ) + } + ret = append(ret, + base.WrapMap(4, maxLength, in.Attributes), + ) + } + + return base.WrapForHelpText(ret) +} + +var attributeMap = map[string]string{} diff --git a/internal/cmd/commands/hostsets/hostset.go b/internal/cmd/commands/hostsets/hostset.go new file mode 100644 index 0000000000..82d1cc6ad2 --- /dev/null +++ b/internal/cmd/commands/hostsets/hostset.go @@ -0,0 +1,249 @@ +package hostsets + +import ( + "fmt" + + "github.com/hashicorp/boundary/api" + "github.com/hashicorp/boundary/api/hostsets" + "github.com/hashicorp/boundary/internal/cmd/base" + "github.com/hashicorp/boundary/internal/cmd/common" + "github.com/hashicorp/boundary/internal/types/resource" + "github.com/hashicorp/vault/sdk/helper/strutil" + "github.com/kr/pretty" + "github.com/mitchellh/cli" + "github.com/posener/complete" +) + +var _ cli.Command = (*Command)(nil) +var _ cli.CommandAutocomplete = (*Command)(nil) + +type Command struct { + *base.Command + + Func string + + flagHostCatalogId string +} + +func (c *Command) Synopsis() string { + if c.Func == "static" { + return "Manage static host sets within Boundary" + } + return common.SynopsisFunc(c.Func, "host-set") +} + +var flagsMap = map[string][]string{ + "read": {"id"}, + "delete": {"id"}, +} + +func (c *Command) Help() string { + helpMap := common.HelpMap("host-set") + switch c.Func { + case "": + return base.WrapForHelpText([]string{ + "Usage: boundary host-sets [sub command] [options] [args]", + "", + " This command allows operations on Boundary host-set resources. Example:", + "", + " Read a host-set:", + "", + ` $ boundary host-sets read -id hsst_1234567890`, + "", + " Please see the host-sets subcommand help for detailed usage information.", + }) + case "static": + return base.WrapForHelpText([]string{ + "Usage: boundary host-sets static [sub command] [options] [args]", + "", + " This command allows operations on Boundary static-type host-set resources. Example:", + "", + " Create a static-type host-set:", + "", + ` $ boundary host-sets static create -name prodops -description "For ProdOps usage"`, + "", + " Please see the subcommand help for detailed usage information.", + }) + default: + return helpMap[c.Func]() + c.Flags().Help() + } +} + +func (c *Command) Flags() *base.FlagSets { + set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat) + + f := set.NewFlagSet("Command Options") + + if len(flagsMap[c.Func]) > 0 { + common.PopulateCommonFlags(c.Command, f, resource.HostSet.String(), flagsMap[c.Func]) + } + + f.StringVar(&base.StringVar{ + Name: "host-catalog-id", + Target: &c.flagHostCatalogId, + Usage: "The host-catalog resource in which to create or update the host-set resource", + }) + + return set +} + +func (c *Command) AutocompleteArgs() complete.Predictor { + return complete.PredictAnything +} + +func (c *Command) AutocompleteFlags() complete.Flags { + return c.Flags().Completions() +} + +func (c *Command) Run(args []string) int { + if c.Func == "" || c.Func == "static" { + return cli.RunResultHelp + } + + f := c.Flags() + + if err := f.Parse(args); err != nil { + c.UI.Error(err.Error()) + return 1 + } + + if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" { + c.UI.Error("ID is required but not passed in via -id") + return 1 + } + + client, err := c.Client() + if err != nil { + c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error())) + return 2 + } + + var opts []hostsets.Option + + switch c.FlagName { + case "": + case "null": + opts = append(opts, hostsets.DefaultName()) + default: + opts = append(opts, hostsets.WithName(c.FlagName)) + } + + switch c.FlagDescription { + case "": + case "null": + opts = append(opts, hostsets.DefaultDescription()) + default: + opts = append(opts, hostsets.WithDescription(c.FlagDescription)) + } + + hostsetClient := hostsets.NewClient(client) + + var existed bool + var set *hostsets.HostSet + var listedSets []*hostsets.HostSet + var apiErr *api.Error + + switch c.Func { + case "read": + set, apiErr, err = hostsetClient.Read(c.Context, c.flagHostCatalogId, c.FlagId, opts...) + case "delete": + existed, apiErr, err = hostsetClient.Delete(c.Context, c.flagHostCatalogId, c.FlagId, opts...) + case "list": + listedSets, apiErr, err = hostsetClient.List(c.Context, c.flagHostCatalogId, opts...) + } + + plural := "host set" + if c.Func == "list" { + plural = "host sets" + } + if err != nil { + c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error())) + return 2 + } + if apiErr != nil { + c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, pretty.Sprint(apiErr))) + return 1 + } + + switch c.Func { + case "delete": + switch base.Format(c.UI) { + case "json": + c.UI.Output("null") + case "table": + output := "The delete operation completed successfully" + switch existed { + case true: + output += "." + default: + output += ", however the resource did not exist at the time." + } + c.UI.Output(output) + } + return 0 + + case "list": + switch base.Format(c.UI) { + case "json": + if len(listedSets) == 0 { + c.UI.Output("null") + return 0 + } + b, err := base.JsonFormatter{}.Format(listedSets) + if err != nil { + c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error()) + return 1 + } + c.UI.Output(string(b)) + + case "table": + if len(listedSets) == 0 { + c.UI.Output("No host sets found") + return 0 + } + var output []string + output = []string{ + "", + "Host Set information:", + } + for i, m := range listedSets { + if i > 0 { + output = append(output, "") + } + if true { + output = append(output, + fmt.Sprintf(" ID: %s", m.Id), + fmt.Sprintf(" Version: %d", m.Version), + fmt.Sprintf(" Type: %s", m.Type), + ) + } + if m.Name != "" { + output = append(output, + fmt.Sprintf(" Name: %s", m.Name), + ) + } + if m.Description != "" { + output = append(output, + fmt.Sprintf(" Description: %s", m.Description), + ) + } + } + c.UI.Output(base.WrapForHelpText(output)) + } + return 0 + } + + switch base.Format(c.UI) { + case "table": + c.UI.Output(generateHostSetTableOutput(set)) + case "json": + b, err := base.JsonFormatter{}.Format(set) + if err != nil { + c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error()) + return 1 + } + c.UI.Output(string(b)) + } + + return 0 +} diff --git a/internal/cmd/commands/hostsets/static.go b/internal/cmd/commands/hostsets/static.go new file mode 100644 index 0000000000..06b1155b7b --- /dev/null +++ b/internal/cmd/commands/hostsets/static.go @@ -0,0 +1,186 @@ +package hostsets + +import ( + "fmt" + "net/textproto" + + "github.com/hashicorp/boundary/api" + "github.com/hashicorp/boundary/api/hostsets" + "github.com/hashicorp/boundary/internal/cmd/base" + "github.com/hashicorp/boundary/internal/cmd/common" + "github.com/hashicorp/vault/sdk/helper/strutil" + "github.com/kr/pretty" + "github.com/mitchellh/cli" + "github.com/posener/complete" +) + +var _ cli.Command = (*StaticCommand)(nil) +var _ cli.CommandAutocomplete = (*StaticCommand)(nil) + +type StaticCommand struct { + *base.Command + + Func string + + flagHostCatalogId string +} + +func (c *StaticCommand) Synopsis() string { + return fmt.Sprintf("%s a static-type host-set within Boundary", textproto.CanonicalMIMEHeaderKey(c.Func)) +} + +var staticFlagsMap = map[string][]string{ + "create": {"name", "description"}, + "update": {"id", "name", "description", "version"}, +} + +func (c *StaticCommand) Help() string { + var info string + switch c.Func { + case "create": + info = base.WrapForHelpText([]string{ + "Usage: boundary host-sets static create [options] [args]", + "", + " Create a static-type host-set. Example:", + "", + ` $ boundary host-sets static create -name prodops -description "Static host-set for ProdOps"`, + "", + "", + }) + + case "update": + info = base.WrapForHelpText([]string{ + "Usage: boundary host-sets static update [options] [args]", + "", + " Update a static-type host-set given its ID. Example:", + "", + ` $ boundary host-sets static update -id hsst_1234567890 -name "devops" -description "Static host-set for DevOps"`, + "", + "", + }) + } + return info + c.Flags().Help() +} + +func (c *StaticCommand) Flags() *base.FlagSets { + set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat) + + f := set.NewFlagSet("Command Options") + + if len(staticFlagsMap[c.Func]) > 0 { + common.PopulateCommonFlags(c.Command, f, "static-type host-set", staticFlagsMap[c.Func]) + } + + f.StringVar(&base.StringVar{ + Name: "host-catalog-id", + Target: &c.flagHostCatalogId, + Usage: "The host-catalog resource in which to create or update the host-set resource", + }) + + return set +} + +func (c *StaticCommand) AutocompleteArgs() complete.Predictor { + return complete.PredictAnything +} + +func (c *StaticCommand) AutocompleteFlags() complete.Flags { + return c.Flags().Completions() +} + +func (c *StaticCommand) Run(args []string) int { + if c.Func == "" { + return cli.RunResultHelp + } + + f := c.Flags() + + if err := f.Parse(args); err != nil { + c.UI.Error(err.Error()) + return 1 + } + + if strutil.StrListContains(staticFlagsMap[c.Func], "id") && c.FlagId == "" { + c.UI.Error("ID is required but not passed in via -id") + return 1 + } + + if c.flagHostCatalogId == "" { + c.UI.Error("Host Catalog ID must be passed in via -host-catalog-id") + return 1 + } + + client, err := c.Client() + if err != nil { + c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error())) + return 2 + } + + var opts []hostsets.Option + + switch c.FlagName { + case "": + case "null": + opts = append(opts, hostsets.DefaultName()) + default: + opts = append(opts, hostsets.WithName(c.FlagName)) + } + + switch c.FlagDescription { + case "": + case "null": + opts = append(opts, hostsets.DefaultDescription()) + default: + opts = append(opts, hostsets.WithDescription(c.FlagDescription)) + } + + hostsetClient := hostsets.NewClient(client) + + // Perform check-and-set when needed + var version uint32 + switch c.Func { + case "create": + // These don't update so don't need the existing version + default: + switch c.FlagVersion { + case 0: + opts = append(opts, hostsets.WithAutomaticVersioning()) + default: + version = uint32(c.FlagVersion) + } + } + + var set *hostsets.HostSet + var apiErr *api.Error + + switch c.Func { + case "create": + set, apiErr, err = hostsetClient.Create(c.Context, c.flagHostCatalogId, opts...) + case "update": + set, apiErr, err = hostsetClient.Update(c.Context, c.flagHostCatalogId, c.FlagId, version, opts...) + } + + plural := "static-type host-set" + if err != nil { + c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error())) + return 2 + } + if apiErr != nil { + c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, pretty.Sprint(apiErr))) + return 1 + } + + switch base.Format(c.UI) { + case "table": + c.UI.Output(generateHostSetTableOutput(set)) + case "json": + b, err := base.JsonFormatter{}.Format(set) + if err != nil { + c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error()) + return 1 + } + c.UI.Output(string(b)) + } + + return 0 +} diff --git a/internal/cmd/commands/roles/funcs.go b/internal/cmd/commands/roles/funcs.go index d28c9468ef..befdae0d58 100644 --- a/internal/cmd/commands/roles/funcs.go +++ b/internal/cmd/commands/roles/funcs.go @@ -86,55 +86,54 @@ func populateFlags(c *Command, f *base.FlagSet, flagNames []string) { } } -func generateRoleTableOutput(role *roles.Role) string { - var output []string - if true { - output = []string{ - "", - "Role information:", - fmt.Sprintf(" ID: %s", role.Id), - fmt.Sprintf(" Version: %d", role.Version), - fmt.Sprintf(" Created At: %s", role.CreatedTime.Local().Format(time.RFC3339)), - fmt.Sprintf(" Updated At: %s", role.UpdatedTime.Local().Format(time.RFC3339)), - } +func generateRoleTableOutput(in *roles.Role) string { + var ret []string + + nonAttributeMap := map[string]interface{}{ + "ID": in.Id, + "Version": in.Version, + "Created Time": in.CreatedTime.Local().Format(time.RFC3339), + "Updated Time": in.UpdatedTime.Local().Format(time.RFC3339), } - if role.Name != "" { - output = append(output, - fmt.Sprintf(" Name: %s", role.Name), - ) + + if in.Name != "" { + nonAttributeMap["Name"] = in.Name } - if role.Description != "" { - output = append(output, - fmt.Sprintf(" Description: %s", role.Description), - ) + if in.Description != "" { + nonAttributeMap["Description"] = in.Description } - if role.GrantScopeId != "" { - output = append(output, - fmt.Sprintf(" Grant Scope ID: %s", role.GrantScopeId), - ) + if in.GrantScopeId != "" { + nonAttributeMap["Grant Scope ID"] = in.GrantScopeId } - if len(role.Principals) > 0 { - output = append(output, + + ret = append(ret, "", "Role information:") + + ret = append(ret, + base.WrapMap(2, 0, nonAttributeMap), + ) + + if len(in.Principals) > 0 { + ret = append(ret, fmt.Sprintf(" Principals: %s", ""), ) } - for _, principal := range role.Principals { - output = append(output, + for _, principal := range in.Principals { + ret = append(ret, fmt.Sprintf(" ID: %s", principal.Id), fmt.Sprintf(" Type: %s", principal.Type), fmt.Sprintf(" Scope ID: %s", principal.ScopeId), ) } - if len(role.Grants) > 0 { - output = append(output, + if len(in.Grants) > 0 { + ret = append(ret, fmt.Sprintf(" Canonical Grants: %s", ""), ) } - for _, grant := range role.Grants { - output = append(output, + for _, grant := range in.Grants { + ret = append(ret, fmt.Sprintf(" %s", grant.Canonical), ) } - return base.WrapForHelpText(output) + return base.WrapForHelpText(ret) } diff --git a/internal/cmd/commands/scopes/funcs.go b/internal/cmd/commands/scopes/funcs.go index a8ddeaba56..a4007821b8 100644 --- a/internal/cmd/commands/scopes/funcs.go +++ b/internal/cmd/commands/scopes/funcs.go @@ -1,7 +1,6 @@ package scopes import ( - "fmt" "time" "github.com/hashicorp/boundary/api/scopes" @@ -10,28 +9,26 @@ import ( func generateScopeTableOutput(in *scopes.Scope) string { var ret []string - // This if true is here to line up columns for easy editing - if true { - ret = append(ret, []string{ - "", - "Scope information:", - fmt.Sprintf(" ID: %s", in.Id), - fmt.Sprintf(" Version: %d", in.Version), - fmt.Sprintf(" Created Time: %s", in.CreatedTime.Local().Format(time.RFC3339)), - fmt.Sprintf(" Updated Time: %s", in.UpdatedTime.Local().Format(time.RFC3339)), - }..., - ) + + nonAttributeMap := map[string]interface{}{ + "ID": in.Id, + "Version": in.Version, + "Created Time": in.CreatedTime.Local().Format(time.RFC3339), + "Updated Time": in.UpdatedTime.Local().Format(time.RFC3339), } + if in.Name != "" { - ret = append(ret, - fmt.Sprintf(" Name: %s", in.Name), - ) + nonAttributeMap["Name"] = in.Name } if in.Description != "" { - ret = append(ret, - fmt.Sprintf(" Description: %s", in.Description), - ) + nonAttributeMap["Description"] = in.Description } + ret = append(ret, "", "Scope information:") + + ret = append(ret, + base.WrapMap(2, 0, nonAttributeMap), + ) + return base.WrapForHelpText(ret) } diff --git a/internal/cmd/commands/users/funcs.go b/internal/cmd/commands/users/funcs.go index 3b4e4e8d85..85f896242c 100644 --- a/internal/cmd/commands/users/funcs.go +++ b/internal/cmd/commands/users/funcs.go @@ -1,7 +1,6 @@ package users import ( - "fmt" "time" "github.com/hashicorp/boundary/api/users" @@ -10,28 +9,26 @@ import ( func generateUserTableOutput(in *users.User) string { var ret []string - // This if true is here to line up columns for easy editing - if true { - ret = append(ret, []string{ - "", - "User information:", - fmt.Sprintf(" ID: %s", in.Id), - fmt.Sprintf(" Version: %d", in.Version), - fmt.Sprintf(" Created Time: %s", in.CreatedTime.Local().Format(time.RFC3339)), - fmt.Sprintf(" Updated Time: %s", in.UpdatedTime.Local().Format(time.RFC3339)), - }..., - ) + + nonAttributeMap := map[string]interface{}{ + "ID": in.Id, + "Version": in.Version, + "Created Time": in.CreatedTime.Local().Format(time.RFC3339), + "Updated Time": in.UpdatedTime.Local().Format(time.RFC3339), } + if in.Name != "" { - ret = append(ret, - fmt.Sprintf(" Name: %s", in.Name), - ) + nonAttributeMap["Name"] = in.Name } if in.Description != "" { - ret = append(ret, - fmt.Sprintf(" Description: %s", in.Description), - ) + nonAttributeMap["Description"] = in.Description } + ret = append(ret, "", "User information:") + + ret = append(ret, + base.WrapMap(2, 0, nonAttributeMap), + ) + return base.WrapForHelpText(ret) }