github.com/portworx/docker@v1.12.1/integration-cli/daemon_swarm.go (about) 1 package main 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "strings" 8 "time" 9 10 "github.com/docker/docker/pkg/integration/checker" 11 "github.com/docker/engine-api/types" 12 "github.com/docker/engine-api/types/filters" 13 "github.com/docker/engine-api/types/swarm" 14 "github.com/go-check/check" 15 ) 16 17 // SwarmDaemon is a test daemon with helpers for participating in a swarm. 18 type SwarmDaemon struct { 19 *Daemon 20 swarm.Info 21 port int 22 listenAddr string 23 } 24 25 // Init initializes a new swarm cluster. 26 func (d *SwarmDaemon) Init(req swarm.InitRequest) error { 27 if req.ListenAddr == "" { 28 req.ListenAddr = d.listenAddr 29 } 30 status, out, err := d.SockRequest("POST", "/swarm/init", req) 31 if status != http.StatusOK { 32 return fmt.Errorf("initializing swarm: invalid statuscode %v, %q", status, out) 33 } 34 if err != nil { 35 return fmt.Errorf("initializing swarm: %v", err) 36 } 37 info, err := d.info() 38 if err != nil { 39 return err 40 } 41 d.Info = info 42 return nil 43 } 44 45 // Join joins a daemon to an existing cluster. 46 func (d *SwarmDaemon) Join(req swarm.JoinRequest) error { 47 if req.ListenAddr == "" { 48 req.ListenAddr = d.listenAddr 49 } 50 status, out, err := d.SockRequest("POST", "/swarm/join", req) 51 if status != http.StatusOK { 52 return fmt.Errorf("joining swarm: invalid statuscode %v, %q", status, out) 53 } 54 if err != nil { 55 return fmt.Errorf("joining swarm: %v", err) 56 } 57 info, err := d.info() 58 if err != nil { 59 return err 60 } 61 d.Info = info 62 return nil 63 } 64 65 // Leave forces daemon to leave current cluster. 66 func (d *SwarmDaemon) Leave(force bool) error { 67 url := "/swarm/leave" 68 if force { 69 url += "?force=1" 70 } 71 status, out, err := d.SockRequest("POST", url, nil) 72 if status != http.StatusOK { 73 return fmt.Errorf("leaving swarm: invalid statuscode %v, %q", status, out) 74 } 75 if err != nil { 76 err = fmt.Errorf("leaving swarm: %v", err) 77 } 78 return err 79 } 80 81 func (d *SwarmDaemon) info() (swarm.Info, error) { 82 var info struct { 83 Swarm swarm.Info 84 } 85 status, dt, err := d.SockRequest("GET", "/info", nil) 86 if status != http.StatusOK { 87 return info.Swarm, fmt.Errorf("get swarm info: invalid statuscode %v", status) 88 } 89 if err != nil { 90 return info.Swarm, fmt.Errorf("get swarm info: %v", err) 91 } 92 if err := json.Unmarshal(dt, &info); err != nil { 93 return info.Swarm, err 94 } 95 return info.Swarm, nil 96 } 97 98 type serviceConstructor func(*swarm.Service) 99 type nodeConstructor func(*swarm.Node) 100 type specConstructor func(*swarm.Spec) 101 102 func (d *SwarmDaemon) createService(c *check.C, f ...serviceConstructor) string { 103 var service swarm.Service 104 for _, fn := range f { 105 fn(&service) 106 } 107 status, out, err := d.SockRequest("POST", "/services/create", service.Spec) 108 109 c.Assert(err, checker.IsNil) 110 c.Assert(status, checker.Equals, http.StatusCreated, check.Commentf("output: %q", string(out))) 111 112 var scr types.ServiceCreateResponse 113 c.Assert(json.Unmarshal(out, &scr), checker.IsNil) 114 return scr.ID 115 } 116 117 func (d *SwarmDaemon) getService(c *check.C, id string) *swarm.Service { 118 var service swarm.Service 119 status, out, err := d.SockRequest("GET", "/services/"+id, nil) 120 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 121 c.Assert(err, checker.IsNil) 122 c.Assert(json.Unmarshal(out, &service), checker.IsNil) 123 return &service 124 } 125 126 func (d *SwarmDaemon) getServiceTasks(c *check.C, service string) []swarm.Task { 127 var tasks []swarm.Task 128 129 filterArgs := filters.NewArgs() 130 filterArgs.Add("desired-state", "running") 131 filterArgs.Add("service", service) 132 filters, err := filters.ToParam(filterArgs) 133 c.Assert(err, checker.IsNil) 134 135 status, out, err := d.SockRequest("GET", "/tasks?filters="+filters, nil) 136 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 137 c.Assert(err, checker.IsNil, check.Commentf(string(out))) 138 c.Assert(json.Unmarshal(out, &tasks), checker.IsNil) 139 return tasks 140 } 141 142 func (d *SwarmDaemon) checkRunningTaskImages(c *check.C) (interface{}, check.CommentInterface) { 143 var tasks []swarm.Task 144 145 filterArgs := filters.NewArgs() 146 filterArgs.Add("desired-state", "running") 147 filters, err := filters.ToParam(filterArgs) 148 c.Assert(err, checker.IsNil) 149 150 status, out, err := d.SockRequest("GET", "/tasks?filters="+filters, nil) 151 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 152 c.Assert(err, checker.IsNil, check.Commentf(string(out))) 153 c.Assert(json.Unmarshal(out, &tasks), checker.IsNil) 154 155 result := make(map[string]int) 156 for _, task := range tasks { 157 if task.Status.State == swarm.TaskStateRunning { 158 result[task.Spec.ContainerSpec.Image]++ 159 } 160 } 161 return result, nil 162 } 163 164 func (d *SwarmDaemon) checkNodeReadyCount(c *check.C) (interface{}, check.CommentInterface) { 165 nodes := d.listNodes(c) 166 var readyCount int 167 for _, node := range nodes { 168 if node.Status.State == swarm.NodeStateReady { 169 readyCount++ 170 } 171 } 172 return readyCount, nil 173 } 174 175 func (d *SwarmDaemon) getTask(c *check.C, id string) swarm.Task { 176 var task swarm.Task 177 178 status, out, err := d.SockRequest("GET", "/tasks/"+id, nil) 179 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 180 c.Assert(err, checker.IsNil, check.Commentf(string(out))) 181 c.Assert(json.Unmarshal(out, &task), checker.IsNil) 182 return task 183 } 184 185 func (d *SwarmDaemon) updateService(c *check.C, service *swarm.Service, f ...serviceConstructor) { 186 for _, fn := range f { 187 fn(service) 188 } 189 url := fmt.Sprintf("/services/%s/update?version=%d", service.ID, service.Version.Index) 190 status, out, err := d.SockRequest("POST", url, service.Spec) 191 c.Assert(err, checker.IsNil) 192 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 193 } 194 195 func (d *SwarmDaemon) removeService(c *check.C, id string) { 196 status, out, err := d.SockRequest("DELETE", "/services/"+id, nil) 197 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 198 c.Assert(err, checker.IsNil) 199 } 200 201 func (d *SwarmDaemon) getNode(c *check.C, id string) *swarm.Node { 202 var node swarm.Node 203 status, out, err := d.SockRequest("GET", "/nodes/"+id, nil) 204 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 205 c.Assert(err, checker.IsNil) 206 c.Assert(json.Unmarshal(out, &node), checker.IsNil) 207 c.Assert(node.ID, checker.Equals, id) 208 return &node 209 } 210 211 func (d *SwarmDaemon) removeNode(c *check.C, id string, force bool) { 212 url := "/nodes/" + id 213 if force { 214 url += "?force=1" 215 } 216 217 status, out, err := d.SockRequest("DELETE", url, nil) 218 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 219 c.Assert(err, checker.IsNil) 220 } 221 222 func (d *SwarmDaemon) updateNode(c *check.C, id string, f ...nodeConstructor) { 223 for i := 0; ; i++ { 224 node := d.getNode(c, id) 225 for _, fn := range f { 226 fn(node) 227 } 228 url := fmt.Sprintf("/nodes/%s/update?version=%d", node.ID, node.Version.Index) 229 status, out, err := d.SockRequest("POST", url, node.Spec) 230 if i < 10 && strings.Contains(string(out), "update out of sequence") { 231 time.Sleep(100 * time.Millisecond) 232 continue 233 } 234 c.Assert(err, checker.IsNil) 235 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 236 return 237 } 238 } 239 240 func (d *SwarmDaemon) listNodes(c *check.C) []swarm.Node { 241 status, out, err := d.SockRequest("GET", "/nodes", nil) 242 c.Assert(err, checker.IsNil) 243 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 244 245 nodes := []swarm.Node{} 246 c.Assert(json.Unmarshal(out, &nodes), checker.IsNil) 247 return nodes 248 } 249 250 func (d *SwarmDaemon) listServices(c *check.C) []swarm.Service { 251 status, out, err := d.SockRequest("GET", "/services", nil) 252 c.Assert(err, checker.IsNil) 253 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 254 255 services := []swarm.Service{} 256 c.Assert(json.Unmarshal(out, &services), checker.IsNil) 257 return services 258 } 259 260 func (d *SwarmDaemon) getSwarm(c *check.C) swarm.Swarm { 261 var sw swarm.Swarm 262 status, out, err := d.SockRequest("GET", "/swarm", nil) 263 c.Assert(err, checker.IsNil) 264 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 265 c.Assert(json.Unmarshal(out, &sw), checker.IsNil) 266 return sw 267 } 268 269 func (d *SwarmDaemon) updateSwarm(c *check.C, f ...specConstructor) { 270 sw := d.getSwarm(c) 271 for _, fn := range f { 272 fn(&sw.Spec) 273 } 274 url := fmt.Sprintf("/swarm/update?version=%d", sw.Version.Index) 275 status, out, err := d.SockRequest("POST", url, sw.Spec) 276 c.Assert(err, checker.IsNil) 277 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 278 } 279 280 func (d *SwarmDaemon) rotateTokens(c *check.C) { 281 var sw swarm.Swarm 282 status, out, err := d.SockRequest("GET", "/swarm", nil) 283 c.Assert(err, checker.IsNil) 284 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 285 c.Assert(json.Unmarshal(out, &sw), checker.IsNil) 286 287 url := fmt.Sprintf("/swarm/update?version=%d&rotateWorkerToken=true&rotateManagerToken=true", sw.Version.Index) 288 status, out, err = d.SockRequest("POST", url, sw.Spec) 289 c.Assert(err, checker.IsNil) 290 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 291 } 292 293 func (d *SwarmDaemon) joinTokens(c *check.C) swarm.JoinTokens { 294 var sw swarm.Swarm 295 status, out, err := d.SockRequest("GET", "/swarm", nil) 296 c.Assert(err, checker.IsNil) 297 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 298 c.Assert(json.Unmarshal(out, &sw), checker.IsNil) 299 return sw.JoinTokens 300 } 301 302 func (d *SwarmDaemon) checkLocalNodeState(c *check.C) (interface{}, check.CommentInterface) { 303 info, err := d.info() 304 c.Assert(err, checker.IsNil) 305 return info.LocalNodeState, nil 306 } 307 308 func (d *SwarmDaemon) checkControlAvailable(c *check.C) (interface{}, check.CommentInterface) { 309 info, err := d.info() 310 c.Assert(err, checker.IsNil) 311 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 312 return info.ControlAvailable, nil 313 } 314 315 func (d *SwarmDaemon) cmdRetryOutOfSequence(args ...string) (string, error) { 316 for i := 0; ; i++ { 317 out, err := d.Cmd(args[0], args[1:]...) 318 if err != nil { 319 if strings.Contains(err.Error(), "update out of sequence") { 320 if i < 10 { 321 continue 322 } 323 } 324 } 325 return out, err 326 } 327 }