github.com/nullne/docker@v1.13.0-rc1/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/api/types" 11 "github.com/docker/docker/api/types/filters" 12 "github.com/docker/docker/api/types/swarm" 13 "github.com/docker/docker/pkg/integration/checker" 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, check.Commentf(string(out))) 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(err, checker.IsNil, check.Commentf(string(out))) 121 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 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(err, checker.IsNil, check.Commentf(string(out))) 137 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 138 c.Assert(json.Unmarshal(out, &tasks), checker.IsNil) 139 return tasks 140 } 141 142 func (d *SwarmDaemon) checkServiceRunningTasks(service string) func(*check.C) (interface{}, check.CommentInterface) { 143 return func(c *check.C) (interface{}, check.CommentInterface) { 144 tasks := d.getServiceTasks(c, service) 145 var runningCount int 146 for _, task := range tasks { 147 if task.Status.State == swarm.TaskStateRunning { 148 runningCount++ 149 } 150 } 151 return runningCount, nil 152 } 153 } 154 155 func (d *SwarmDaemon) checkServiceUpdateState(service string) func(*check.C) (interface{}, check.CommentInterface) { 156 return func(c *check.C) (interface{}, check.CommentInterface) { 157 service := d.getService(c, service) 158 return service.UpdateStatus.State, nil 159 } 160 } 161 162 func (d *SwarmDaemon) checkServiceTasks(service string) func(*check.C) (interface{}, check.CommentInterface) { 163 return func(c *check.C) (interface{}, check.CommentInterface) { 164 tasks := d.getServiceTasks(c, service) 165 return len(tasks), nil 166 } 167 } 168 169 func (d *SwarmDaemon) checkRunningTaskImages(c *check.C) (interface{}, check.CommentInterface) { 170 var tasks []swarm.Task 171 172 filterArgs := filters.NewArgs() 173 filterArgs.Add("desired-state", "running") 174 filters, err := filters.ToParam(filterArgs) 175 c.Assert(err, checker.IsNil) 176 177 status, out, err := d.SockRequest("GET", "/tasks?filters="+filters, nil) 178 c.Assert(err, checker.IsNil, check.Commentf(string(out))) 179 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 180 c.Assert(json.Unmarshal(out, &tasks), checker.IsNil) 181 182 result := make(map[string]int) 183 for _, task := range tasks { 184 if task.Status.State == swarm.TaskStateRunning { 185 result[task.Spec.ContainerSpec.Image]++ 186 } 187 } 188 return result, nil 189 } 190 191 func (d *SwarmDaemon) checkNodeReadyCount(c *check.C) (interface{}, check.CommentInterface) { 192 nodes := d.listNodes(c) 193 var readyCount int 194 for _, node := range nodes { 195 if node.Status.State == swarm.NodeStateReady { 196 readyCount++ 197 } 198 } 199 return readyCount, nil 200 } 201 202 func (d *SwarmDaemon) getTask(c *check.C, id string) swarm.Task { 203 var task swarm.Task 204 205 status, out, err := d.SockRequest("GET", "/tasks/"+id, nil) 206 c.Assert(err, checker.IsNil, check.Commentf(string(out))) 207 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 208 c.Assert(json.Unmarshal(out, &task), checker.IsNil) 209 return task 210 } 211 212 func (d *SwarmDaemon) updateService(c *check.C, service *swarm.Service, f ...serviceConstructor) { 213 for _, fn := range f { 214 fn(service) 215 } 216 url := fmt.Sprintf("/services/%s/update?version=%d", service.ID, service.Version.Index) 217 status, out, err := d.SockRequest("POST", url, service.Spec) 218 c.Assert(err, checker.IsNil, check.Commentf(string(out))) 219 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 220 } 221 222 func (d *SwarmDaemon) removeService(c *check.C, id string) { 223 status, out, err := d.SockRequest("DELETE", "/services/"+id, nil) 224 c.Assert(err, checker.IsNil, check.Commentf(string(out))) 225 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 226 } 227 228 func (d *SwarmDaemon) getNode(c *check.C, id string) *swarm.Node { 229 var node swarm.Node 230 status, out, err := d.SockRequest("GET", "/nodes/"+id, nil) 231 c.Assert(err, checker.IsNil, check.Commentf(string(out))) 232 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 233 c.Assert(json.Unmarshal(out, &node), checker.IsNil) 234 c.Assert(node.ID, checker.Equals, id) 235 return &node 236 } 237 238 func (d *SwarmDaemon) removeNode(c *check.C, id string, force bool) { 239 url := "/nodes/" + id 240 if force { 241 url += "?force=1" 242 } 243 244 status, out, err := d.SockRequest("DELETE", url, nil) 245 c.Assert(err, checker.IsNil, check.Commentf(string(out))) 246 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 247 } 248 249 func (d *SwarmDaemon) updateNode(c *check.C, id string, f ...nodeConstructor) { 250 for i := 0; ; i++ { 251 node := d.getNode(c, id) 252 for _, fn := range f { 253 fn(node) 254 } 255 url := fmt.Sprintf("/nodes/%s/update?version=%d", node.ID, node.Version.Index) 256 status, out, err := d.SockRequest("POST", url, node.Spec) 257 if i < 10 && strings.Contains(string(out), "update out of sequence") { 258 time.Sleep(100 * time.Millisecond) 259 continue 260 } 261 c.Assert(err, checker.IsNil, check.Commentf(string(out))) 262 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 263 return 264 } 265 } 266 267 func (d *SwarmDaemon) listNodes(c *check.C) []swarm.Node { 268 status, out, err := d.SockRequest("GET", "/nodes", nil) 269 c.Assert(err, checker.IsNil, check.Commentf(string(out))) 270 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 271 272 nodes := []swarm.Node{} 273 c.Assert(json.Unmarshal(out, &nodes), checker.IsNil) 274 return nodes 275 } 276 277 func (d *SwarmDaemon) listServices(c *check.C) []swarm.Service { 278 status, out, err := d.SockRequest("GET", "/services", nil) 279 c.Assert(err, checker.IsNil, check.Commentf(string(out))) 280 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 281 282 services := []swarm.Service{} 283 c.Assert(json.Unmarshal(out, &services), checker.IsNil) 284 return services 285 } 286 287 func (d *SwarmDaemon) createSecret(c *check.C, secretSpec swarm.SecretSpec) string { 288 status, out, err := d.SockRequest("POST", "/secrets", secretSpec) 289 290 c.Assert(err, checker.IsNil, check.Commentf(string(out))) 291 c.Assert(status, checker.Equals, http.StatusCreated, check.Commentf("output: %q", string(out))) 292 293 var scr types.SecretCreateResponse 294 c.Assert(json.Unmarshal(out, &scr), checker.IsNil) 295 return scr.ID 296 } 297 298 func (d *SwarmDaemon) listSecrets(c *check.C) []swarm.Secret { 299 status, out, err := d.SockRequest("GET", "/secrets", nil) 300 c.Assert(err, checker.IsNil, check.Commentf(string(out))) 301 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 302 303 secrets := []swarm.Secret{} 304 c.Assert(json.Unmarshal(out, &secrets), checker.IsNil) 305 return secrets 306 } 307 308 func (d *SwarmDaemon) getSecret(c *check.C, id string) *swarm.Secret { 309 var secret swarm.Secret 310 status, out, err := d.SockRequest("GET", "/secrets/"+id, nil) 311 c.Assert(err, checker.IsNil, check.Commentf(string(out))) 312 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 313 c.Assert(json.Unmarshal(out, &secret), checker.IsNil) 314 return &secret 315 } 316 317 func (d *SwarmDaemon) deleteSecret(c *check.C, id string) { 318 status, out, err := d.SockRequest("DELETE", "/secrets/"+id, nil) 319 c.Assert(err, checker.IsNil, check.Commentf(string(out))) 320 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 321 } 322 323 func (d *SwarmDaemon) getSwarm(c *check.C) swarm.Swarm { 324 var sw swarm.Swarm 325 status, out, err := d.SockRequest("GET", "/swarm", nil) 326 c.Assert(err, checker.IsNil, check.Commentf(string(out))) 327 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 328 c.Assert(json.Unmarshal(out, &sw), checker.IsNil) 329 return sw 330 } 331 332 func (d *SwarmDaemon) updateSwarm(c *check.C, f ...specConstructor) { 333 sw := d.getSwarm(c) 334 for _, fn := range f { 335 fn(&sw.Spec) 336 } 337 url := fmt.Sprintf("/swarm/update?version=%d", sw.Version.Index) 338 status, out, err := d.SockRequest("POST", url, sw.Spec) 339 c.Assert(err, checker.IsNil, check.Commentf(string(out))) 340 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 341 } 342 343 func (d *SwarmDaemon) rotateTokens(c *check.C) { 344 var sw swarm.Swarm 345 status, out, err := d.SockRequest("GET", "/swarm", nil) 346 c.Assert(err, checker.IsNil, check.Commentf(string(out))) 347 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 348 c.Assert(json.Unmarshal(out, &sw), checker.IsNil) 349 350 url := fmt.Sprintf("/swarm/update?version=%d&rotateWorkerToken=true&rotateManagerToken=true", sw.Version.Index) 351 status, out, err = d.SockRequest("POST", url, sw.Spec) 352 c.Assert(err, checker.IsNil, check.Commentf(string(out))) 353 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 354 } 355 356 func (d *SwarmDaemon) joinTokens(c *check.C) swarm.JoinTokens { 357 var sw swarm.Swarm 358 status, out, err := d.SockRequest("GET", "/swarm", nil) 359 c.Assert(err, checker.IsNil, check.Commentf(string(out))) 360 c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) 361 c.Assert(json.Unmarshal(out, &sw), checker.IsNil) 362 return sw.JoinTokens 363 } 364 365 func (d *SwarmDaemon) checkLocalNodeState(c *check.C) (interface{}, check.CommentInterface) { 366 info, err := d.info() 367 c.Assert(err, checker.IsNil) 368 return info.LocalNodeState, nil 369 } 370 371 func (d *SwarmDaemon) checkControlAvailable(c *check.C) (interface{}, check.CommentInterface) { 372 info, err := d.info() 373 c.Assert(err, checker.IsNil) 374 c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive) 375 return info.ControlAvailable, nil 376 } 377 378 func (d *SwarmDaemon) checkLeader(c *check.C) (interface{}, check.CommentInterface) { 379 errList := check.Commentf("could not get node list") 380 status, out, err := d.SockRequest("GET", "/nodes", nil) 381 if err != nil { 382 return err, errList 383 } 384 if status != http.StatusOK { 385 return fmt.Errorf("expected http status OK, got: %d", status), errList 386 } 387 388 var ls []swarm.Node 389 if err := json.Unmarshal(out, &ls); err != nil { 390 return err, errList 391 } 392 393 for _, node := range ls { 394 if node.ManagerStatus != nil && node.ManagerStatus.Leader { 395 return nil, nil 396 } 397 } 398 return fmt.Errorf("no leader"), check.Commentf("could not find leader") 399 } 400 401 func (d *SwarmDaemon) cmdRetryOutOfSequence(args ...string) (string, error) { 402 for i := 0; ; i++ { 403 out, err := d.Cmd(args...) 404 if err != nil { 405 if strings.Contains(out, "update out of sequence") { 406 if i < 10 { 407 continue 408 } 409 } 410 } 411 return out, err 412 } 413 }