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  }