github.com/lrills/helm@v2.8.1+incompatible/pkg/storage/storage.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 storage // import "k8s.io/helm/pkg/storage"
    18  
    19  import (
    20  	"fmt"
    21  	"strings"
    22  
    23  	rspb "k8s.io/helm/pkg/proto/hapi/release"
    24  	relutil "k8s.io/helm/pkg/releaseutil"
    25  	"k8s.io/helm/pkg/storage/driver"
    26  )
    27  
    28  // Storage represents a storage engine for a Release.
    29  type Storage struct {
    30  	driver.Driver
    31  
    32  	// MaxHistory specifies the maximum number of historical releases that will
    33  	// be retained, including the most recent release. Values of 0 or less are
    34  	// ignored (meaning no limits are imposed).
    35  	MaxHistory int
    36  
    37  	Log func(string, ...interface{})
    38  }
    39  
    40  // Get retrieves the release from storage. An error is returned
    41  // if the storage driver failed to fetch the release, or the
    42  // release identified by the key, version pair does not exist.
    43  func (s *Storage) Get(name string, version int32) (*rspb.Release, error) {
    44  	s.Log("getting release %q", makeKey(name, version))
    45  	return s.Driver.Get(makeKey(name, version))
    46  }
    47  
    48  // Create creates a new storage entry holding the release. An
    49  // error is returned if the storage driver failed to store the
    50  // release, or a release with identical an key already exists.
    51  func (s *Storage) Create(rls *rspb.Release) error {
    52  	s.Log("creating release %q", makeKey(rls.Name, rls.Version))
    53  	if s.MaxHistory > 0 {
    54  		// Want to make space for one more release.
    55  		s.removeLeastRecent(rls.Name, s.MaxHistory-1)
    56  	}
    57  	return s.Driver.Create(makeKey(rls.Name, rls.Version), rls)
    58  }
    59  
    60  // Update update the release in storage. An error is returned if the
    61  // storage backend fails to update the release or if the release
    62  // does not exist.
    63  func (s *Storage) Update(rls *rspb.Release) error {
    64  	s.Log("updating release %q", makeKey(rls.Name, rls.Version))
    65  	return s.Driver.Update(makeKey(rls.Name, rls.Version), rls)
    66  }
    67  
    68  // Delete deletes the release from storage. An error is returned if
    69  // the storage backend fails to delete the release or if the release
    70  // does not exist.
    71  func (s *Storage) Delete(name string, version int32) (*rspb.Release, error) {
    72  	s.Log("deleting release %q", makeKey(name, version))
    73  	return s.Driver.Delete(makeKey(name, version))
    74  }
    75  
    76  // ListReleases returns all releases from storage. An error is returned if the
    77  // storage backend fails to retrieve the releases.
    78  func (s *Storage) ListReleases() ([]*rspb.Release, error) {
    79  	s.Log("listing all releases in storage")
    80  	return s.Driver.List(func(_ *rspb.Release) bool { return true })
    81  }
    82  
    83  // ListDeleted returns all releases with Status == DELETED. An error is returned
    84  // if the storage backend fails to retrieve the releases.
    85  func (s *Storage) ListDeleted() ([]*rspb.Release, error) {
    86  	s.Log("listing deleted releases in storage")
    87  	return s.Driver.List(func(rls *rspb.Release) bool {
    88  		return relutil.StatusFilter(rspb.Status_DELETED).Check(rls)
    89  	})
    90  }
    91  
    92  // ListDeployed returns all releases with Status == DEPLOYED. An error is returned
    93  // if the storage backend fails to retrieve the releases.
    94  func (s *Storage) ListDeployed() ([]*rspb.Release, error) {
    95  	s.Log("listing all deployed releases in storage")
    96  	return s.Driver.List(func(rls *rspb.Release) bool {
    97  		return relutil.StatusFilter(rspb.Status_DEPLOYED).Check(rls)
    98  	})
    99  }
   100  
   101  // ListFilterAll returns the set of releases satisfying satisfying the predicate
   102  // (filter0 && filter1 && ... && filterN), i.e. a Release is included in the results
   103  // if and only if all filters return true.
   104  func (s *Storage) ListFilterAll(fns ...relutil.FilterFunc) ([]*rspb.Release, error) {
   105  	s.Log("listing all releases with filter")
   106  	return s.Driver.List(func(rls *rspb.Release) bool {
   107  		return relutil.All(fns...).Check(rls)
   108  	})
   109  }
   110  
   111  // ListFilterAny returns the set of releases satisfying satisfying the predicate
   112  // (filter0 || filter1 || ... || filterN), i.e. a Release is included in the results
   113  // if at least one of the filters returns true.
   114  func (s *Storage) ListFilterAny(fns ...relutil.FilterFunc) ([]*rspb.Release, error) {
   115  	s.Log("listing any releases with filter")
   116  	return s.Driver.List(func(rls *rspb.Release) bool {
   117  		return relutil.Any(fns...).Check(rls)
   118  	})
   119  }
   120  
   121  // Deployed returns the deployed release with the provided release name, or
   122  // returns ErrReleaseNotFound if not found.
   123  func (s *Storage) Deployed(name string) (*rspb.Release, error) {
   124  	s.Log("getting deployed release from %q history", name)
   125  
   126  	ls, err := s.Driver.Query(map[string]string{
   127  		"NAME":   name,
   128  		"OWNER":  "TILLER",
   129  		"STATUS": "DEPLOYED",
   130  	})
   131  	if err == nil {
   132  		return ls[0], nil
   133  	}
   134  	if strings.Contains(err.Error(), "not found") {
   135  		return nil, fmt.Errorf("%q has no deployed releases", name)
   136  	}
   137  	return nil, err
   138  }
   139  
   140  // History returns the revision history for the release with the provided name, or
   141  // returns ErrReleaseNotFound if no such release name exists.
   142  func (s *Storage) History(name string) ([]*rspb.Release, error) {
   143  	s.Log("getting release history for %q", name)
   144  
   145  	return s.Driver.Query(map[string]string{"NAME": name, "OWNER": "TILLER"})
   146  }
   147  
   148  // removeLeastRecent removes items from history until the lengh number of releases
   149  // does not exceed max.
   150  //
   151  // We allow max to be set explicitly so that calling functions can "make space"
   152  // for the new records they are going to write.
   153  func (s *Storage) removeLeastRecent(name string, max int) error {
   154  	if max < 0 {
   155  		return nil
   156  	}
   157  	h, err := s.History(name)
   158  	if err != nil {
   159  		return err
   160  	}
   161  	if len(h) <= max {
   162  		return nil
   163  	}
   164  	overage := len(h) - max
   165  
   166  	// We want oldest to newest
   167  	relutil.SortByRevision(h)
   168  
   169  	// Delete as many as possible. In the case of API throughput limitations,
   170  	// multiple invocations of this function will eventually delete them all.
   171  	toDelete := h[0:overage]
   172  	errors := []error{}
   173  	for _, rel := range toDelete {
   174  		key := makeKey(name, rel.Version)
   175  		_, innerErr := s.Delete(name, rel.Version)
   176  		if innerErr != nil {
   177  			s.Log("error pruning %s from release history: %s", key, innerErr)
   178  			errors = append(errors, innerErr)
   179  		}
   180  	}
   181  
   182  	s.Log("Pruned %d record(s) from %s with %d error(s)", len(toDelete), name, len(errors))
   183  	switch c := len(errors); c {
   184  	case 0:
   185  		return nil
   186  	case 1:
   187  		return errors[0]
   188  	default:
   189  		return fmt.Errorf("encountered %d deletion errors. First is: %s", c, errors[0])
   190  	}
   191  }
   192  
   193  // Last fetches the last revision of the named release.
   194  func (s *Storage) Last(name string) (*rspb.Release, error) {
   195  	s.Log("getting last revision of %q", name)
   196  	h, err := s.History(name)
   197  	if err != nil {
   198  		return nil, err
   199  	}
   200  	if len(h) == 0 {
   201  		return nil, fmt.Errorf("no revision for release %q", name)
   202  	}
   203  
   204  	relutil.Reverse(h, relutil.SortByRevision)
   205  	return h[0], nil
   206  }
   207  
   208  // makeKey concatenates a release name and version into
   209  // a string with format ```<release_name>#v<version>```.
   210  // This key is used to uniquely identify storage objects.
   211  func makeKey(rlsname string, version int32) string {
   212  	return fmt.Sprintf("%s.v%d", rlsname, version)
   213  }
   214  
   215  // Init initializes a new storage backend with the driver d.
   216  // If d is nil, the default in-memory driver is used.
   217  func Init(d driver.Driver) *Storage {
   218  	// default driver is in memory
   219  	if d == nil {
   220  		d = driver.NewMemory()
   221  	}
   222  	return &Storage{
   223  		Driver: d,
   224  		Log:    func(_ string, _ ...interface{}) {},
   225  	}
   226  }