github.com/stefanmcshane/helm@v0.0.0-20221213002717-88a4a2c6e77d/cmd/helm/status.go (about) 1 /* 2 Copyright The Helm Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package main 18 19 import ( 20 "fmt" 21 "io" 22 "log" 23 "strings" 24 "time" 25 26 "github.com/spf13/cobra" 27 28 "github.com/stefanmcshane/helm/cmd/helm/require" 29 "github.com/stefanmcshane/helm/pkg/action" 30 "github.com/stefanmcshane/helm/pkg/chartutil" 31 "github.com/stefanmcshane/helm/pkg/cli/output" 32 "github.com/stefanmcshane/helm/pkg/release" 33 ) 34 35 // NOTE: Keep the list of statuses up-to-date with pkg/release/status.go. 36 var statusHelp = ` 37 This command shows the status of a named release. 38 The status consists of: 39 - last deployment time 40 - k8s namespace in which the release lives 41 - state of the release (can be: unknown, deployed, uninstalled, superseded, failed, uninstalling, pending-install, pending-upgrade or pending-rollback) 42 - revision of the release 43 - description of the release (can be completion message or error message, need to enable --show-desc) 44 - list of resources that this release consists of, sorted by kind 45 - details on last test suite run, if applicable 46 - additional notes provided by the chart 47 ` 48 49 func newStatusCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { 50 client := action.NewStatus(cfg) 51 var outfmt output.Format 52 53 cmd := &cobra.Command{ 54 Use: "status RELEASE_NAME", 55 Short: "display the status of the named release", 56 Long: statusHelp, 57 Args: require.ExactArgs(1), 58 ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { 59 if len(args) != 0 { 60 return nil, cobra.ShellCompDirectiveNoFileComp 61 } 62 return compListReleases(toComplete, args, cfg) 63 }, 64 RunE: func(cmd *cobra.Command, args []string) error { 65 rel, err := client.Run(args[0]) 66 if err != nil { 67 return err 68 } 69 70 // strip chart metadata from the output 71 rel.Chart = nil 72 73 return outfmt.Write(out, &statusPrinter{rel, false, client.ShowDescription}) 74 }, 75 } 76 77 f := cmd.Flags() 78 79 f.IntVar(&client.Version, "revision", 0, "if set, display the status of the named release with revision") 80 81 err := cmd.RegisterFlagCompletionFunc("revision", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { 82 if len(args) == 1 { 83 return compListRevisions(toComplete, cfg, args[0]) 84 } 85 return nil, cobra.ShellCompDirectiveNoFileComp 86 }) 87 88 if err != nil { 89 log.Fatal(err) 90 } 91 92 bindOutputFlag(cmd, &outfmt) 93 f.BoolVar(&client.ShowDescription, "show-desc", false, "if set, display the description message of the named release") 94 95 return cmd 96 } 97 98 type statusPrinter struct { 99 release *release.Release 100 debug bool 101 showDescription bool 102 } 103 104 func (s statusPrinter) WriteJSON(out io.Writer) error { 105 return output.EncodeJSON(out, s.release) 106 } 107 108 func (s statusPrinter) WriteYAML(out io.Writer) error { 109 return output.EncodeYAML(out, s.release) 110 } 111 112 func (s statusPrinter) WriteTable(out io.Writer) error { 113 if s.release == nil { 114 return nil 115 } 116 fmt.Fprintf(out, "NAME: %s\n", s.release.Name) 117 if !s.release.Info.LastDeployed.IsZero() { 118 fmt.Fprintf(out, "LAST DEPLOYED: %s\n", s.release.Info.LastDeployed.Format(time.ANSIC)) 119 } 120 fmt.Fprintf(out, "NAMESPACE: %s\n", s.release.Namespace) 121 fmt.Fprintf(out, "STATUS: %s\n", s.release.Info.Status.String()) 122 fmt.Fprintf(out, "REVISION: %d\n", s.release.Version) 123 if s.showDescription { 124 fmt.Fprintf(out, "DESCRIPTION: %s\n", s.release.Info.Description) 125 } 126 127 executions := executionsByHookEvent(s.release) 128 if tests, ok := executions[release.HookTest]; !ok || len(tests) == 0 { 129 fmt.Fprintln(out, "TEST SUITE: None") 130 } else { 131 for _, h := range tests { 132 // Don't print anything if hook has not been initiated 133 if h.LastRun.StartedAt.IsZero() { 134 continue 135 } 136 fmt.Fprintf(out, "TEST SUITE: %s\n%s\n%s\n%s\n", 137 h.Name, 138 fmt.Sprintf("Last Started: %s", h.LastRun.StartedAt.Format(time.ANSIC)), 139 fmt.Sprintf("Last Completed: %s", h.LastRun.CompletedAt.Format(time.ANSIC)), 140 fmt.Sprintf("Phase: %s", h.LastRun.Phase), 141 ) 142 } 143 } 144 145 if s.debug { 146 fmt.Fprintln(out, "USER-SUPPLIED VALUES:") 147 err := output.EncodeYAML(out, s.release.Config) 148 if err != nil { 149 return err 150 } 151 // Print an extra newline 152 fmt.Fprintln(out) 153 154 cfg, err := chartutil.CoalesceValues(s.release.Chart, s.release.Config) 155 if err != nil { 156 return err 157 } 158 159 fmt.Fprintln(out, "COMPUTED VALUES:") 160 err = output.EncodeYAML(out, cfg.AsMap()) 161 if err != nil { 162 return err 163 } 164 // Print an extra newline 165 fmt.Fprintln(out) 166 } 167 168 if strings.EqualFold(s.release.Info.Description, "Dry run complete") || s.debug { 169 fmt.Fprintln(out, "HOOKS:") 170 for _, h := range s.release.Hooks { 171 fmt.Fprintf(out, "---\n# Source: %s\n%s\n", h.Path, h.Manifest) 172 } 173 fmt.Fprintf(out, "MANIFEST:\n%s\n", s.release.Manifest) 174 } 175 176 if len(s.release.Info.Notes) > 0 { 177 fmt.Fprintf(out, "NOTES:\n%s\n", strings.TrimSpace(s.release.Info.Notes)) 178 } 179 return nil 180 } 181 182 func executionsByHookEvent(rel *release.Release) map[release.HookEvent][]*release.Hook { 183 result := make(map[release.HookEvent][]*release.Hook) 184 for _, h := range rel.Hooks { 185 for _, e := range h.Events { 186 executions, ok := result[e] 187 if !ok { 188 executions = []*release.Hook{} 189 } 190 result[e] = append(executions, h) 191 } 192 } 193 return result 194 }