github.com/fanux/shipyard@v0.0.0-20161009071005-6515ce223235/controller/plugin/manager/cmd/scale.go (about)

     1  package cmd
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/emicklei/go-restful"
     8  	"github.com/samalba/dockerclient"
     9  )
    10  
    11  type ContainerNumberInfo struct {
    12  	Current     int
    13  	Need        int
    14  	ContainerId string
    15  }
    16  
    17  type ScaleResult struct {
    18  	Scaled []string
    19  	Errors []string
    20  }
    21  
    22  func initScaleInfo(info map[string]ContainerNumberInfo, scaleApp []ScaleApp) {
    23  	for _, v := range scaleApp {
    24  		info[v.App] = ContainerNumberInfo{Current: 0, Need: v.Number, ContainerId: ""}
    25  	}
    26  }
    27  
    28  func releaseContainers(info map[string]ContainerNumberInfo, client *dockerclient.DockerClient) {
    29  	containers, err := client.ListContainers(true, false, "")
    30  
    31  	if err != nil {
    32  	}
    33  
    34  	for _, c := range containers {
    35  		fmt.Printf("container image name:%s\n", c.Image)
    36  		containerNumberInfo, ok := info[c.Image]
    37  		if !ok {
    38  			fmt.Printf("out of scale:%s\n", c.Image)
    39  			continue
    40  		}
    41  		containerNumberInfo.Current++
    42  
    43  		if containerNumberInfo.ContainerId == "" {
    44  			containerNumberInfo.ContainerId = c.Id
    45  		}
    46  
    47  		info[c.Image] = containerNumberInfo
    48  
    49  		cid, ok2 := info[c.Image]
    50  		if ok2 {
    51  			fmt.Printf("image [%s] container id is:%s\n", c.Image, cid.ContainerId)
    52  		}
    53  
    54  		if containerNumberInfo.Current > containerNumberInfo.Need {
    55  			// stop container with 5 seconds timeout
    56  			client.StopContainer(c.Id, 5)
    57  			// force remove, delete volume
    58  			client.RemoveContainer(c.Id, true, true)
    59  		}
    60  	}
    61  }
    62  
    63  func deployContainers(info map[string]ContainerNumberInfo, client *dockerclient.DockerClient) {
    64  	for _, v := range info {
    65  		if v.Current < v.Need {
    66  			n := v.Need - v.Current
    67  			scaleContainer(v.ContainerId, n, client)
    68  		}
    69  	}
    70  }
    71  
    72  func scaleContainer(id string, numInstances int, client *dockerclient.DockerClient) ScaleResult {
    73  	var (
    74  		errChan = make(chan (error))
    75  		resChan = make(chan (string))
    76  		result  = ScaleResult{Scaled: make([]string, 0), Errors: make([]string, 0)}
    77  	)
    78  
    79  	// docker client get container info
    80  	containerInfo, err := client.InspectContainer(id)
    81  	if err != nil {
    82  		result.Errors = append(result.Errors, err.Error())
    83  		return result
    84  	}
    85  
    86  	for i := 0; i < numInstances; i++ {
    87  		go func(instance int) {
    88  			config := containerInfo.Config
    89  			// clear hostname to get a newly generated
    90  			config.Hostname = ""
    91  			hostConfig := containerInfo.HostConfig
    92  			config.HostConfig = *hostConfig // sending hostconfig via the Start-endpoint is deprecated starting with docker-engine 1.12
    93  			// using docker client create Container
    94  			id, err := client.CreateContainer(config, "", nil)
    95  			if err != nil {
    96  				errChan <- err
    97  				return
    98  			}
    99  			// using docker client start container
   100  			if err := client.StartContainer(id, hostConfig); err != nil {
   101  				errChan <- err
   102  				return
   103  			}
   104  			resChan <- id
   105  		}(i)
   106  	}
   107  
   108  	for i := 0; i < numInstances; i++ {
   109  		select {
   110  		case id := <-resChan:
   111  			result.Scaled = append(result.Scaled, id)
   112  		case err := <-errChan:
   113  			result.Errors = append(result.Errors, strings.TrimSpace(err.Error()))
   114  		}
   115  	}
   116  
   117  	return result
   118  }
   119  
   120  func (this PluginResource) scaleApp(request *restful.Request,
   121  	response *restful.Response) {
   122  
   123  	scaleApp := []ScaleApp{}
   124  
   125  	dockerClient, err := dockerclient.NewDockerClient(DockerHost, nil)
   126  	if err != nil {
   127  		fmt.Printf("init docker client error:%s", err)
   128  	}
   129  
   130  	err = request.ReadEntity(&scaleApp)
   131  	if err != nil {
   132  	}
   133  	fmt.Println("scale : ", scaleApp)
   134  
   135  	/*
   136  		{
   137  			"ats:latest":{2, 20}
   138  			"hadoop:v1.0":{20, 2}
   139  		}
   140  	*/
   141  
   142  	scaleInfo := make(map[string]ContainerNumberInfo)
   143  
   144  	initScaleInfo(scaleInfo, scaleApp)
   145  
   146  	fmt.Println("map info: ", scaleInfo)
   147  
   148  	releaseContainers(scaleInfo, dockerClient)
   149  	deployContainers(scaleInfo, dockerClient)
   150  
   151  	//fmt.Println("scale map: ", scaleInfo["ats"])
   152  }