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