github.com/umeshredd/helm@v3.0.0-alpha.1+incompatible/pkg/action/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 action 18 19 import ( 20 "encoding/json" 21 "fmt" 22 23 "github.com/ghodss/yaml" 24 "github.com/gosuri/uitable" 25 "github.com/pkg/errors" 26 27 "helm.sh/helm/pkg/chart" 28 "helm.sh/helm/pkg/release" 29 "helm.sh/helm/pkg/releaseutil" 30 ) 31 32 type releaseInfo struct { 33 Revision int `json:"revision"` 34 Updated string `json:"updated"` 35 Status string `json:"status"` 36 Chart string `json:"chart"` 37 AppVersion string `json:"app_version"` 38 Description string `json:"description"` 39 } 40 41 type releaseHistory []releaseInfo 42 43 type OutputFormat string 44 45 const ( 46 Table OutputFormat = "table" 47 JSON OutputFormat = "json" 48 YAML OutputFormat = "yaml" 49 ) 50 51 var ErrInvalidFormatType = errors.New("invalid format type") 52 53 func (o OutputFormat) String() string { 54 return string(o) 55 } 56 57 func ParseOutputFormat(s string) (out OutputFormat, err error) { 58 switch s { 59 case Table.String(): 60 out, err = Table, nil 61 case JSON.String(): 62 out, err = JSON, nil 63 case YAML.String(): 64 out, err = YAML, nil 65 default: 66 out, err = "", ErrInvalidFormatType 67 } 68 return 69 } 70 71 func (o OutputFormat) MarshalHistory(hist releaseHistory) (byt []byte, err error) { 72 switch o { 73 case YAML: 74 byt, err = yaml.Marshal(hist) 75 case JSON: 76 byt, err = json.Marshal(hist) 77 case Table: 78 byt = formatAsTable(hist) 79 default: 80 err = ErrInvalidFormatType 81 } 82 return 83 } 84 85 // History is the action for checking the release's ledger. 86 // 87 // It provides the implementation of 'helm history'. 88 type History struct { 89 cfg *Configuration 90 91 Max int 92 OutputFormat string 93 } 94 95 // NewHistory creates a new History object with the given configuration. 96 func NewHistory(cfg *Configuration) *History { 97 return &History{ 98 cfg: cfg, 99 } 100 } 101 102 // Run executes 'helm history' against the given release. 103 func (h *History) Run(name string) (string, error) { 104 if err := validateReleaseName(name); err != nil { 105 return "", errors.Errorf("getHistory: Release name is invalid: %s", name) 106 } 107 108 h.cfg.Log("getting history for release %s", name) 109 hist, err := h.cfg.Releases.History(name) 110 if err != nil { 111 return "", err 112 } 113 114 releaseutil.Reverse(hist, releaseutil.SortByRevision) 115 116 var rels []*release.Release 117 for i := 0; i < min(len(hist), h.Max); i++ { 118 rels = append(rels, hist[i]) 119 } 120 121 if len(rels) == 0 { 122 return "", nil 123 } 124 125 releaseHistory := getReleaseHistory(rels) 126 127 outputFormat, err := ParseOutputFormat(h.OutputFormat) 128 if err != nil { 129 return "", err 130 } 131 history, formattingError := outputFormat.MarshalHistory(releaseHistory) 132 if formattingError != nil { 133 return "", formattingError 134 } 135 136 return string(history), nil 137 } 138 139 func getReleaseHistory(rls []*release.Release) (history releaseHistory) { 140 for i := len(rls) - 1; i >= 0; i-- { 141 r := rls[i] 142 c := formatChartname(r.Chart) 143 s := r.Info.Status.String() 144 v := r.Version 145 d := r.Info.Description 146 a := formatAppVersion(r.Chart) 147 148 rInfo := releaseInfo{ 149 Revision: v, 150 Status: s, 151 Chart: c, 152 AppVersion: a, 153 Description: d, 154 } 155 if !r.Info.LastDeployed.IsZero() { 156 rInfo.Updated = r.Info.LastDeployed.String() 157 158 } 159 history = append(history, rInfo) 160 } 161 162 return history 163 } 164 165 func formatAsTable(releases releaseHistory) []byte { 166 tbl := uitable.New() 167 168 tbl.AddRow("REVISION", "UPDATED", "STATUS", "CHART", "APP VERSION", "DESCRIPTION") 169 for i := 0; i <= len(releases)-1; i++ { 170 r := releases[i] 171 tbl.AddRow(r.Revision, r.Updated, r.Status, r.Chart, r.AppVersion, r.Description) 172 } 173 return tbl.Bytes() 174 } 175 176 func formatChartname(c *chart.Chart) string { 177 if c == nil || c.Metadata == nil { 178 // This is an edge case that has happened in prod, though we don't 179 // know how: https://github.com/helm/helm/issues/1347 180 return "MISSING" 181 } 182 return fmt.Sprintf("%s-%s", c.Name(), c.Metadata.Version) 183 } 184 185 func formatAppVersion(c *chart.Chart) string { 186 if c == nil || c.Metadata == nil { 187 // This is an edge case that has happened in prod, though we don't 188 // know how: https://github.com/helm/helm/issues/1347 189 return "MISSING" 190 } 191 return c.AppVersion() 192 }