daemon_swarm.go 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "net/http"
  6. "strings"
  7. "time"
  8. "github.com/docker/docker/pkg/integration/checker"
  9. "github.com/docker/engine-api/types"
  10. "github.com/docker/engine-api/types/filters"
  11. "github.com/docker/engine-api/types/swarm"
  12. "github.com/go-check/check"
  13. )
  14. // SwarmDaemon is a test daemon with helpers for participating in a swarm.
  15. type SwarmDaemon struct {
  16. *Daemon
  17. swarm.Info
  18. port int
  19. listenAddr string
  20. }
  21. // default policy in tests is allow-all
  22. var autoAcceptPolicy = swarm.AcceptancePolicy{
  23. Policies: []swarm.Policy{
  24. {Role: swarm.NodeRoleWorker, Autoaccept: true},
  25. {Role: swarm.NodeRoleManager, Autoaccept: true},
  26. },
  27. }
  28. // Init initializes a new swarm cluster.
  29. func (d *SwarmDaemon) Init(req swarm.InitRequest) error {
  30. if req.ListenAddr == "" {
  31. req.ListenAddr = d.listenAddr
  32. }
  33. status, out, err := d.SockRequest("POST", "/swarm/init", req)
  34. if status != http.StatusOK {
  35. return fmt.Errorf("initializing swarm: invalid statuscode %v, %q", status, out)
  36. }
  37. if err != nil {
  38. return fmt.Errorf("initializing swarm: %v", err)
  39. }
  40. info, err := d.info()
  41. if err != nil {
  42. return err
  43. }
  44. d.Info = info
  45. return nil
  46. }
  47. // Join joins a daemon to an existing cluster.
  48. func (d *SwarmDaemon) Join(req swarm.JoinRequest) error {
  49. if req.ListenAddr == "" {
  50. req.ListenAddr = d.listenAddr
  51. }
  52. status, out, err := d.SockRequest("POST", "/swarm/join", req)
  53. if status != http.StatusOK {
  54. return fmt.Errorf("joining swarm: invalid statuscode %v, %q", status, out)
  55. }
  56. if err != nil {
  57. return fmt.Errorf("joining swarm: %v", err)
  58. }
  59. info, err := d.info()
  60. if err != nil {
  61. return err
  62. }
  63. d.Info = info
  64. return nil
  65. }
  66. // Leave forces daemon to leave current cluster.
  67. func (d *SwarmDaemon) Leave(force bool) error {
  68. url := "/swarm/leave"
  69. if force {
  70. url += "?force=1"
  71. }
  72. status, out, err := d.SockRequest("POST", url, nil)
  73. if status != http.StatusOK {
  74. return fmt.Errorf("leaving swarm: invalid statuscode %v, %q", status, out)
  75. }
  76. if err != nil {
  77. err = fmt.Errorf("leaving swarm: %v", err)
  78. }
  79. return err
  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. type serviceConstructor func(*swarm.Service)
  98. type nodeConstructor func(*swarm.Node)
  99. type specConstructor func(*swarm.Spec)
  100. func (d *SwarmDaemon) createService(c *check.C, f ...serviceConstructor) string {
  101. var service swarm.Service
  102. for _, fn := range f {
  103. fn(&service)
  104. }
  105. status, out, err := d.SockRequest("POST", "/services/create", service.Spec)
  106. c.Assert(err, checker.IsNil)
  107. c.Assert(status, checker.Equals, http.StatusCreated, check.Commentf("output: %q", string(out)))
  108. var scr types.ServiceCreateResponse
  109. c.Assert(json.Unmarshal(out, &scr), checker.IsNil)
  110. return scr.ID
  111. }
  112. func (d *SwarmDaemon) getService(c *check.C, id string) *swarm.Service {
  113. var service swarm.Service
  114. status, out, err := d.SockRequest("GET", "/services/"+id, nil)
  115. c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
  116. c.Assert(err, checker.IsNil)
  117. c.Assert(json.Unmarshal(out, &service), checker.IsNil)
  118. c.Assert(service.ID, checker.Equals, id)
  119. return &service
  120. }
  121. func (d *SwarmDaemon) getServiceTasks(c *check.C, service string) []swarm.Task {
  122. var tasks []swarm.Task
  123. filterArgs := filters.NewArgs()
  124. filterArgs.Add("desired-state", "running")
  125. filterArgs.Add("service", service)
  126. filters, err := filters.ToParam(filterArgs)
  127. c.Assert(err, checker.IsNil)
  128. status, out, err := d.SockRequest("GET", "/tasks?filters="+filters, nil)
  129. c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
  130. c.Assert(err, checker.IsNil, check.Commentf(string(out)))
  131. c.Assert(json.Unmarshal(out, &tasks), checker.IsNil)
  132. return tasks
  133. }
  134. func (d *SwarmDaemon) checkRunningTaskImages(c *check.C) (interface{}, check.CommentInterface) {
  135. var tasks []swarm.Task
  136. filterArgs := filters.NewArgs()
  137. filterArgs.Add("desired-state", "running")
  138. filters, err := filters.ToParam(filterArgs)
  139. c.Assert(err, checker.IsNil)
  140. status, out, err := d.SockRequest("GET", "/tasks?filters="+filters, nil)
  141. c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
  142. c.Assert(err, checker.IsNil, check.Commentf(string(out)))
  143. c.Assert(json.Unmarshal(out, &tasks), checker.IsNil)
  144. result := make(map[string]int)
  145. for _, task := range tasks {
  146. if task.Status.State == swarm.TaskStateRunning {
  147. result[task.Spec.ContainerSpec.Image]++
  148. }
  149. }
  150. return result, nil
  151. }
  152. func (d *SwarmDaemon) checkNodeReadyCount(c *check.C) (interface{}, check.CommentInterface) {
  153. nodes := d.listNodes(c)
  154. var readyCount int
  155. for _, node := range nodes {
  156. if node.Status.State == swarm.NodeStateReady {
  157. readyCount++
  158. }
  159. }
  160. return readyCount, nil
  161. }
  162. func (d *SwarmDaemon) getTask(c *check.C, id string) swarm.Task {
  163. var task swarm.Task
  164. status, out, err := d.SockRequest("GET", "/tasks/"+id, nil)
  165. c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
  166. c.Assert(err, checker.IsNil, check.Commentf(string(out)))
  167. c.Assert(json.Unmarshal(out, &task), checker.IsNil)
  168. return task
  169. }
  170. func (d *SwarmDaemon) updateService(c *check.C, service *swarm.Service, f ...serviceConstructor) {
  171. for _, fn := range f {
  172. fn(service)
  173. }
  174. url := fmt.Sprintf("/services/%s/update?version=%d", service.ID, service.Version.Index)
  175. status, out, err := d.SockRequest("POST", url, service.Spec)
  176. c.Assert(err, checker.IsNil)
  177. c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
  178. }
  179. func (d *SwarmDaemon) removeService(c *check.C, id string) {
  180. status, out, err := d.SockRequest("DELETE", "/services/"+id, nil)
  181. c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
  182. c.Assert(err, checker.IsNil)
  183. }
  184. func (d *SwarmDaemon) getNode(c *check.C, id string) *swarm.Node {
  185. var node swarm.Node
  186. status, out, err := d.SockRequest("GET", "/nodes/"+id, nil)
  187. c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
  188. c.Assert(err, checker.IsNil)
  189. c.Assert(json.Unmarshal(out, &node), checker.IsNil)
  190. c.Assert(node.ID, checker.Equals, id)
  191. return &node
  192. }
  193. func (d *SwarmDaemon) updateNode(c *check.C, id string, f ...nodeConstructor) {
  194. for i := 0; ; i++ {
  195. node := d.getNode(c, id)
  196. for _, fn := range f {
  197. fn(node)
  198. }
  199. url := fmt.Sprintf("/nodes/%s/update?version=%d", node.ID, node.Version.Index)
  200. status, out, err := d.SockRequest("POST", url, node.Spec)
  201. if i < 10 && strings.Contains(string(out), "update out of sequence") {
  202. time.Sleep(100 * time.Millisecond)
  203. continue
  204. }
  205. c.Assert(err, checker.IsNil)
  206. c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
  207. return
  208. }
  209. }
  210. func (d *SwarmDaemon) listNodes(c *check.C) []swarm.Node {
  211. status, out, err := d.SockRequest("GET", "/nodes", nil)
  212. c.Assert(err, checker.IsNil)
  213. c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
  214. nodes := []swarm.Node{}
  215. c.Assert(json.Unmarshal(out, &nodes), checker.IsNil)
  216. return nodes
  217. }
  218. func (d *SwarmDaemon) listServices(c *check.C) []swarm.Service {
  219. status, out, err := d.SockRequest("GET", "/services", nil)
  220. c.Assert(err, checker.IsNil)
  221. c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
  222. services := []swarm.Service{}
  223. c.Assert(json.Unmarshal(out, &services), checker.IsNil)
  224. return services
  225. }
  226. func (d *SwarmDaemon) updateSwarm(c *check.C, f ...specConstructor) {
  227. var sw swarm.Swarm
  228. status, out, err := d.SockRequest("GET", "/swarm", nil)
  229. c.Assert(err, checker.IsNil)
  230. c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
  231. c.Assert(json.Unmarshal(out, &sw), checker.IsNil)
  232. for _, fn := range f {
  233. fn(&sw.Spec)
  234. }
  235. url := fmt.Sprintf("/swarm/update?version=%d", sw.Version.Index)
  236. status, out, err = d.SockRequest("POST", url, sw.Spec)
  237. c.Assert(err, checker.IsNil)
  238. c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
  239. }
  240. func (d *SwarmDaemon) checkLocalNodeState(c *check.C) (interface{}, check.CommentInterface) {
  241. info, err := d.info()
  242. c.Assert(err, checker.IsNil)
  243. return info.LocalNodeState, nil
  244. }
  245. func (d *SwarmDaemon) checkControlAvailable(c *check.C) (interface{}, check.CommentInterface) {
  246. info, err := d.info()
  247. c.Assert(err, checker.IsNil)
  248. c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
  249. return info.ControlAvailable, nil
  250. }