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