From eabd30c51096cd36e8530d27d1b69d163f777d4a Mon Sep 17 00:00:00 2001 From: Jessica Yuen <im.jessicayuen@gmail.com> Date: Thu, 2 Nov 2017 12:42:24 -0700 Subject: [PATCH] Introduce command: 'ks param list [component] [--env=<env>]' Pretty prints component or environment parameters. This command will display all parameters for the component specified. If a component is not specified, parameters for all components will be listed. Furthermore, parameters can be listed on a per-environment basis. Examples: List all component parameters ks param list List all parameters for the component "guestbook" ks param list guestbook List all parameters for the environment "dev" ks param list --env=dev List all parameters for the component "guestbook" in the environment "dev" ks param list guestbook --env=dev`, --- cmd/param.go | 45 ++++++++++++ pkg/kubecfg/param.go | 167 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 212 insertions(+) diff --git a/cmd/param.go b/cmd/param.go index 6679ff6f..af41950c 100644 --- a/cmd/param.go +++ b/cmd/param.go @@ -31,8 +31,10 @@ func init() { RootCmd.AddCommand(paramCmd) paramCmd.AddCommand(paramSetCmd) + paramCmd.AddCommand(paramListCmd) paramSetCmd.PersistentFlags().String(flagParamEnv, "", "Specify environment to set parameters for") + paramListCmd.PersistentFlags().String(flagParamEnv, "", "Specify environment to list parameters for") } var paramCmd = &cobra.Command{ @@ -93,3 +95,46 @@ of environment parameters, we suggest modifying the # 'dev' ks param set guestbook replicas 2 --env=dev`, } + +var paramListCmd = &cobra.Command{ + Use: "list [component-name]", + Short: "List all parameters for a component(s)", + RunE: func(cmd *cobra.Command, args []string) error { + flags := cmd.Flags() + if len(args) > 1 { + return fmt.Errorf("'param list' takes at most one argument, that is the name of the component") + } + + component := "" + if len(args) == 1 { + component = args[0] + } + + env, err := flags.GetString(flagParamEnv) + if err != nil { + return err + } + + c := kubecfg.NewParamListCmd(component, env) + + return c.Run(cmd.OutOrStdout()) + }, + Long: `"List all component parameters or environment parameters. + +This command will display all parameters for the component specified. If a +component is not specified, parameters for all components will be listed. + +Furthermore, parameters can be listed on a per-environment basis. +`, + Example: ` # List all component parameters + ks param list + + # List all parameters for the component "guestbook" + ks param list guestbook + + # List all parameters for the environment "dev" + ks param list --env=dev + + # List all parameters for the component "guestbook" in the environment "dev" + ks param list guestbook --env=dev`, +} diff --git a/pkg/kubecfg/param.go b/pkg/kubecfg/param.go index e06e2ae7..3ddfb07d 100644 --- a/pkg/kubecfg/param.go +++ b/pkg/kubecfg/param.go @@ -17,11 +17,38 @@ package kubecfg import ( "fmt" + "io" + "sort" "strconv" + "strings" + + param "github.com/ksonnet/ksonnet/metadata/params" log "github.com/sirupsen/logrus" ) +func sortedKeys(params map[string]param.Params) []string { + // keys maintains an alphabetically sorted list of the components + keys := make([]string, 0, len(params)) + for key := range params { + keys = append(keys, key) + } + sort.Strings(keys) + return keys +} + +func sortedParams(params param.Params) []string { + // keys maintains an alphabetically sorted list of the params + keys := make([]string, 0, len(params)) + for key := range params { + keys = append(keys, key) + } + sort.Strings(keys) + return keys +} + +// ---------------------------------------------------------------------------- + // ParamSetCmd stores the information necessary to set component and // environment params. type ParamSetCmd struct { @@ -73,3 +100,143 @@ func sanitizeParamValue(value string) string { // string return fmt.Sprintf(`"%s"`, value) } + +// ---------------------------------------------------------------------------- + +const ( + paramComponentHeader = "COMPONENT" + paramNameHeader = "PARAM" + paramValueHeader = "VALUE" +) + +// ParamListCmd stores the information necessary display component or +// environment parameters +type ParamListCmd struct { + component string + env string +} + +// NewParamListCmd acts as a constructor for ParamListCmd. +func NewParamListCmd(component, env string) *ParamListCmd { + return &ParamListCmd{component: component, env: env} +} + +// Run executes the displaying of params. +func (c *ParamListCmd) Run(out io.Writer) error { + manager, err := manager() + if err != nil { + return err + } + + var params map[string]param.Params + if len(c.env) != 0 { + params, err = manager.GetEnvironmentParams(c.env) + if err != nil { + return err + } + } else { + params, err = manager.GetAllComponentParams() + if err != nil { + return err + } + } + + if len(c.component) != 0 { + if _, ok := params[c.component]; !ok { + return fmt.Errorf("No such component '%s' found", c.component) + } + + p := params[c.component] + return outputParamsFor(c.component, p, out) + } + + return outputParams(params, out) +} + +func outputParamsFor(component string, params param.Params, out io.Writer) error { + keys := sortedParams(params) + + // + // Format each parameter information for pretty printing. + // Each parameter will be outputted alphabetically like the following: + // + // PARAM VALUE + // name "foo" + // replicas 1 + // + + maxParamLen := len(paramNameHeader) + for _, k := range keys { + if l := len(k); l > maxParamLen { + maxParamLen = l + } + } + + nameSpacing := strings.Repeat(" ", maxParamLen-len(paramNameHeader)+1) + + lines := []string{} + lines = append(lines, paramNameHeader+nameSpacing+paramValueHeader+"\n") + lines = append(lines, strings.Repeat("=", len(paramNameHeader))+nameSpacing+ + strings.Repeat("=", len(paramValueHeader))+"\n") + + for _, k := range keys { + nameSpacing = strings.Repeat(" ", maxParamLen-len(k)+1) + lines = append(lines, k+nameSpacing+params[k]+"\n") + } + + _, err := fmt.Fprint(out, strings.Join(lines, "")) + return err +} + +func outputParams(params map[string]param.Params, out io.Writer) error { + keys := sortedKeys(params) + + // + // Format each component parameter information for pretty printing. + // Each component will be outputted alphabetically like the following: + // + // COMPONENT PARAM VALUE + // bar name "bar" + // bar replicas 2 + // foo name "foo" + // foo replicas 1 + // + + maxComponentLen := len(paramComponentHeader) + for _, k := range keys { + if l := len(k); l > maxComponentLen { + maxComponentLen = l + } + } + + maxParamLen := len(paramNameHeader) + maxComponentLen + 1 + for _, k := range keys { + for p := range params[k] { + if l := len(p) + maxComponentLen + 1; l > maxParamLen { + maxParamLen = l + } + } + } + + componentSpacing := strings.Repeat(" ", maxComponentLen-len(paramComponentHeader)+1) + nameSpacing := strings.Repeat(" ", maxParamLen-maxComponentLen-len(paramNameHeader)) + + lines := []string{} + lines = append(lines, paramComponentHeader+componentSpacing+paramNameHeader+nameSpacing+paramValueHeader+"\n") + lines = append(lines, strings.Repeat("=", len(paramComponentHeader))+componentSpacing+ + strings.Repeat("=", len(paramNameHeader))+nameSpacing+strings.Repeat("=", len(paramValueHeader))+"\n") + + for _, k := range keys { + // sort params to display alphabetically + ps := sortedParams(params[k]) + + for _, p := range ps { + componentSpacing = strings.Repeat(" ", maxComponentLen-len(k)+1) + nameSpacing = strings.Repeat(" ", maxParamLen-maxComponentLen-len(p)) + lines = append(lines, k+componentSpacing+p+nameSpacing+params[k][p]+"\n") + } + } + + _, err := fmt.Fprint(out, strings.Join(lines, "")) + return err +} -- GitLab