github.com/kata-containers/runtime@v0.0.0-20210505125100-04f29832a923/virtcontainers/store/manager.go (about) 1 // Copyright (c) 2019 Intel Corporation 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 6 package store 7 8 import ( 9 "context" 10 "fmt" 11 "net/url" 12 "sync" 13 14 opentracing "github.com/opentracing/opentracing-go" 15 "github.com/sirupsen/logrus" 16 ) 17 18 // Item represents a virtcontainers items that will be managed through the store. 19 type Item uint8 20 21 const ( 22 // Configuration represents a configuration item to be stored 23 Configuration Item = iota 24 25 // State represents a state item to be stored. 26 State 27 28 // Network represents a networking item to be stored. 29 Network 30 31 // Hypervisor represents an hypervisor item to be stored. 32 Hypervisor 33 34 // Agent represents a agent item to be stored. 35 Agent 36 37 // Process represents a container process item to be stored. 38 Process 39 40 // Lock represents a lock item to be stored. 41 Lock 42 43 // Mounts represents a set of mounts related item to be stored. 44 Mounts 45 46 // Devices represents a set of devices related item to be stored. 47 Devices 48 49 // DeviceIDs represents a set of reference IDs item to be stored. 50 DeviceIDs 51 52 // UUID represents a set of uuids item to be stored. 53 UUID 54 ) 55 56 func (i Item) String() string { 57 switch i { 58 case Configuration: 59 return "Configuration" 60 case State: 61 return "State" 62 case Network: 63 return "Network" 64 case Hypervisor: 65 return "Hypervisor" 66 case Agent: 67 return "Agent" 68 case Process: 69 return "Process" 70 case Lock: 71 return "Lock" 72 case Mounts: 73 return "Mounts" 74 case Devices: 75 return "Devices" 76 case DeviceIDs: 77 return "Device IDs" 78 } 79 80 return "" 81 } 82 83 // Store is an opaque structure representing a virtcontainers Store. 84 type Store struct { 85 sync.RWMutex 86 ctx context.Context 87 88 url string 89 scheme string 90 path string 91 host string 92 93 backend backend 94 } 95 96 type manager struct { 97 sync.RWMutex 98 stores map[string]*Store 99 } 100 101 var stores = &manager{stores: make(map[string]*Store)} 102 103 func (m *manager) addStore(s *Store) (rs *Store, err error) { 104 if s == nil { 105 return nil, fmt.Errorf("Store can not be nil") 106 } 107 108 if s.url == "" { 109 return nil, fmt.Errorf("Store URL can not be nil") 110 } 111 112 m.Lock() 113 defer m.Unlock() 114 115 if m.stores[s.url] == nil { 116 m.stores[s.url] = s 117 } 118 119 return m.stores[s.url], nil 120 } 121 122 func (m *manager) removeStore(url string) { 123 m.Lock() 124 defer m.Unlock() 125 126 delete(m.stores, url) 127 } 128 129 func (m *manager) findStore(url string) *Store { 130 m.RLock() 131 defer m.RUnlock() 132 133 return m.stores[url] 134 } 135 136 // New will return a new virtcontainers Store. 137 // If there is already a Store for the URL, we will re-use it. 138 // Otherwise a new Store is created. 139 func New(ctx context.Context, storeURL string) (*Store, error) { 140 // Do we already have such store? 141 if s := stores.findStore(storeURL); s != nil { 142 return s, nil 143 } 144 145 u, err := url.Parse(storeURL) 146 if err != nil { 147 return nil, err 148 } 149 150 s := &Store{ 151 ctx: ctx, 152 url: storeURL, 153 scheme: u.Scheme, 154 path: u.Path, 155 host: u.Host, 156 } 157 158 backend, err := newBackend(s.scheme) 159 if err != nil { 160 return nil, err 161 } 162 163 s.backend = backend 164 165 // Create new backend 166 if err = s.backend.new(ctx, s.path, s.host); err != nil { 167 return nil, err 168 } 169 170 if s, err = stores.addStore(s); err != nil { 171 return nil, err 172 } 173 174 return s, nil 175 } 176 177 // DeleteAll deletes all Stores from the manager. 178 func DeleteAll() { 179 for _, s := range stores.stores { 180 s.Delete() 181 } 182 } 183 184 var storeLog = logrus.WithField("source", "virtcontainers/store") 185 186 // SetLogger sets the custom logger to be used by this package. If not called, 187 // the package will create its own logger. 188 func SetLogger(logger *logrus.Entry) { 189 fields := storeLog.Data 190 storeLog = logger.WithFields(fields) 191 } 192 193 // Logger returns a logrus logger appropriate for logging Store messages 194 func (s *Store) Logger() *logrus.Entry { 195 return storeLog.WithFields(logrus.Fields{ 196 "subsystem": "store", 197 "path": s.path, 198 }) 199 } 200 201 func (s *Store) trace(name string) (opentracing.Span, context.Context) { 202 if s.ctx == nil { 203 s.Logger().WithField("type", "bug").Error("trace called before context set") 204 s.ctx = context.Background() 205 } 206 207 span, ctx := opentracing.StartSpanFromContext(s.ctx, name) 208 209 span.SetTag("subsystem", "store") 210 span.SetTag("path", s.path) 211 212 return span, ctx 213 } 214 215 // Load loads a virtcontainers item from a Store. 216 func (s *Store) Load(item Item, data interface{}) error { 217 span, _ := s.trace("Load") 218 defer span.Finish() 219 220 span.SetTag("item", item) 221 222 s.RLock() 223 defer s.RUnlock() 224 225 return s.backend.load(item, data) 226 } 227 228 // Store stores a virtcontainers item into a Store. 229 func (s *Store) Store(item Item, data interface{}) error { 230 span, _ := s.trace("Store") 231 defer span.Finish() 232 233 span.SetTag("item", item) 234 235 s.Lock() 236 defer s.Unlock() 237 238 return s.backend.store(item, data) 239 } 240 241 // Delete deletes all artifacts created by a Store. 242 // The Store is also removed from the manager. 243 func (s *Store) Delete() error { 244 span, _ := s.trace("Store") 245 defer span.Finish() 246 247 s.Lock() 248 defer s.Unlock() 249 250 if err := s.backend.delete(); err != nil { 251 return err 252 } 253 254 stores.removeStore(s.url) 255 s.url = "" 256 257 return nil 258 } 259 260 // Raw creates a raw item to be handled directly by the API caller. 261 // It returns a full URL to the item and the caller is responsible 262 // for handling the item through this URL. 263 func (s *Store) Raw(id string) (string, error) { 264 span, _ := s.trace("Raw") 265 defer span.Finish() 266 267 s.Lock() 268 defer s.Unlock() 269 270 return s.backend.raw(id) 271 } 272 273 // ItemLock takes a lock on an item. 274 func (s *Store) ItemLock(item Item, exclusive bool) (string, error) { 275 return s.backend.lock(item, exclusive) 276 } 277 278 // ItemUnlock unlocks an item. 279 func (s *Store) ItemUnlock(item Item, token string) error { 280 return s.backend.unlock(item, token) 281 }