resources.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. package store
  2. import (
  3. "github.com/docker/swarmkit/api"
  4. memdb "github.com/hashicorp/go-memdb"
  5. "github.com/pkg/errors"
  6. )
  7. const tableResource = "resource"
  8. func init() {
  9. register(ObjectStoreConfig{
  10. Table: &memdb.TableSchema{
  11. Name: tableResource,
  12. Indexes: map[string]*memdb.IndexSchema{
  13. indexID: {
  14. Name: indexID,
  15. Unique: true,
  16. Indexer: resourceIndexerByID{},
  17. },
  18. indexName: {
  19. Name: indexName,
  20. Unique: true,
  21. Indexer: resourceIndexerByName{},
  22. },
  23. indexKind: {
  24. Name: indexKind,
  25. Indexer: resourceIndexerByKind{},
  26. },
  27. indexCustom: {
  28. Name: indexCustom,
  29. Indexer: resourceCustomIndexer{},
  30. AllowMissing: true,
  31. },
  32. },
  33. },
  34. Save: func(tx ReadTx, snapshot *api.StoreSnapshot) error {
  35. var err error
  36. snapshot.Resources, err = FindResources(tx, All)
  37. return err
  38. },
  39. Restore: func(tx Tx, snapshot *api.StoreSnapshot) error {
  40. resources, err := FindResources(tx, All)
  41. if err != nil {
  42. return err
  43. }
  44. for _, r := range resources {
  45. if err := DeleteResource(tx, r.ID); err != nil {
  46. return err
  47. }
  48. }
  49. for _, r := range snapshot.Resources {
  50. if err := CreateResource(tx, r); err != nil {
  51. return err
  52. }
  53. }
  54. return nil
  55. },
  56. ApplyStoreAction: func(tx Tx, sa api.StoreAction) error {
  57. switch v := sa.Target.(type) {
  58. case *api.StoreAction_Resource:
  59. obj := v.Resource
  60. switch sa.Action {
  61. case api.StoreActionKindCreate:
  62. return CreateResource(tx, obj)
  63. case api.StoreActionKindUpdate:
  64. return UpdateResource(tx, obj)
  65. case api.StoreActionKindRemove:
  66. return DeleteResource(tx, obj.ID)
  67. }
  68. }
  69. return errUnknownStoreAction
  70. },
  71. })
  72. }
  73. type resourceEntry struct {
  74. *api.Resource
  75. }
  76. func (r resourceEntry) CopyStoreObject() api.StoreObject {
  77. return resourceEntry{Resource: r.Resource.Copy()}
  78. }
  79. func confirmExtension(tx Tx, r *api.Resource) error {
  80. // There must be an extension corresponding to the Kind field.
  81. extensions, err := FindExtensions(tx, ByName(r.Kind))
  82. if err != nil {
  83. return errors.Wrap(err, "failed to query extensions")
  84. }
  85. if len(extensions) == 0 {
  86. return errors.Errorf("object kind %s is unregistered", r.Kind)
  87. }
  88. return nil
  89. }
  90. // CreateResource adds a new resource object to the store.
  91. // Returns ErrExist if the ID is already taken.
  92. func CreateResource(tx Tx, r *api.Resource) error {
  93. if err := confirmExtension(tx, r); err != nil {
  94. return err
  95. }
  96. return tx.create(tableResource, resourceEntry{r})
  97. }
  98. // UpdateResource updates an existing resource object in the store.
  99. // Returns ErrNotExist if the object doesn't exist.
  100. func UpdateResource(tx Tx, r *api.Resource) error {
  101. if err := confirmExtension(tx, r); err != nil {
  102. return err
  103. }
  104. return tx.update(tableResource, resourceEntry{r})
  105. }
  106. // DeleteResource removes a resource object from the store.
  107. // Returns ErrNotExist if the object doesn't exist.
  108. func DeleteResource(tx Tx, id string) error {
  109. return tx.delete(tableResource, id)
  110. }
  111. // GetResource looks up a resource object by ID.
  112. // Returns nil if the object doesn't exist.
  113. func GetResource(tx ReadTx, id string) *api.Resource {
  114. r := tx.get(tableResource, id)
  115. if r == nil {
  116. return nil
  117. }
  118. return r.(resourceEntry).Resource
  119. }
  120. // FindResources selects a set of resource objects and returns them.
  121. func FindResources(tx ReadTx, by By) ([]*api.Resource, error) {
  122. checkType := func(by By) error {
  123. switch by.(type) {
  124. case byIDPrefix, byName, byKind, byCustom, byCustomPrefix:
  125. return nil
  126. default:
  127. return ErrInvalidFindBy
  128. }
  129. }
  130. resourceList := []*api.Resource{}
  131. appendResult := func(o api.StoreObject) {
  132. resourceList = append(resourceList, o.(resourceEntry).Resource)
  133. }
  134. err := tx.find(tableResource, by, checkType, appendResult)
  135. return resourceList, err
  136. }
  137. type resourceIndexerByKind struct{}
  138. func (ri resourceIndexerByKind) FromArgs(args ...interface{}) ([]byte, error) {
  139. return fromArgs(args...)
  140. }
  141. func (ri resourceIndexerByKind) FromObject(obj interface{}) (bool, []byte, error) {
  142. r := obj.(resourceEntry)
  143. // Add the null character as a terminator
  144. val := r.Resource.Kind + "\x00"
  145. return true, []byte(val), nil
  146. }
  147. type resourceIndexerByID struct{}
  148. func (indexer resourceIndexerByID) FromArgs(args ...interface{}) ([]byte, error) {
  149. return api.ResourceIndexerByID{}.FromArgs(args...)
  150. }
  151. func (indexer resourceIndexerByID) PrefixFromArgs(args ...interface{}) ([]byte, error) {
  152. return api.ResourceIndexerByID{}.PrefixFromArgs(args...)
  153. }
  154. func (indexer resourceIndexerByID) FromObject(obj interface{}) (bool, []byte, error) {
  155. return api.ResourceIndexerByID{}.FromObject(obj.(resourceEntry).Resource)
  156. }
  157. type resourceIndexerByName struct{}
  158. func (indexer resourceIndexerByName) FromArgs(args ...interface{}) ([]byte, error) {
  159. return api.ResourceIndexerByName{}.FromArgs(args...)
  160. }
  161. func (indexer resourceIndexerByName) PrefixFromArgs(args ...interface{}) ([]byte, error) {
  162. return api.ResourceIndexerByName{}.PrefixFromArgs(args...)
  163. }
  164. func (indexer resourceIndexerByName) FromObject(obj interface{}) (bool, []byte, error) {
  165. return api.ResourceIndexerByName{}.FromObject(obj.(resourceEntry).Resource)
  166. }
  167. type resourceCustomIndexer struct{}
  168. func (indexer resourceCustomIndexer) FromArgs(args ...interface{}) ([]byte, error) {
  169. return api.ResourceCustomIndexer{}.FromArgs(args...)
  170. }
  171. func (indexer resourceCustomIndexer) PrefixFromArgs(args ...interface{}) ([]byte, error) {
  172. return api.ResourceCustomIndexer{}.PrefixFromArgs(args...)
  173. }
  174. func (indexer resourceCustomIndexer) FromObject(obj interface{}) (bool, [][]byte, error) {
  175. return api.ResourceCustomIndexer{}.FromObject(obj.(resourceEntry).Resource)
  176. }