github.com/strongmonkey/helm@v2.7.2+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  	pending    bool
    76  	client     helm.Interface
    77  }
    78  
    79  func newListCmd(client helm.Interface, out io.Writer) *cobra.Command {
    80  	list := &listCmd{
    81  		out:    out,
    82  		client: client,
    83  	}
    84  
    85  	cmd := &cobra.Command{
    86  		Use:     "list [flags] [FILTER]",
    87  		Short:   "list releases",
    88  		Long:    listHelp,
    89  		Aliases: []string{"ls"},
    90  		PreRunE: setupConnection,
    91  		RunE: func(cmd *cobra.Command, args []string) error {
    92  			if len(args) > 0 {
    93  				list.filter = strings.Join(args, " ")
    94  			}
    95  			if list.client == nil {
    96  				list.client = newClient()
    97  			}
    98  			return list.run()
    99  		},
   100  	}
   101  
   102  	f := cmd.Flags()
   103  	f.BoolVarP(&list.short, "short", "q", false, "output short (quiet) listing format")
   104  	f.BoolVarP(&list.byDate, "date", "d", false, "sort by release date")
   105  	f.BoolVarP(&list.sortDesc, "reverse", "r", false, "reverse the sort order")
   106  	f.IntVarP(&list.limit, "max", "m", 256, "maximum number of releases to fetch")
   107  	f.StringVarP(&list.offset, "offset", "o", "", "next release name in the list, used to offset from start value")
   108  	f.BoolVarP(&list.all, "all", "a", false, "show all releases, not just the ones marked DEPLOYED")
   109  	f.BoolVar(&list.deleted, "deleted", false, "show deleted releases")
   110  	f.BoolVar(&list.deleting, "deleting", false, "show releases that are currently being deleted")
   111  	f.BoolVar(&list.deployed, "deployed", false, "show deployed releases. If no other is specified, this will be automatically enabled")
   112  	f.BoolVar(&list.failed, "failed", false, "show failed releases")
   113  	f.BoolVar(&list.pending, "pending", false, "show pending releases")
   114  	f.StringVar(&list.namespace, "namespace", "", "show releases within a specific namespace")
   115  
   116  	// TODO: Do we want this as a feature of 'helm list'?
   117  	//f.BoolVar(&list.superseded, "history", true, "show historical releases")
   118  
   119  	return cmd
   120  }
   121  
   122  func (l *listCmd) run() error {
   123  	sortBy := services.ListSort_NAME
   124  	if l.byDate {
   125  		sortBy = services.ListSort_LAST_RELEASED
   126  	}
   127  
   128  	sortOrder := services.ListSort_ASC
   129  	if l.sortDesc {
   130  		sortOrder = services.ListSort_DESC
   131  	}
   132  
   133  	stats := l.statusCodes()
   134  
   135  	res, err := l.client.ListReleases(
   136  		helm.ReleaseListLimit(l.limit),
   137  		helm.ReleaseListOffset(l.offset),
   138  		helm.ReleaseListFilter(l.filter),
   139  		helm.ReleaseListSort(int32(sortBy)),
   140  		helm.ReleaseListOrder(int32(sortOrder)),
   141  		helm.ReleaseListStatuses(stats),
   142  		helm.ReleaseListNamespace(l.namespace),
   143  	)
   144  
   145  	if err != nil {
   146  		return prettyError(err)
   147  	}
   148  
   149  	if len(res.Releases) == 0 {
   150  		return nil
   151  	}
   152  
   153  	if res.Next != "" && !l.short {
   154  		fmt.Fprintf(l.out, "\tnext: %s\n", res.Next)
   155  	}
   156  
   157  	rels := res.Releases
   158  
   159  	if l.short {
   160  		for _, r := range rels {
   161  			fmt.Fprintln(l.out, r.Name)
   162  		}
   163  		return nil
   164  	}
   165  	fmt.Fprintln(l.out, formatList(rels))
   166  	return nil
   167  }
   168  
   169  // statusCodes gets the list of status codes that are to be included in the results.
   170  func (l *listCmd) statusCodes() []release.Status_Code {
   171  	if l.all {
   172  		return []release.Status_Code{
   173  			release.Status_UNKNOWN,
   174  			release.Status_DEPLOYED,
   175  			release.Status_DELETED,
   176  			release.Status_DELETING,
   177  			release.Status_FAILED,
   178  			release.Status_PENDING_INSTALL,
   179  			release.Status_PENDING_UPGRADE,
   180  			release.Status_PENDING_ROLLBACK,
   181  		}
   182  	}
   183  	status := []release.Status_Code{}
   184  	if l.deployed {
   185  		status = append(status, release.Status_DEPLOYED)
   186  	}
   187  	if l.deleted {
   188  		status = append(status, release.Status_DELETED)
   189  	}
   190  	if l.deleting {
   191  		status = append(status, release.Status_DELETING)
   192  	}
   193  	if l.failed {
   194  		status = append(status, release.Status_FAILED)
   195  	}
   196  	if l.superseded {
   197  		status = append(status, release.Status_SUPERSEDED)
   198  	}
   199  	if l.pending {
   200  		status = append(status, release.Status_PENDING_INSTALL, release.Status_PENDING_UPGRADE, release.Status_PENDING_ROLLBACK)
   201  	}
   202  
   203  	// Default case.
   204  	if len(status) == 0 {
   205  		status = append(status, release.Status_DEPLOYED, release.Status_FAILED)
   206  	}
   207  	return status
   208  }
   209  
   210  func formatList(rels []*release.Release) string {
   211  	table := uitable.New()
   212  	table.MaxColWidth = 60
   213  	table.AddRow("NAME", "REVISION", "UPDATED", "STATUS", "CHART", "NAMESPACE")
   214  	for _, r := range rels {
   215  		c := fmt.Sprintf("%s-%s", r.Chart.Metadata.Name, r.Chart.Metadata.Version)
   216  		t := timeconv.String(r.Info.LastDeployed)
   217  		s := r.Info.Status.Code.String()
   218  		v := r.Version
   219  		n := r.Namespace
   220  		table.AddRow(r.Name, v, t, s, c, n)
   221  	}
   222  	return table.String()
   223  }