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  }