services.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. package store
  2. import (
  3. "strings"
  4. "github.com/docker/swarmkit/api"
  5. "github.com/docker/swarmkit/api/naming"
  6. memdb "github.com/hashicorp/go-memdb"
  7. )
  8. const tableService = "service"
  9. func init() {
  10. register(ObjectStoreConfig{
  11. Table: &memdb.TableSchema{
  12. Name: tableService,
  13. Indexes: map[string]*memdb.IndexSchema{
  14. indexID: {
  15. Name: indexID,
  16. Unique: true,
  17. Indexer: api.ServiceIndexerByID{},
  18. },
  19. indexName: {
  20. Name: indexName,
  21. Unique: true,
  22. Indexer: api.ServiceIndexerByName{},
  23. },
  24. indexRuntime: {
  25. Name: indexRuntime,
  26. AllowMissing: true,
  27. Indexer: serviceIndexerByRuntime{},
  28. },
  29. indexNetwork: {
  30. Name: indexNetwork,
  31. AllowMissing: true,
  32. Indexer: serviceIndexerByNetwork{},
  33. },
  34. indexSecret: {
  35. Name: indexSecret,
  36. AllowMissing: true,
  37. Indexer: serviceIndexerBySecret{},
  38. },
  39. indexConfig: {
  40. Name: indexConfig,
  41. AllowMissing: true,
  42. Indexer: serviceIndexerByConfig{},
  43. },
  44. indexCustom: {
  45. Name: indexCustom,
  46. Indexer: api.ServiceCustomIndexer{},
  47. AllowMissing: true,
  48. },
  49. },
  50. },
  51. Save: func(tx ReadTx, snapshot *api.StoreSnapshot) error {
  52. var err error
  53. snapshot.Services, err = FindServices(tx, All)
  54. return err
  55. },
  56. Restore: func(tx Tx, snapshot *api.StoreSnapshot) error {
  57. services, err := FindServices(tx, All)
  58. if err != nil {
  59. return err
  60. }
  61. for _, s := range services {
  62. if err := DeleteService(tx, s.ID); err != nil {
  63. return err
  64. }
  65. }
  66. for _, s := range snapshot.Services {
  67. if err := CreateService(tx, s); err != nil {
  68. return err
  69. }
  70. }
  71. return nil
  72. },
  73. ApplyStoreAction: func(tx Tx, sa api.StoreAction) error {
  74. switch v := sa.Target.(type) {
  75. case *api.StoreAction_Service:
  76. obj := v.Service
  77. switch sa.Action {
  78. case api.StoreActionKindCreate:
  79. return CreateService(tx, obj)
  80. case api.StoreActionKindUpdate:
  81. return UpdateService(tx, obj)
  82. case api.StoreActionKindRemove:
  83. return DeleteService(tx, obj.ID)
  84. }
  85. }
  86. return errUnknownStoreAction
  87. },
  88. })
  89. }
  90. // CreateService adds a new service to the store.
  91. // Returns ErrExist if the ID is already taken.
  92. func CreateService(tx Tx, s *api.Service) error {
  93. // Ensure the name is not already in use.
  94. if tx.lookup(tableService, indexName, strings.ToLower(s.Spec.Annotations.Name)) != nil {
  95. return ErrNameConflict
  96. }
  97. return tx.create(tableService, s)
  98. }
  99. // UpdateService updates an existing service in the store.
  100. // Returns ErrNotExist if the service doesn't exist.
  101. func UpdateService(tx Tx, s *api.Service) error {
  102. // Ensure the name is either not in use or already used by this same Service.
  103. if existing := tx.lookup(tableService, indexName, strings.ToLower(s.Spec.Annotations.Name)); existing != nil {
  104. if existing.GetID() != s.ID {
  105. return ErrNameConflict
  106. }
  107. }
  108. return tx.update(tableService, s)
  109. }
  110. // DeleteService removes a service from the store.
  111. // Returns ErrNotExist if the service doesn't exist.
  112. func DeleteService(tx Tx, id string) error {
  113. return tx.delete(tableService, id)
  114. }
  115. // GetService looks up a service by ID.
  116. // Returns nil if the service doesn't exist.
  117. func GetService(tx ReadTx, id string) *api.Service {
  118. s := tx.get(tableService, id)
  119. if s == nil {
  120. return nil
  121. }
  122. return s.(*api.Service)
  123. }
  124. // FindServices selects a set of services and returns them.
  125. func FindServices(tx ReadTx, by By) ([]*api.Service, error) {
  126. checkType := func(by By) error {
  127. switch by.(type) {
  128. case byName, byNamePrefix, byIDPrefix, byRuntime, byReferencedNetworkID, byReferencedSecretID, byReferencedConfigID, byCustom, byCustomPrefix:
  129. return nil
  130. default:
  131. return ErrInvalidFindBy
  132. }
  133. }
  134. serviceList := []*api.Service{}
  135. appendResult := func(o api.StoreObject) {
  136. serviceList = append(serviceList, o.(*api.Service))
  137. }
  138. err := tx.find(tableService, by, checkType, appendResult)
  139. return serviceList, err
  140. }
  141. type serviceIndexerByRuntime struct{}
  142. func (si serviceIndexerByRuntime) FromArgs(args ...interface{}) ([]byte, error) {
  143. return fromArgs(args...)
  144. }
  145. func (si serviceIndexerByRuntime) FromObject(obj interface{}) (bool, []byte, error) {
  146. s := obj.(*api.Service)
  147. r, err := naming.Runtime(s.Spec.Task)
  148. if err != nil {
  149. return false, nil, nil
  150. }
  151. return true, []byte(r + "\x00"), nil
  152. }
  153. func (si serviceIndexerByRuntime) PrefixFromArgs(args ...interface{}) ([]byte, error) {
  154. return prefixFromArgs(args...)
  155. }
  156. type serviceIndexerByNetwork struct{}
  157. func (si serviceIndexerByNetwork) FromArgs(args ...interface{}) ([]byte, error) {
  158. return fromArgs(args...)
  159. }
  160. func (si serviceIndexerByNetwork) FromObject(obj interface{}) (bool, [][]byte, error) {
  161. s := obj.(*api.Service)
  162. var networkIDs [][]byte
  163. specNetworks := s.Spec.Task.Networks
  164. if len(specNetworks) == 0 {
  165. specNetworks = s.Spec.Networks
  166. }
  167. for _, na := range specNetworks {
  168. // Add the null character as a terminator
  169. networkIDs = append(networkIDs, []byte(na.Target+"\x00"))
  170. }
  171. return len(networkIDs) != 0, networkIDs, nil
  172. }
  173. type serviceIndexerBySecret struct{}
  174. func (si serviceIndexerBySecret) FromArgs(args ...interface{}) ([]byte, error) {
  175. return fromArgs(args...)
  176. }
  177. func (si serviceIndexerBySecret) FromObject(obj interface{}) (bool, [][]byte, error) {
  178. s := obj.(*api.Service)
  179. container := s.Spec.Task.GetContainer()
  180. if container == nil {
  181. return false, nil, nil
  182. }
  183. var secretIDs [][]byte
  184. for _, secretRef := range container.Secrets {
  185. // Add the null character as a terminator
  186. secretIDs = append(secretIDs, []byte(secretRef.SecretID+"\x00"))
  187. }
  188. return len(secretIDs) != 0, secretIDs, nil
  189. }
  190. type serviceIndexerByConfig struct{}
  191. func (si serviceIndexerByConfig) FromArgs(args ...interface{}) ([]byte, error) {
  192. return fromArgs(args...)
  193. }
  194. func (si serviceIndexerByConfig) FromObject(obj interface{}) (bool, [][]byte, error) {
  195. s, ok := obj.(*api.Service)
  196. if !ok {
  197. panic("unexpected type passed to FromObject")
  198. }
  199. container := s.Spec.Task.GetContainer()
  200. if container == nil {
  201. return false, nil, nil
  202. }
  203. var configIDs [][]byte
  204. for _, configRef := range container.Configs {
  205. // Add the null character as a terminator
  206. configIDs = append(configIDs, []byte(configRef.ConfigID+"\x00"))
  207. }
  208. return len(configIDs) != 0, configIDs, nil
  209. }