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 }