github.com/umeshredd/helm@v3.0.0-alpha.1+incompatible/pkg/action/list.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  	"fmt"
    21  	"regexp"
    22  
    23  	"github.com/gosuri/uitable"
    24  
    25  	"helm.sh/helm/pkg/release"
    26  	"helm.sh/helm/pkg/releaseutil"
    27  )
    28  
    29  // ListStates represents zero or more status codes that a list item may have set
    30  //
    31  // Because this is used as a bitmask filter, more than one one bit can be flipped
    32  // in the ListStates.
    33  type ListStates uint
    34  
    35  const (
    36  	// ListDeployed filters on status "deployed"
    37  	ListDeployed ListStates = 1 << iota
    38  	// ListUninstalled filters on status "uninstalled"
    39  	ListUninstalled
    40  	// ListUninstalling filters on status "uninstalling" (uninstall in progress)
    41  	ListUninstalling
    42  	// ListPendingInstall filters on status "pending" (deployment in progress)
    43  	ListPendingInstall
    44  	// ListPendingUpgrade filters on status "pending_upgrade" (upgrade in progress)
    45  	ListPendingUpgrade
    46  	// ListPendingRollback filters on status "pending_rollback" (rollback in progres)
    47  	ListPendingRollback
    48  	// ListSuperseded filters on status "superseded" (historical release version that is no longer deployed)
    49  	ListSuperseded
    50  	// ListFailed filters on status "failed" (release version not deployed because of error)
    51  	ListFailed
    52  	// ListUnknown filters on an unknown status
    53  	ListUnknown
    54  )
    55  
    56  // FromName takes a state name and returns a ListStates representation.
    57  //
    58  // Currently, there are only names for individual flipped bits, so the returned
    59  // ListStates will only match one of the constants. However, it is possible that
    60  // this behavior could change in the future.
    61  func (s ListStates) FromName(str string) ListStates {
    62  	switch str {
    63  	case "deployed":
    64  		return ListDeployed
    65  	case "uninstalled":
    66  		return ListUninstalled
    67  	case "superseded":
    68  		return ListSuperseded
    69  	case "failed":
    70  		return ListFailed
    71  	case "uninstalling":
    72  		return ListUninstalling
    73  	case "pending-install":
    74  		return ListPendingInstall
    75  	case "pending-upgrade":
    76  		return ListPendingUpgrade
    77  	case "pending-rollback":
    78  		return ListPendingRollback
    79  	}
    80  	return ListUnknown
    81  }
    82  
    83  // ListAll is a convenience for enabling all list filters
    84  const ListAll = ListDeployed | ListUninstalled | ListUninstalling | ListPendingInstall | ListPendingRollback | ListPendingUpgrade | ListSuperseded | ListFailed
    85  
    86  // Sorter is a top-level sort
    87  type Sorter uint
    88  
    89  const (
    90  	// ByDate sorts by date
    91  	ByDate Sorter = iota
    92  	// ByNameAsc sorts by ascending lexicographic order
    93  	ByNameAsc
    94  	// ByNameDesc sorts by descending lexicographic order
    95  	ByNameDesc
    96  )
    97  
    98  // List is the action for listing releases.
    99  //
   100  // It provides, for example, the implementation of 'helm list'.
   101  type List struct {
   102  	cfg *Configuration
   103  
   104  	// All ignores the limit/offset
   105  	All bool
   106  	// AllNamespaces searches across namespaces
   107  	AllNamespaces bool
   108  	// Sort indicates the sort to use
   109  	//
   110  	// see pkg/releaseutil for several useful sorters
   111  	Sort Sorter
   112  	// StateMask accepts a bitmask of states for items to show.
   113  	// The default is ListDeployed
   114  	StateMask ListStates
   115  	// Limit is the number of items to return per Run()
   116  	Limit int
   117  	// Offset is the starting index for the Run() call
   118  	Offset int
   119  	// Filter is a filter that is applied to the results
   120  	Filter       string
   121  	Short        bool
   122  	ByDate       bool
   123  	SortDesc     bool
   124  	Uninstalled  bool
   125  	Superseded   bool
   126  	Uninstalling bool
   127  	Deployed     bool
   128  	Failed       bool
   129  	Pending      bool
   130  }
   131  
   132  // NewList constructs a new *List
   133  func NewList(cfg *Configuration) *List {
   134  	return &List{
   135  		StateMask: ListDeployed | ListFailed,
   136  		cfg:       cfg,
   137  	}
   138  }
   139  
   140  func (l *List) SetConfiguration(cfg *Configuration) {
   141  	l.cfg = cfg
   142  }
   143  
   144  // Run executes the list command, returning a set of matches.
   145  func (l *List) Run() ([]*release.Release, error) {
   146  	var filter *regexp.Regexp
   147  	if l.Filter != "" {
   148  		var err error
   149  		filter, err = regexp.Compile(l.Filter)
   150  		if err != nil {
   151  			return nil, err
   152  		}
   153  	}
   154  
   155  	results, err := l.cfg.Releases.List(func(rel *release.Release) bool {
   156  		// Skip anything that the mask doesn't cover
   157  		currentStatus := l.StateMask.FromName(rel.Info.Status.String())
   158  		if l.StateMask&currentStatus == 0 {
   159  			return false
   160  		}
   161  
   162  		// Skip anything that doesn't match the filter.
   163  		if filter != nil && !filter.MatchString(rel.Name) {
   164  			return false
   165  		}
   166  		return true
   167  	})
   168  
   169  	if results == nil {
   170  		return results, nil
   171  	}
   172  
   173  	// Unfortunately, we have to sort before truncating, which can incur substantial overhead
   174  	l.sort(results)
   175  
   176  	// Guard on offset
   177  	if l.Offset >= len(results) {
   178  		return []*release.Release{}, nil
   179  	}
   180  
   181  	// Calculate the limit and offset, and then truncate results if necessary.
   182  	limit := len(results)
   183  	if l.Limit > 0 && l.Limit < limit {
   184  		limit = l.Limit
   185  	}
   186  	last := l.Offset + limit
   187  	if l := len(results); l < last {
   188  		last = l
   189  	}
   190  	results = results[l.Offset:last]
   191  
   192  	return results, err
   193  }
   194  
   195  // sort is an in-place sort where order is based on the value of a.Sort
   196  func (l *List) sort(rels []*release.Release) {
   197  	switch l.Sort {
   198  	case ByDate:
   199  		releaseutil.SortByDate(rels)
   200  	case ByNameDesc:
   201  		releaseutil.Reverse(rels, releaseutil.SortByName)
   202  	default:
   203  		releaseutil.SortByName(rels)
   204  	}
   205  }
   206  
   207  // setStateMask calculates the state mask based on parameters.
   208  func (l *List) SetStateMask() {
   209  	if l.All {
   210  		l.StateMask = ListAll
   211  		return
   212  	}
   213  
   214  	state := ListStates(0)
   215  	if l.Deployed {
   216  		state |= ListDeployed
   217  	}
   218  	if l.Uninstalled {
   219  		state |= ListUninstalled
   220  	}
   221  	if l.Uninstalling {
   222  		state |= ListUninstalling
   223  	}
   224  	if l.Pending {
   225  		state |= ListPendingInstall | ListPendingRollback | ListPendingUpgrade
   226  	}
   227  	if l.Failed {
   228  		state |= ListFailed
   229  	}
   230  
   231  	// Apply a default
   232  	if state == 0 {
   233  		state = ListDeployed | ListFailed
   234  	}
   235  
   236  	l.StateMask = state
   237  }
   238  
   239  func FormatList(rels []*release.Release) string {
   240  	table := uitable.New()
   241  	table.AddRow("NAME", "NAMESPACE", "REVISION", "UPDATED", "STATUS", "CHART")
   242  	for _, r := range rels {
   243  		md := r.Chart.Metadata
   244  		c := fmt.Sprintf("%s-%s", md.Name, md.Version)
   245  		t := "-"
   246  		if tspb := r.Info.LastDeployed; !tspb.IsZero() {
   247  			t = tspb.String()
   248  		}
   249  		s := r.Info.Status.String()
   250  		v := r.Version
   251  		n := r.Namespace
   252  		table.AddRow(r.Name, n, v, t, s, c)
   253  	}
   254  	return table.String()
   255  }