github.com/deemoprobe/k8s-first-commit@v0.0.0-20230430165612-a541f1982be3/pkg/registry/replication_controller.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 "math/rand" 23 "strings" 24 "sync" 25 "time" 26 27 . "github.com/GoogleCloudPlatform/kubernetes/pkg/api" 28 "github.com/GoogleCloudPlatform/kubernetes/pkg/client" 29 "github.com/GoogleCloudPlatform/kubernetes/pkg/util" 30 "github.com/coreos/go-etcd/etcd" 31 ) 32 33 // ReplicationManager is responsible for synchronizing ReplicationController objects stored in etcd 34 // with actual running tasks. 35 // TODO: Remove the etcd dependency and re-factor in terms of a generic watch interface 36 type ReplicationManager struct { 37 etcdClient *etcd.Client 38 kubeClient client.ClientInterface 39 taskControl TaskControlInterface 40 updateLock sync.Mutex 41 } 42 43 // An interface that knows how to add or delete tasks 44 // created as an interface to allow testing. 45 type TaskControlInterface interface { 46 createReplica(controllerSpec ReplicationController) 47 deleteTask(taskID string) error 48 } 49 50 type RealTaskControl struct { 51 kubeClient client.ClientInterface 52 } 53 54 func (r RealTaskControl) createReplica(controllerSpec ReplicationController) { 55 labels := controllerSpec.DesiredState.TaskTemplate.Labels 56 if labels != nil { 57 labels["replicationController"] = controllerSpec.ID 58 } 59 task := Task{ 60 JSONBase: JSONBase{ 61 ID: fmt.Sprintf("%x", rand.Int()), 62 }, 63 DesiredState: controllerSpec.DesiredState.TaskTemplate.DesiredState, 64 Labels: controllerSpec.DesiredState.TaskTemplate.Labels, 65 } 66 _, err := r.kubeClient.CreateTask(task) 67 if err != nil { 68 log.Printf("%#v\n", err) 69 } 70 } 71 72 func (r RealTaskControl) deleteTask(taskID string) error { 73 return r.kubeClient.DeleteTask(taskID) 74 } 75 76 func MakeReplicationManager(etcdClient *etcd.Client, kubeClient client.ClientInterface) *ReplicationManager { 77 return &ReplicationManager{ 78 kubeClient: kubeClient, 79 etcdClient: etcdClient, 80 taskControl: RealTaskControl{ 81 kubeClient: kubeClient, 82 }, 83 } 84 } 85 86 func (rm *ReplicationManager) WatchControllers() { 87 watchChannel := make(chan *etcd.Response) 88 go util.Forever(func() { rm.etcdClient.Watch("/registry/controllers", 0, true, watchChannel, nil) }, 0) 89 for { 90 watchResponse := <-watchChannel 91 if watchResponse == nil { 92 time.Sleep(time.Second * 10) 93 continue 94 } 95 log.Printf("Got watch: %#v", watchResponse) 96 controller, err := rm.handleWatchResponse(watchResponse) 97 if err != nil { 98 log.Printf("Error handling data: %#v, %#v", err, watchResponse) 99 continue 100 } 101 rm.syncReplicationController(*controller) 102 } 103 } 104 105 func (rm *ReplicationManager) handleWatchResponse(response *etcd.Response) (*ReplicationController, error) { 106 if response.Action == "set" { 107 if response.Node != nil { 108 var controllerSpec ReplicationController 109 err := json.Unmarshal([]byte(response.Node.Value), &controllerSpec) 110 if err != nil { 111 return nil, err 112 } 113 return &controllerSpec, nil 114 } else { 115 return nil, fmt.Errorf("Response node is null %#v", response) 116 } 117 } 118 return nil, nil 119 } 120 121 func (rm *ReplicationManager) filterActiveTasks(tasks []Task) []Task { 122 var result []Task 123 for _, value := range tasks { 124 if strings.Index(value.CurrentState.Status, "Exit") == -1 { 125 result = append(result, value) 126 } 127 } 128 return result 129 } 130 131 func (rm *ReplicationManager) syncReplicationController(controllerSpec ReplicationController) error { 132 rm.updateLock.Lock() 133 taskList, err := rm.kubeClient.ListTasks(controllerSpec.DesiredState.ReplicasInSet) 134 if err != nil { 135 return err 136 } 137 filteredList := rm.filterActiveTasks(taskList.Items) 138 diff := len(filteredList) - controllerSpec.DesiredState.Replicas 139 log.Printf("%#v", filteredList) 140 if diff < 0 { 141 diff *= -1 142 log.Printf("Too few replicas, creating %d\n", diff) 143 for i := 0; i < diff; i++ { 144 rm.taskControl.createReplica(controllerSpec) 145 } 146 } else if diff > 0 { 147 log.Print("Too many replicas, deleting") 148 for i := 0; i < diff; i++ { 149 rm.taskControl.deleteTask(filteredList[i].ID) 150 } 151 } 152 rm.updateLock.Unlock() 153 return nil 154 } 155 156 func (rm *ReplicationManager) Synchronize() { 157 for { 158 response, err := rm.etcdClient.Get("/registry/controllers", false, false) 159 if err != nil { 160 log.Printf("Synchronization error %#v", err) 161 } 162 // TODO(bburns): There is a race here, if we get a version of the controllers, and then it is 163 // updated, its possible that the watch will pick up the change first, and then we will execute 164 // using the old version of the controller. 165 // Probably the correct thing to do is to use the version number in etcd to detect when 166 // we are stale. 167 // Punting on this for now, but this could lead to some nasty bugs, so we should really fix it 168 // sooner rather than later. 169 if response != nil && response.Node != nil && response.Node.Nodes != nil { 170 for _, value := range response.Node.Nodes { 171 var controllerSpec ReplicationController 172 err := json.Unmarshal([]byte(value.Value), &controllerSpec) 173 if err != nil { 174 log.Printf("Unexpected error: %#v", err) 175 continue 176 } 177 log.Printf("Synchronizing %s\n", controllerSpec.ID) 178 err = rm.syncReplicationController(controllerSpec) 179 if err != nil { 180 log.Printf("Error synchronizing: %#v", err) 181 } 182 } 183 } 184 time.Sleep(10 * time.Second) 185 } 186 }