github.com/vtuson/helm@v2.8.2+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 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 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 last 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  	ls, err := s.DeployedAll(name)
   125  	if err != nil {
   126  		if strings.Contains(err.Error(), "not found") {
   127  			return nil, fmt.Errorf("%q has no deployed releases", name)
   128  		}
   129  		return nil, err
   130  	}
   131  
   132  	if len(ls) == 0 {
   133  		return nil, fmt.Errorf("%q has no deployed releases", name)
   134  	}
   135  
   136  	return ls[0], err
   137  }
   138  
   139  // DeployedAll returns all deployed releases with the provided name, or
   140  // returns ErrReleaseNotFound if not found.
   141  func (s *Storage) DeployedAll(name string) ([]*rspb.Release, error) {
   142  	s.Log("getting deployed releases from %q history", name)
   143  
   144  	ls, err := s.Driver.Query(map[string]string{
   145  		"NAME":   name,
   146  		"OWNER":  "TILLER",
   147  		"STATUS": "DEPLOYED",
   148  	})
   149  	if err == nil {
   150  		return ls, nil
   151  	}
   152  	if strings.Contains(err.Error(), "not found") {
   153  		return nil, fmt.Errorf("%q has no deployed releases", name)
   154  	}
   155  	return nil, err
   156  }
   157  
   158  // History returns the revision history for the release with the provided name, or
   159  // returns ErrReleaseNotFound if no such release name exists.
   160  func (s *Storage) History(name string) ([]*rspb.Release, error) {
   161  	s.Log("getting release history for %q", name)
   162  
   163  	return s.Driver.Query(map[string]string{"NAME": name, "OWNER": "TILLER"})
   164  }
   165  
   166  // removeLeastRecent removes items from history until the lengh number of releases
   167  // does not exceed max.
   168  //
   169  // We allow max to be set explicitly so that calling functions can "make space"
   170  // for the new records they are going to write.
   171  func (s *Storage) removeLeastRecent(name string, max int) error {
   172  	if max < 0 {
   173  		return nil
   174  	}
   175  	h, err := s.History(name)
   176  	if err != nil {
   177  		return err
   178  	}
   179  	if len(h) <= max {
   180  		return nil
   181  	}
   182  	overage := len(h) - max
   183  
   184  	// We want oldest to newest
   185  	relutil.SortByRevision(h)
   186  
   187  	// Delete as many as possible. In the case of API throughput limitations,
   188  	// multiple invocations of this function will eventually delete them all.
   189  	toDelete := h[0:overage]
   190  	errors := []error{}
   191  	for _, rel := range toDelete {
   192  		key := makeKey(name, rel.Version)
   193  		_, innerErr := s.Delete(name, rel.Version)
   194  		if innerErr != nil {
   195  			s.Log("error pruning %s from release history: %s", key, innerErr)
   196  			errors = append(errors, innerErr)
   197  		}
   198  	}
   199  
   200  	s.Log("Pruned %d record(s) from %s with %d error(s)", len(toDelete), name, len(errors))
   201  	switch c := len(errors); c {
   202  	case 0:
   203  		return nil
   204  	case 1:
   205  		return errors[0]
   206  	default:
   207  		return fmt.Errorf("encountered %d deletion errors. First is: %s", c, errors[0])
   208  	}
   209  }
   210  
   211  // Last fetches the last revision of the named release.
   212  func (s *Storage) Last(name string) (*rspb.Release, error) {
   213  	s.Log("getting last revision of %q", name)
   214  	h, err := s.History(name)
   215  	if err != nil {
   216  		return nil, err
   217  	}
   218  	if len(h) == 0 {
   219  		return nil, fmt.Errorf("no revision for release %q", name)
   220  	}
   221  
   222  	relutil.Reverse(h, relutil.SortByRevision)
   223  	return h[0], nil
   224  }
   225  
   226  // makeKey concatenates a release name and version into
   227  // a string with format ```<release_name>#v<version>```.
   228  // This key is used to uniquely identify storage objects.
   229  func makeKey(rlsname string, version int32) string {
   230  	return fmt.Sprintf("%s.v%d", rlsname, version)
   231  }
   232  
   233  // Init initializes a new storage backend with the driver d.
   234  // If d is nil, the default in-memory driver is used.
   235  func Init(d driver.Driver) *Storage {
   236  	// default driver is in memory
   237  	if d == nil {
   238  		d = driver.NewMemory()
   239  	}
   240  	return &Storage{
   241  		Driver: d,
   242  		Log:    func(_ string, _ ...interface{}) {},
   243  	}
   244  }