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  }