github.com/canthefason/helm@v2.2.1-0.20170221172616-16b043b8d505+incompatible/cmd/helm/list.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors All rights reserved.
     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  	"strings"
    23  
    24  	"github.com/gosuri/uitable"
    25  	"github.com/spf13/cobra"
    26  
    27  	"k8s.io/helm/pkg/helm"
    28  	"k8s.io/helm/pkg/proto/hapi/release"
    29  	"k8s.io/helm/pkg/proto/hapi/services"
    30  	"k8s.io/helm/pkg/timeconv"
    31  )
    32  
    33  var listHelp = `
    34  This command lists all of the releases.
    35  
    36  By default, it lists only releases that are deployed or failed. Flags like
    37  '--deleted' and '--all' will alter this behavior. Such flags can be combined:
    38  '--deleted --failed'.
    39  
    40  By default, items are sorted alphabetically. Use the '-d' flag to sort by
    41  release date.
    42  
    43  If an argument is provided, it will be treated as a filter. Filters are
    44  regular expressions (Perl compatible) that are applied to the list of releases.
    45  Only items that match the filter will be returned.
    46  
    47  	$ helm list 'ara[a-z]+'
    48  	NAME            	UPDATED                 	CHART
    49  	maudlin-arachnid	Mon May  9 16:07:08 2016	alpine-0.1.0
    50  
    51  If no results are found, 'helm list' will exit 0, but with no output (or in
    52  the case of no '-q' flag, only headers).
    53  
    54  By default, up to 256 items may be returned. To limit this, use the '--max' flag.
    55  Setting '--max' to 0 will not return all results. Rather, it will return the
    56  server's default, which may be much higher than 256. Pairing the '--max'
    57  flag with the '--offset' flag allows you to page through results.
    58  `
    59  
    60  type listCmd struct {
    61  	filter     string
    62  	short      bool
    63  	limit      int
    64  	offset     string
    65  	byDate     bool
    66  	sortDesc   bool
    67  	out        io.Writer
    68  	all        bool
    69  	deleted    bool
    70  	deleting   bool
    71  	deployed   bool
    72  	failed     bool
    73  	namespace  string
    74  	superseded bool
    75  	client     helm.Interface
    76  }
    77  
    78  func newListCmd(client helm.Interface, out io.Writer) *cobra.Command {
    79  	list := &listCmd{
    80  		out:    out,
    81  		client: client,
    82  	}
    83  
    84  	cmd := &cobra.Command{
    85  		Use:               "list [flags] [FILTER]",
    86  		Short:             "list releases",
    87  		Long:              listHelp,
    88  		Aliases:           []string{"ls"},
    89  		PersistentPreRunE: setupConnection,
    90  		RunE: func(cmd *cobra.Command, args []string) error {
    91  			if len(args) > 0 {
    92  				list.filter = strings.Join(args, " ")
    93  			}
    94  			if list.client == nil {
    95  				list.client = helm.NewClient(helm.Host(tillerHost))
    96  			}
    97  			return list.run()
    98  		},
    99  	}
   100  
   101  	f := cmd.Flags()
   102  	f.BoolVarP(&list.short, "short", "q", false, "output short (quiet) listing format")
   103  	f.BoolVarP(&list.byDate, "date", "d", false, "sort by release date")
   104  	f.BoolVarP(&list.sortDesc, "reverse", "r", false, "reverse the sort order")
   105  	f.IntVarP(&list.limit, "max", "m", 256, "maximum number of releases to fetch")
   106  	f.StringVarP(&list.offset, "offset", "o", "", "next release name in the list, used to offset from start value")
   107  	f.BoolVar(&list.all, "all", false, "show all releases, not just the ones marked DEPLOYED")
   108  	f.BoolVar(&list.deleted, "deleted", false, "show deleted releases")
   109  	f.BoolVar(&list.deleting, "deleting", false, "show releases that are currently being deleted")
   110  	f.BoolVar(&list.deployed, "deployed", false, "show deployed releases. If no other is specified, this will be automatically enabled")
   111  	f.BoolVar(&list.failed, "failed", false, "show failed releases")
   112  	f.StringVar(&list.namespace, "namespace", "", "show releases within a specific namespace")
   113  
   114  	// TODO: Do we want this as a feature of 'helm list'?
   115  	//f.BoolVar(&list.superseded, "history", true, "show historical releases")
   116  
   117  	return cmd
   118  }
   119  
   120  func (l *listCmd) run() error {
   121  	sortBy := services.ListSort_NAME
   122  	if l.byDate {
   123  		sortBy = services.ListSort_LAST_RELEASED
   124  	}
   125  
   126  	sortOrder := services.ListSort_ASC
   127  	if l.sortDesc {
   128  		sortOrder = services.ListSort_DESC
   129  	}
   130  
   131  	stats := l.statusCodes()
   132  
   133  	res, err := l.client.ListReleases(
   134  		helm.ReleaseListLimit(l.limit),
   135  		helm.ReleaseListOffset(l.offset),
   136  		helm.ReleaseListFilter(l.filter),
   137  		helm.ReleaseListSort(int32(sortBy)),
   138  		helm.ReleaseListOrder(int32(sortOrder)),
   139  		helm.ReleaseListStatuses(stats),
   140  		helm.ReleaseListNamespace(l.namespace),
   141  	)
   142  
   143  	if err != nil {
   144  		return prettyError(err)
   145  	}
   146  
   147  	if len(res.Releases) == 0 {
   148  		return nil
   149  	}
   150  
   151  	if res.Next != "" && !l.short {
   152  		fmt.Fprintf(l.out, "\tnext: %s\n", res.Next)
   153  	}
   154  
   155  	rels := res.Releases
   156  
   157  	if l.short {
   158  		for _, r := range rels {
   159  			fmt.Fprintln(l.out, r.Name)
   160  		}
   161  		return nil
   162  	}
   163  	fmt.Fprintln(l.out, formatList(rels))
   164  	return nil
   165  }
   166  
   167  // statusCodes gets the list of status codes that are to be included in the results.
   168  func (l *listCmd) statusCodes() []release.Status_Code {
   169  	if l.all {
   170  		return []release.Status_Code{
   171  			release.Status_UNKNOWN,
   172  			release.Status_DEPLOYED,
   173  			release.Status_DELETED,
   174  			release.Status_DELETING,
   175  			release.Status_FAILED,
   176  		}
   177  	}
   178  	status := []release.Status_Code{}
   179  	if l.deployed {
   180  		status = append(status, release.Status_DEPLOYED)
   181  	}
   182  	if l.deleted {
   183  		status = append(status, release.Status_DELETED)
   184  	}
   185  	if l.deleting {
   186  		status = append(status, release.Status_DELETING)
   187  	}
   188  	if l.failed {
   189  		status = append(status, release.Status_FAILED)
   190  	}
   191  	if l.superseded {
   192  		status = append(status, release.Status_SUPERSEDED)
   193  	}
   194  
   195  	// Default case.
   196  	if len(status) == 0 {
   197  		status = append(status, release.Status_DEPLOYED, release.Status_FAILED)
   198  	}
   199  	return status
   200  }
   201  
   202  func formatList(rels []*release.Release) string {
   203  	table := uitable.New()
   204  	table.MaxColWidth = 60
   205  	table.AddRow("NAME", "REVISION", "UPDATED", "STATUS", "CHART", "NAMESPACE")
   206  	for _, r := range rels {
   207  		c := fmt.Sprintf("%s-%s", r.Chart.Metadata.Name, r.Chart.Metadata.Version)
   208  		t := timeconv.String(r.Info.LastDeployed)
   209  		s := r.Info.Status.Code.String()
   210  		v := r.Version
   211  		n := r.Namespace
   212  		table.AddRow(r.Name, v, t, s, c, n)
   213  	}
   214  	return table.String()
   215  }