github.com/zoumo/helm@v2.5.0+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  	"sync"
    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  	// releaseLocks are for locking releases to make sure that only one operation at a time is executed on each release
    33  	releaseLocks map[string]*sync.Mutex
    34  	// releaseLocksLock is a mutex for accessing releaseLocks
    35  	releaseLocksLock *sync.Mutex
    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  	return s.Driver.Create(makeKey(rls.Name, rls.Version), rls)
    54  }
    55  
    56  // Update update the release in storage. An error is returned if the
    57  // storage backend fails to update the release or if the release
    58  // does not exist.
    59  func (s *Storage) Update(rls *rspb.Release) error {
    60  	s.Log("updating release %q", makeKey(rls.Name, rls.Version))
    61  	return s.Driver.Update(makeKey(rls.Name, rls.Version), rls)
    62  }
    63  
    64  // Delete deletes the release from storage. An error is returned if
    65  // the storage backend fails to delete the release or if the release
    66  // does not exist.
    67  func (s *Storage) Delete(name string, version int32) (*rspb.Release, error) {
    68  	s.Log("deleting release %q", makeKey(name, version))
    69  	return s.Driver.Delete(makeKey(name, version))
    70  }
    71  
    72  // ListReleases returns all releases from storage. An error is returned if the
    73  // storage backend fails to retrieve the releases.
    74  func (s *Storage) ListReleases() ([]*rspb.Release, error) {
    75  	s.Log("listing all releases in storage")
    76  	return s.Driver.List(func(_ *rspb.Release) bool { return true })
    77  }
    78  
    79  // ListDeleted returns all releases with Status == DELETED. An error is returned
    80  // if the storage backend fails to retrieve the releases.
    81  func (s *Storage) ListDeleted() ([]*rspb.Release, error) {
    82  	s.Log("listing deleted releases in storage")
    83  	return s.Driver.List(func(rls *rspb.Release) bool {
    84  		return relutil.StatusFilter(rspb.Status_DELETED).Check(rls)
    85  	})
    86  }
    87  
    88  // ListDeployed returns all releases with Status == DEPLOYED. An error is returned
    89  // if the storage backend fails to retrieve the releases.
    90  func (s *Storage) ListDeployed() ([]*rspb.Release, error) {
    91  	s.Log("listing all deployed releases in storage")
    92  	return s.Driver.List(func(rls *rspb.Release) bool {
    93  		return relutil.StatusFilter(rspb.Status_DEPLOYED).Check(rls)
    94  	})
    95  }
    96  
    97  // ListFilterAll returns the set of releases satisfying satisfying the predicate
    98  // (filter0 && filter1 && ... && filterN), i.e. a Release is included in the results
    99  // if and only if all filters return true.
   100  func (s *Storage) ListFilterAll(fns ...relutil.FilterFunc) ([]*rspb.Release, error) {
   101  	s.Log("listing all releases with filter")
   102  	return s.Driver.List(func(rls *rspb.Release) bool {
   103  		return relutil.All(fns...).Check(rls)
   104  	})
   105  }
   106  
   107  // ListFilterAny returns the set of releases satisfying satisfying the predicate
   108  // (filter0 || filter1 || ... || filterN), i.e. a Release is included in the results
   109  // if at least one of the filters returns true.
   110  func (s *Storage) ListFilterAny(fns ...relutil.FilterFunc) ([]*rspb.Release, error) {
   111  	s.Log("listing any releases with filter")
   112  	return s.Driver.List(func(rls *rspb.Release) bool {
   113  		return relutil.Any(fns...).Check(rls)
   114  	})
   115  }
   116  
   117  // Deployed returns the deployed release with the provided release name, or
   118  // returns ErrReleaseNotFound if not found.
   119  func (s *Storage) Deployed(name string) (*rspb.Release, error) {
   120  	s.Log("getting deployed release from %q history", name)
   121  
   122  	ls, err := s.Driver.Query(map[string]string{
   123  		"NAME":   name,
   124  		"OWNER":  "TILLER",
   125  		"STATUS": "DEPLOYED",
   126  	})
   127  	switch {
   128  	case err != nil:
   129  		return nil, err
   130  	case len(ls) == 0:
   131  		return nil, fmt.Errorf("%q has no deployed releases", name)
   132  	default:
   133  		return ls[0], nil
   134  	}
   135  }
   136  
   137  // History returns the revision history for the release with the provided name, or
   138  // returns ErrReleaseNotFound if no such release name exists.
   139  func (s *Storage) History(name string) ([]*rspb.Release, error) {
   140  	s.Log("getting release history for %q", name)
   141  
   142  	return s.Driver.Query(map[string]string{"NAME": name, "OWNER": "TILLER"})
   143  }
   144  
   145  // Last fetches the last revision of the named release.
   146  func (s *Storage) Last(name string) (*rspb.Release, error) {
   147  	s.Log("getting last revision of %q", name)
   148  	h, err := s.History(name)
   149  	if err != nil {
   150  		return nil, err
   151  	}
   152  	if len(h) == 0 {
   153  		return nil, fmt.Errorf("no revision for release %q", name)
   154  	}
   155  
   156  	relutil.Reverse(h, relutil.SortByRevision)
   157  	return h[0], nil
   158  }
   159  
   160  // LockRelease gains a mutually exclusive access to a release via a mutex.
   161  func (s *Storage) LockRelease(name string) error {
   162  	s.Log("locking release %s", name)
   163  	s.releaseLocksLock.Lock()
   164  	defer s.releaseLocksLock.Unlock()
   165  
   166  	var lock *sync.Mutex
   167  	lock, exists := s.releaseLocks[name]
   168  
   169  	if !exists {
   170  		releases, err := s.ListReleases()
   171  		if err != nil {
   172  			return err
   173  		}
   174  
   175  		found := false
   176  		for _, release := range releases {
   177  			if release.Name == name {
   178  				found = true
   179  			}
   180  		}
   181  		if !found {
   182  			return fmt.Errorf("Unable to lock release %q: release not found", name)
   183  		}
   184  
   185  		lock = &sync.Mutex{}
   186  		s.releaseLocks[name] = lock
   187  	}
   188  	lock.Lock()
   189  	return nil
   190  }
   191  
   192  // UnlockRelease releases a mutually exclusive access to a release.
   193  // If release doesn't exist or wasn't previously locked - the unlock will pass
   194  func (s *Storage) UnlockRelease(name string) {
   195  	s.Log("unlocking release %s", name)
   196  	s.releaseLocksLock.Lock()
   197  	defer s.releaseLocksLock.Unlock()
   198  
   199  	var lock *sync.Mutex
   200  	lock, exists := s.releaseLocks[name]
   201  	if !exists {
   202  		return
   203  	}
   204  	lock.Unlock()
   205  }
   206  
   207  // makeKey concatenates a release name and version into
   208  // a string with format ```<release_name>#v<version>```.
   209  // This key is used to uniquely identify storage objects.
   210  func makeKey(rlsname string, version int32) string {
   211  	return fmt.Sprintf("%s.v%d", rlsname, version)
   212  }
   213  
   214  // Init initializes a new storage backend with the driver d.
   215  // If d is nil, the default in-memory driver is used.
   216  func Init(d driver.Driver) *Storage {
   217  	// default driver is in memory
   218  	if d == nil {
   219  		d = driver.NewMemory()
   220  	}
   221  	return &Storage{
   222  		Driver:           d,
   223  		releaseLocks:     make(map[string]*sync.Mutex),
   224  		releaseLocksLock: &sync.Mutex{},
   225  		Log:              func(_ string, _ ...interface{}) {},
   226  	}
   227  }