github.com/Beeketing/helm@v2.12.1+incompatible/cmd/helm/history.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 "encoding/json" 21 "fmt" 22 "io" 23 24 "github.com/ghodss/yaml" 25 "github.com/gosuri/uitable" 26 "github.com/spf13/cobra" 27 28 "k8s.io/helm/pkg/helm" 29 "k8s.io/helm/pkg/proto/hapi/chart" 30 "k8s.io/helm/pkg/proto/hapi/release" 31 "k8s.io/helm/pkg/timeconv" 32 ) 33 34 type releaseInfo struct { 35 Revision int32 `json:"revision"` 36 Updated string `json:"updated"` 37 Status string `json:"status"` 38 Chart string `json:"chart"` 39 Description string `json:"description"` 40 } 41 42 type releaseHistory []releaseInfo 43 44 var historyHelp = ` 45 History prints historical revisions for a given release. 46 47 A default maximum of 256 revisions will be returned. Setting '--max' 48 configures the maximum length of the revision list returned. 49 50 The historical release set is printed as a formatted table, e.g: 51 52 $ helm history angry-bird --max=4 53 REVISION UPDATED STATUS CHART DESCRIPTION 54 1 Mon Oct 3 10:15:13 2016 SUPERSEDED alpine-0.1.0 Initial install 55 2 Mon Oct 3 10:15:13 2016 SUPERSEDED alpine-0.1.0 Upgraded successfully 56 3 Mon Oct 3 10:15:13 2016 SUPERSEDED alpine-0.1.0 Rolled back to 2 57 4 Mon Oct 3 10:15:13 2016 DEPLOYED alpine-0.1.0 Upgraded successfully 58 ` 59 60 type historyCmd struct { 61 max int32 62 rls string 63 out io.Writer 64 helmc helm.Interface 65 colWidth uint 66 outputFormat string 67 } 68 69 func newHistoryCmd(c helm.Interface, w io.Writer) *cobra.Command { 70 his := &historyCmd{out: w, helmc: c} 71 72 cmd := &cobra.Command{ 73 Use: "history [flags] RELEASE_NAME", 74 Long: historyHelp, 75 Short: "fetch release history", 76 Aliases: []string{"hist"}, 77 PreRunE: func(_ *cobra.Command, _ []string) error { return setupConnection() }, 78 RunE: func(cmd *cobra.Command, args []string) error { 79 switch { 80 case len(args) == 0: 81 return errReleaseRequired 82 case his.helmc == nil: 83 his.helmc = newClient() 84 } 85 his.rls = args[0] 86 return his.run() 87 }, 88 } 89 90 f := cmd.Flags() 91 settings.AddFlagsTLS(f) 92 f.Int32Var(&his.max, "max", 256, "maximum number of revision to include in history") 93 f.UintVar(&his.colWidth, "col-width", 60, "specifies the max column width of output") 94 f.StringVarP(&his.outputFormat, "output", "o", "table", "prints the output in the specified format (json|table|yaml)") 95 96 // set defaults from environment 97 settings.InitTLS(f) 98 99 return cmd 100 } 101 102 func (cmd *historyCmd) run() error { 103 r, err := cmd.helmc.ReleaseHistory(cmd.rls, helm.WithMaxHistory(cmd.max)) 104 if err != nil { 105 return prettyError(err) 106 } 107 if len(r.Releases) == 0 { 108 return nil 109 } 110 111 releaseHistory := getReleaseHistory(r.Releases) 112 113 var history []byte 114 var formattingError error 115 116 switch cmd.outputFormat { 117 case "yaml": 118 history, formattingError = yaml.Marshal(releaseHistory) 119 case "json": 120 history, formattingError = json.Marshal(releaseHistory) 121 case "table": 122 history = formatAsTable(releaseHistory, cmd.colWidth) 123 default: 124 return fmt.Errorf("unknown output format %q", cmd.outputFormat) 125 } 126 127 if formattingError != nil { 128 return prettyError(formattingError) 129 } 130 131 fmt.Fprintln(cmd.out, string(history)) 132 return nil 133 } 134 135 func getReleaseHistory(rls []*release.Release) (history releaseHistory) { 136 for i := len(rls) - 1; i >= 0; i-- { 137 r := rls[i] 138 c := formatChartname(r.Chart) 139 t := timeconv.String(r.Info.LastDeployed) 140 s := r.Info.Status.Code.String() 141 v := r.Version 142 d := r.Info.Description 143 144 rInfo := releaseInfo{ 145 Revision: v, 146 Updated: t, 147 Status: s, 148 Chart: c, 149 Description: d, 150 } 151 history = append(history, rInfo) 152 } 153 154 return history 155 } 156 157 func formatAsTable(releases releaseHistory, colWidth uint) []byte { 158 tbl := uitable.New() 159 160 tbl.MaxColWidth = colWidth 161 tbl.AddRow("REVISION", "UPDATED", "STATUS", "CHART", "DESCRIPTION") 162 for i := 0; i <= len(releases)-1; i++ { 163 r := releases[i] 164 tbl.AddRow(r.Revision, r.Updated, r.Status, r.Chart, r.Description) 165 } 166 return tbl.Bytes() 167 } 168 169 func formatChartname(c *chart.Chart) string { 170 if c == nil || c.Metadata == nil { 171 // This is an edge case that has happened in prod, though we don't 172 // know how: https://github.com/kubernetes/helm/issues/1347 173 return "MISSING" 174 } 175 return fmt.Sprintf("%s-%s", c.Metadata.Name, c.Metadata.Version) 176 }