github.com/deemoprobe/k8s-first-commit@v0.0.0-20230430165612-a541f1982be3/pkg/registry/etcd_registry.go (about) 1 /* 2 Copyright 2014 Google Inc. All rights reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 package registry 17 18 import ( 19 "encoding/json" 20 "fmt" 21 "log" 22 23 "github.com/coreos/go-etcd/etcd" 24 25 . "github.com/GoogleCloudPlatform/kubernetes/pkg/api" 26 ) 27 28 // TODO: Need to add a reconciler loop that makes sure that things in tasks are reflected into 29 // kubelet (and vice versa) 30 31 // EtcdClient is an injectable interface for testing. 32 type EtcdClient interface { 33 AddChild(key, data string, ttl uint64) (*etcd.Response, error) 34 Get(key string, sort, recursive bool) (*etcd.Response, error) 35 Set(key, value string, ttl uint64) (*etcd.Response, error) 36 Create(key, value string, ttl uint64) (*etcd.Response, error) 37 Delete(key string, recursive bool) (*etcd.Response, error) 38 // I'd like to use directional channels here (e.g. <-chan) but this interface mimics 39 // the etcd client interface which doesn't, and it doesn't seem worth it to wrap the api. 40 Watch(prefix string, waitIndex uint64, recursive bool, receiver chan *etcd.Response, stop chan bool) (*etcd.Response, error) 41 } 42 43 // EtcdRegistry is an implementation of both ControllerRegistry and TaskRegistry which is backed with etcd. 44 type EtcdRegistry struct { 45 etcdClient EtcdClient 46 machines []string 47 manifestFactory ManifestFactory 48 } 49 50 // MakeEtcdRegistry creates an etcd registry. 51 // 'client' is the connection to etcd 52 // 'machines' is the list of machines 53 // 'scheduler' is the scheduling algorithm to use. 54 func MakeEtcdRegistry(client EtcdClient, machines []string) *EtcdRegistry { 55 registry := &EtcdRegistry{ 56 etcdClient: client, 57 machines: machines, 58 } 59 registry.manifestFactory = &BasicManifestFactory{ 60 serviceRegistry: registry, 61 } 62 return registry 63 } 64 65 func makeTaskKey(machine, taskID string) string { 66 return "/registry/hosts/" + machine + "/tasks/" + taskID 67 } 68 69 func (registry *EtcdRegistry) ListTasks(query *map[string]string) ([]Task, error) { 70 tasks := []Task{} 71 for _, machine := range registry.machines { 72 machineTasks, err := registry.listTasksForMachine(machine) 73 if err != nil { 74 return tasks, err 75 } 76 for _, task := range machineTasks { 77 if LabelsMatch(task, query) { 78 tasks = append(tasks, task) 79 } 80 } 81 } 82 return tasks, nil 83 } 84 85 func (registry *EtcdRegistry) listEtcdNode(key string) ([]*etcd.Node, error) { 86 result, err := registry.etcdClient.Get(key, false, true) 87 if err != nil { 88 nodes := make([]*etcd.Node, 0) 89 if isEtcdNotFound(err) { 90 return nodes, nil 91 } else { 92 return nodes, err 93 } 94 } 95 return result.Node.Nodes, nil 96 } 97 98 func (registry *EtcdRegistry) listTasksForMachine(machine string) ([]Task, error) { 99 tasks := []Task{} 100 key := "/registry/hosts/" + machine + "/tasks" 101 nodes, err := registry.listEtcdNode(key) 102 for _, node := range nodes { 103 task := Task{} 104 err = json.Unmarshal([]byte(node.Value), &task) 105 if err != nil { 106 return tasks, err 107 } 108 task.CurrentState.Host = machine 109 tasks = append(tasks, task) 110 } 111 return tasks, err 112 } 113 114 func (registry *EtcdRegistry) GetTask(taskID string) (*Task, error) { 115 task, _, err := registry.findTask(taskID) 116 return &task, err 117 } 118 119 func makeContainerKey(machine string) string { 120 return "/registry/hosts/" + machine + "/kubelet" 121 } 122 123 func (registry *EtcdRegistry) loadManifests(machine string) ([]ContainerManifest, error) { 124 var manifests []ContainerManifest 125 response, err := registry.etcdClient.Get(makeContainerKey(machine), false, false) 126 127 if err != nil { 128 if isEtcdNotFound(err) { 129 err = nil 130 manifests = []ContainerManifest{} 131 } 132 } else { 133 err = json.Unmarshal([]byte(response.Node.Value), &manifests) 134 } 135 return manifests, err 136 } 137 138 func (registry *EtcdRegistry) updateManifests(machine string, manifests []ContainerManifest) error { 139 containerData, err := json.Marshal(manifests) 140 if err != nil { 141 return err 142 } 143 _, err = registry.etcdClient.Set(makeContainerKey(machine), string(containerData), 0) 144 return err 145 } 146 147 func (registry *EtcdRegistry) CreateTask(machineIn string, task Task) error { 148 taskOut, machine, err := registry.findTask(task.ID) 149 if err == nil { 150 return fmt.Errorf("A task named %s already exists on %s (%#v)", task.ID, machine, taskOut) 151 } 152 return registry.runTask(task, machineIn) 153 } 154 155 func (registry *EtcdRegistry) runTask(task Task, machine string) error { 156 manifests, err := registry.loadManifests(machine) 157 if err != nil { 158 return err 159 } 160 161 key := makeTaskKey(machine, task.ID) 162 data, err := json.Marshal(task) 163 if err != nil { 164 return err 165 } 166 _, err = registry.etcdClient.Create(key, string(data), 0) 167 168 manifest, err := registry.manifestFactory.MakeManifest(machine, task) 169 if err != nil { 170 return err 171 } 172 manifests = append(manifests, manifest) 173 return registry.updateManifests(machine, manifests) 174 } 175 176 func (registry *EtcdRegistry) UpdateTask(task Task) error { 177 return fmt.Errorf("Unimplemented!") 178 } 179 180 func (registry *EtcdRegistry) DeleteTask(taskID string) error { 181 _, machine, err := registry.findTask(taskID) 182 if err != nil { 183 return err 184 } 185 return registry.deleteTaskFromMachine(machine, taskID) 186 } 187 188 func (registry *EtcdRegistry) deleteTaskFromMachine(machine, taskID string) error { 189 manifests, err := registry.loadManifests(machine) 190 if err != nil { 191 return err 192 } 193 newManifests := make([]ContainerManifest, 0) 194 found := false 195 for _, manifest := range manifests { 196 if manifest.Id != taskID { 197 newManifests = append(newManifests, manifest) 198 } else { 199 found = true 200 } 201 } 202 if !found { 203 // This really shouldn't happen, it indicates something is broken, and likely 204 // there is a lost task somewhere. 205 // However it is "deleted" so log it and move on 206 log.Printf("Couldn't find: %s in %#v", taskID, manifests) 207 } 208 if err = registry.updateManifests(machine, newManifests); err != nil { 209 return err 210 } 211 key := makeTaskKey(machine, taskID) 212 _, err = registry.etcdClient.Delete(key, true) 213 return err 214 } 215 216 func (registry *EtcdRegistry) getTaskForMachine(machine, taskID string) (Task, error) { 217 key := makeTaskKey(machine, taskID) 218 result, err := registry.etcdClient.Get(key, false, false) 219 if err != nil { 220 if isEtcdNotFound(err) { 221 return Task{}, fmt.Errorf("Not found (%#v).", err) 222 } else { 223 return Task{}, err 224 } 225 } 226 if result.Node == nil || len(result.Node.Value) == 0 { 227 return Task{}, fmt.Errorf("no nodes field: %#v", result) 228 } 229 task := Task{} 230 err = json.Unmarshal([]byte(result.Node.Value), &task) 231 task.CurrentState.Host = machine 232 return task, err 233 } 234 235 func (registry *EtcdRegistry) findTask(taskID string) (Task, string, error) { 236 for _, machine := range registry.machines { 237 task, err := registry.getTaskForMachine(machine, taskID) 238 if err == nil { 239 return task, machine, nil 240 } 241 } 242 return Task{}, "", fmt.Errorf("Task not found %s", taskID) 243 } 244 245 func isEtcdNotFound(err error) bool { 246 if err == nil { 247 return false 248 } 249 switch err.(type) { 250 case *etcd.EtcdError: 251 etcdError := err.(*etcd.EtcdError) 252 if etcdError == nil { 253 return false 254 } 255 if etcdError.ErrorCode == 100 { 256 return true 257 } 258 } 259 return false 260 } 261 262 func (registry *EtcdRegistry) ListControllers() ([]ReplicationController, error) { 263 var controllers []ReplicationController 264 key := "/registry/controllers" 265 nodes, err := registry.listEtcdNode(key) 266 for _, node := range nodes { 267 var controller ReplicationController 268 err = json.Unmarshal([]byte(node.Value), &controller) 269 if err != nil { 270 return controllers, err 271 } 272 controllers = append(controllers, controller) 273 } 274 return controllers, nil 275 } 276 277 func makeControllerKey(id string) string { 278 return "/registry/controllers/" + id 279 } 280 281 func (registry *EtcdRegistry) GetController(controllerID string) (*ReplicationController, error) { 282 var controller ReplicationController 283 key := makeControllerKey(controllerID) 284 result, err := registry.etcdClient.Get(key, false, false) 285 if err != nil { 286 if isEtcdNotFound(err) { 287 return nil, fmt.Errorf("Controller %s not found", controllerID) 288 } else { 289 return nil, err 290 } 291 } 292 if result.Node == nil || len(result.Node.Value) == 0 { 293 return nil, fmt.Errorf("no nodes field: %#v", result) 294 } 295 err = json.Unmarshal([]byte(result.Node.Value), &controller) 296 return &controller, err 297 } 298 299 func (registry *EtcdRegistry) CreateController(controller ReplicationController) error { 300 // TODO : check for existence here and error. 301 return registry.UpdateController(controller) 302 } 303 304 func (registry *EtcdRegistry) UpdateController(controller ReplicationController) error { 305 controllerData, err := json.Marshal(controller) 306 if err != nil { 307 return err 308 } 309 key := makeControllerKey(controller.ID) 310 _, err = registry.etcdClient.Set(key, string(controllerData), 0) 311 return err 312 } 313 314 func (registry *EtcdRegistry) DeleteController(controllerID string) error { 315 key := makeControllerKey(controllerID) 316 _, err := registry.etcdClient.Delete(key, false) 317 return err 318 } 319 320 func makeServiceKey(name string) string { 321 return "/registry/services/specs/" + name 322 } 323 324 func (registry *EtcdRegistry) ListServices() (ServiceList, error) { 325 nodes, err := registry.listEtcdNode("/registry/services/specs") 326 if err != nil { 327 return ServiceList{}, err 328 } 329 330 var services []Service 331 for _, node := range nodes { 332 var svc Service 333 err := json.Unmarshal([]byte(node.Value), &svc) 334 if err != nil { 335 return ServiceList{}, err 336 } 337 services = append(services, svc) 338 } 339 return ServiceList{Items: services}, nil 340 } 341 342 func (registry *EtcdRegistry) CreateService(svc Service) error { 343 key := makeServiceKey(svc.ID) 344 data, err := json.Marshal(svc) 345 if err != nil { 346 return err 347 } 348 _, err = registry.etcdClient.Set(key, string(data), 0) 349 return err 350 } 351 352 func (registry *EtcdRegistry) GetService(name string) (*Service, error) { 353 key := makeServiceKey(name) 354 response, err := registry.etcdClient.Get(key, false, false) 355 if err != nil { 356 if isEtcdNotFound(err) { 357 return nil, fmt.Errorf("Service %s was not found.", name) 358 } else { 359 return nil, err 360 } 361 } 362 var svc Service 363 err = json.Unmarshal([]byte(response.Node.Value), &svc) 364 if err != nil { 365 return nil, err 366 } 367 return &svc, err 368 } 369 370 func (registry *EtcdRegistry) DeleteService(name string) error { 371 key := makeServiceKey(name) 372 _, err := registry.etcdClient.Delete(key, true) 373 if err != nil { 374 return err 375 } 376 key = "/registry/services/endpoints/" + name 377 _, err = registry.etcdClient.Delete(key, true) 378 return err 379 } 380 381 func (registry *EtcdRegistry) UpdateService(svc Service) error { 382 return registry.CreateService(svc) 383 } 384 385 func (registry *EtcdRegistry) UpdateEndpoints(e Endpoints) error { 386 data, err := json.Marshal(e) 387 if err != nil { 388 return err 389 } 390 _, err = registry.etcdClient.Set("/registry/services/endpoints/"+e.Name, string(data), 0) 391 return err 392 }