github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/manager/state/store/resources.go (about)

     1  package store
     2  
     3  import (
     4  	"strings"
     5  
     6  	"github.com/docker/swarmkit/api"
     7  	memdb "github.com/hashicorp/go-memdb"
     8  	"github.com/pkg/errors"
     9  )
    10  
    11  const tableResource = "resource"
    12  
    13  var (
    14  	// ErrNoKind is returned by resource create operations if the provided Kind
    15  	// of the resource does not exist
    16  	ErrNoKind = errors.New("object kind is unregistered")
    17  )
    18  
    19  func init() {
    20  	register(ObjectStoreConfig{
    21  		Table: &memdb.TableSchema{
    22  			Name: tableResource,
    23  			Indexes: map[string]*memdb.IndexSchema{
    24  				indexID: {
    25  					Name:    indexID,
    26  					Unique:  true,
    27  					Indexer: resourceIndexerByID{},
    28  				},
    29  				indexName: {
    30  					Name:    indexName,
    31  					Unique:  true,
    32  					Indexer: resourceIndexerByName{},
    33  				},
    34  				indexKind: {
    35  					Name:    indexKind,
    36  					Indexer: resourceIndexerByKind{},
    37  				},
    38  				indexCustom: {
    39  					Name:         indexCustom,
    40  					Indexer:      resourceCustomIndexer{},
    41  					AllowMissing: true,
    42  				},
    43  			},
    44  		},
    45  		Save: func(tx ReadTx, snapshot *api.StoreSnapshot) error {
    46  			var err error
    47  			snapshot.Resources, err = FindResources(tx, All)
    48  			return err
    49  		},
    50  		Restore: func(tx Tx, snapshot *api.StoreSnapshot) error {
    51  			toStoreObj := make([]api.StoreObject, len(snapshot.Resources))
    52  			for i, x := range snapshot.Resources {
    53  				toStoreObj[i] = resourceEntry{x}
    54  			}
    55  			return RestoreTable(tx, tableResource, toStoreObj)
    56  		},
    57  		ApplyStoreAction: func(tx Tx, sa api.StoreAction) error {
    58  			switch v := sa.Target.(type) {
    59  			case *api.StoreAction_Resource:
    60  				obj := v.Resource
    61  				switch sa.Action {
    62  				case api.StoreActionKindCreate:
    63  					return CreateResource(tx, obj)
    64  				case api.StoreActionKindUpdate:
    65  					return UpdateResource(tx, obj)
    66  				case api.StoreActionKindRemove:
    67  					return DeleteResource(tx, obj.ID)
    68  				}
    69  			}
    70  			return errUnknownStoreAction
    71  		},
    72  	})
    73  }
    74  
    75  type resourceEntry struct {
    76  	*api.Resource
    77  }
    78  
    79  func (r resourceEntry) CopyStoreObject() api.StoreObject {
    80  	return resourceEntry{Resource: r.Resource.Copy()}
    81  }
    82  
    83  // ensure that when update events are emitted, we unwrap resourceEntry
    84  func (r resourceEntry) EventUpdate(oldObject api.StoreObject) api.Event {
    85  	if oldObject != nil {
    86  		return api.EventUpdateResource{Resource: r.Resource, OldResource: oldObject.(resourceEntry).Resource}
    87  	}
    88  	return api.EventUpdateResource{Resource: r.Resource}
    89  }
    90  
    91  func confirmExtension(tx Tx, r *api.Resource) error {
    92  	// There must be an extension corresponding to the Kind field.
    93  	extensions, err := FindExtensions(tx, ByName(r.Kind))
    94  	if err != nil {
    95  		return errors.Wrap(err, "failed to query extensions")
    96  	}
    97  	if len(extensions) == 0 {
    98  		return ErrNoKind
    99  	}
   100  	return nil
   101  }
   102  
   103  // CreateResource adds a new resource object to the store.
   104  // Returns ErrExist if the ID is already taken.
   105  // Returns ErrNameConflict if a Resource with this Name already exists
   106  // Returns ErrNoKind if the specified Kind does not exist
   107  func CreateResource(tx Tx, r *api.Resource) error {
   108  	if err := confirmExtension(tx, r); err != nil {
   109  		return err
   110  	}
   111  	// TODO(dperny): currently the "name" index is unique, which means only one
   112  	// Resource of _any_ Kind can exist with that name. This isn't a problem
   113  	// right now, but the ideal case would be for names to be namespaced to the
   114  	// kind.
   115  	if tx.lookup(tableResource, indexName, strings.ToLower(r.Annotations.Name)) != nil {
   116  		return ErrNameConflict
   117  	}
   118  	return tx.create(tableResource, resourceEntry{r})
   119  }
   120  
   121  // UpdateResource updates an existing resource object in the store.
   122  // Returns ErrNotExist if the object doesn't exist.
   123  func UpdateResource(tx Tx, r *api.Resource) error {
   124  	if err := confirmExtension(tx, r); err != nil {
   125  		return err
   126  	}
   127  	return tx.update(tableResource, resourceEntry{r})
   128  }
   129  
   130  // DeleteResource removes a resource object from the store.
   131  // Returns ErrNotExist if the object doesn't exist.
   132  func DeleteResource(tx Tx, id string) error {
   133  	return tx.delete(tableResource, id)
   134  }
   135  
   136  // GetResource looks up a resource object by ID.
   137  // Returns nil if the object doesn't exist.
   138  func GetResource(tx ReadTx, id string) *api.Resource {
   139  	r := tx.get(tableResource, id)
   140  	if r == nil {
   141  		return nil
   142  	}
   143  	return r.(resourceEntry).Resource
   144  }
   145  
   146  // FindResources selects a set of resource objects and returns them.
   147  func FindResources(tx ReadTx, by By) ([]*api.Resource, error) {
   148  	checkType := func(by By) error {
   149  		switch by.(type) {
   150  		case byIDPrefix, byName, byNamePrefix, byKind, byCustom, byCustomPrefix:
   151  			return nil
   152  		default:
   153  			return ErrInvalidFindBy
   154  		}
   155  	}
   156  
   157  	resourceList := []*api.Resource{}
   158  	appendResult := func(o api.StoreObject) {
   159  		resourceList = append(resourceList, o.(resourceEntry).Resource)
   160  	}
   161  
   162  	err := tx.find(tableResource, by, checkType, appendResult)
   163  	return resourceList, err
   164  }
   165  
   166  type resourceIndexerByKind struct{}
   167  
   168  func (ri resourceIndexerByKind) FromArgs(args ...interface{}) ([]byte, error) {
   169  	return fromArgs(args...)
   170  }
   171  
   172  func (ri resourceIndexerByKind) FromObject(obj interface{}) (bool, []byte, error) {
   173  	r := obj.(resourceEntry)
   174  
   175  	// Add the null character as a terminator
   176  	val := r.Resource.Kind + "\x00"
   177  	return true, []byte(val), nil
   178  }
   179  
   180  type resourceIndexerByID struct{}
   181  
   182  func (indexer resourceIndexerByID) FromArgs(args ...interface{}) ([]byte, error) {
   183  	return api.ResourceIndexerByID{}.FromArgs(args...)
   184  }
   185  func (indexer resourceIndexerByID) PrefixFromArgs(args ...interface{}) ([]byte, error) {
   186  	return api.ResourceIndexerByID{}.PrefixFromArgs(args...)
   187  }
   188  func (indexer resourceIndexerByID) FromObject(obj interface{}) (bool, []byte, error) {
   189  	return api.ResourceIndexerByID{}.FromObject(obj.(resourceEntry).Resource)
   190  }
   191  
   192  type resourceIndexerByName struct{}
   193  
   194  func (indexer resourceIndexerByName) FromArgs(args ...interface{}) ([]byte, error) {
   195  	return api.ResourceIndexerByName{}.FromArgs(args...)
   196  }
   197  func (indexer resourceIndexerByName) PrefixFromArgs(args ...interface{}) ([]byte, error) {
   198  	return api.ResourceIndexerByName{}.PrefixFromArgs(args...)
   199  }
   200  func (indexer resourceIndexerByName) FromObject(obj interface{}) (bool, []byte, error) {
   201  	return api.ResourceIndexerByName{}.FromObject(obj.(resourceEntry).Resource)
   202  }
   203  
   204  type resourceCustomIndexer struct{}
   205  
   206  func (indexer resourceCustomIndexer) FromArgs(args ...interface{}) ([]byte, error) {
   207  	return api.ResourceCustomIndexer{}.FromArgs(args...)
   208  }
   209  func (indexer resourceCustomIndexer) PrefixFromArgs(args ...interface{}) ([]byte, error) {
   210  	return api.ResourceCustomIndexer{}.PrefixFromArgs(args...)
   211  }
   212  func (indexer resourceCustomIndexer) FromObject(obj interface{}) (bool, [][]byte, error) {
   213  	return api.ResourceCustomIndexer{}.FromObject(obj.(resourceEntry).Resource)
   214  }