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 }