github.com/go/docker@v1.12.0-rc2/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/swarm"
    13  	"github.com/go-check/check"
    14  )
    15  
    16  // SwarmDaemon is a test daemon with helpers for participating in a swarm.
    17  type SwarmDaemon struct {
    18  	*Daemon
    19  	swarm.Info
    20  	port       int
    21  	listenAddr string
    22  }
    23  
    24  // Init initializes a new swarm cluster.
    25  func (d *SwarmDaemon) Init(autoAccept map[string]bool, secret string) error {
    26  	req := swarm.InitRequest{
    27  		ListenAddr: d.listenAddr,
    28  	}
    29  	for _, role := range []swarm.NodeRole{swarm.NodeRoleManager, swarm.NodeRoleWorker} {
    30  		policy := swarm.Policy{
    31  			Role:       role,
    32  			Autoaccept: autoAccept[strings.ToLower(string(role))],
    33  		}
    34  
    35  		if secret != "" {
    36  			policy.Secret = &secret
    37  		}
    38  
    39  		req.Spec.AcceptancePolicy.Policies = append(req.Spec.AcceptancePolicy.Policies, policy)
    40  	}
    41  	status, out, err := d.SockRequest("POST", "/swarm/init", req)
    42  	if status != http.StatusOK {
    43  		return fmt.Errorf("initializing swarm: invalid statuscode %v, %q", status, out)
    44  	}
    45  	if err != nil {
    46  		return fmt.Errorf("initializing swarm: %v", err)
    47  	}
    48  	info, err := d.info()
    49  	if err != nil {
    50  		return err
    51  	}
    52  	d.Info = info
    53  	return nil
    54  }
    55  
    56  // Join joins a current daemon with existing cluster.
    57  func (d *SwarmDaemon) Join(remoteAddr, secret, cahash string, manager bool) error {
    58  	req := swarm.JoinRequest{
    59  		ListenAddr:  d.listenAddr,
    60  		RemoteAddrs: []string{remoteAddr},
    61  		Manager:     manager,
    62  		CACertHash:  cahash,
    63  	}
    64  
    65  	if secret != "" {
    66  		req.Secret = secret
    67  	}
    68  	status, out, err := d.SockRequest("POST", "/swarm/join", req)
    69  	if status != http.StatusOK {
    70  		return fmt.Errorf("joining swarm: invalid statuscode %v, %q", status, out)
    71  	}
    72  	if err != nil {
    73  		return fmt.Errorf("joining swarm: %v", err)
    74  	}
    75  	info, err := d.info()
    76  	if err != nil {
    77  		return err
    78  	}
    79  	d.Info = info
    80  	return nil
    81  }
    82  
    83  // Leave forces daemon to leave current cluster.
    84  func (d *SwarmDaemon) Leave(force bool) error {
    85  	url := "/swarm/leave"
    86  	if force {
    87  		url += "?force=1"
    88  	}
    89  	status, out, err := d.SockRequest("POST", url, nil)
    90  	if status != http.StatusOK {
    91  		return fmt.Errorf("leaving swarm: invalid statuscode %v, %q", status, out)
    92  	}
    93  	if err != nil {
    94  		err = fmt.Errorf("leaving swarm: %v", err)
    95  	}
    96  	return err
    97  }
    98  
    99  func (d *SwarmDaemon) info() (swarm.Info, error) {
   100  	var info struct {
   101  		Swarm swarm.Info
   102  	}
   103  	status, dt, err := d.SockRequest("GET", "/info", nil)
   104  	if status != http.StatusOK {
   105  		return info.Swarm, fmt.Errorf("get swarm info: invalid statuscode %v", status)
   106  	}
   107  	if err != nil {
   108  		return info.Swarm, fmt.Errorf("get swarm info: %v", err)
   109  	}
   110  	if err := json.Unmarshal(dt, &info); err != nil {
   111  		return info.Swarm, err
   112  	}
   113  	return info.Swarm, nil
   114  }
   115  
   116  type serviceConstructor func(*swarm.Service)
   117  type nodeConstructor func(*swarm.Node)
   118  type specConstructor func(*swarm.Spec)
   119  
   120  func (d *SwarmDaemon) createService(c *check.C, f ...serviceConstructor) string {
   121  	var service swarm.Service
   122  	for _, fn := range f {
   123  		fn(&service)
   124  	}
   125  	status, out, err := d.SockRequest("POST", "/services/create", service.Spec)
   126  
   127  	c.Assert(err, checker.IsNil)
   128  	c.Assert(status, checker.Equals, http.StatusCreated, check.Commentf("output: %q", string(out)))
   129  
   130  	var scr types.ServiceCreateResponse
   131  	c.Assert(json.Unmarshal(out, &scr), checker.IsNil)
   132  	return scr.ID
   133  }
   134  
   135  func (d *SwarmDaemon) getService(c *check.C, id string) *swarm.Service {
   136  	var service swarm.Service
   137  	status, out, err := d.SockRequest("GET", "/services/"+id, nil)
   138  	c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
   139  	c.Assert(err, checker.IsNil)
   140  	c.Assert(json.Unmarshal(out, &service), checker.IsNil)
   141  	c.Assert(service.ID, checker.Equals, id)
   142  	return &service
   143  }
   144  
   145  func (d *SwarmDaemon) updateService(c *check.C, service *swarm.Service, f ...serviceConstructor) {
   146  	for _, fn := range f {
   147  		fn(service)
   148  	}
   149  	url := fmt.Sprintf("/services/%s/update?version=%d", service.ID, service.Version.Index)
   150  	status, out, err := d.SockRequest("POST", url, service.Spec)
   151  	c.Assert(err, checker.IsNil)
   152  	c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
   153  }
   154  
   155  func (d *SwarmDaemon) removeService(c *check.C, id string) {
   156  	status, out, err := d.SockRequest("DELETE", "/services/"+id, nil)
   157  	c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
   158  	c.Assert(err, checker.IsNil)
   159  }
   160  
   161  func (d *SwarmDaemon) getNode(c *check.C, id string) *swarm.Node {
   162  	var node swarm.Node
   163  	status, out, err := d.SockRequest("GET", "/nodes/"+id, nil)
   164  	c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
   165  	c.Assert(err, checker.IsNil)
   166  	c.Assert(json.Unmarshal(out, &node), checker.IsNil)
   167  	c.Assert(node.ID, checker.Equals, id)
   168  	return &node
   169  }
   170  
   171  func (d *SwarmDaemon) updateNode(c *check.C, id string, f ...nodeConstructor) {
   172  	for i := 0; ; i++ {
   173  		node := d.getNode(c, id)
   174  		for _, fn := range f {
   175  			fn(node)
   176  		}
   177  		url := fmt.Sprintf("/nodes/%s/update?version=%d", node.ID, node.Version.Index)
   178  		status, out, err := d.SockRequest("POST", url, node.Spec)
   179  		if i < 10 && strings.Contains(string(out), "update out of sequence") {
   180  			time.Sleep(100 * time.Millisecond)
   181  			continue
   182  		}
   183  		c.Assert(err, checker.IsNil)
   184  		c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
   185  		return
   186  	}
   187  }
   188  
   189  func (d *SwarmDaemon) listNodes(c *check.C) []swarm.Node {
   190  	status, out, err := d.SockRequest("GET", "/nodes", nil)
   191  	c.Assert(err, checker.IsNil)
   192  	c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
   193  
   194  	nodes := []swarm.Node{}
   195  	c.Assert(json.Unmarshal(out, &nodes), checker.IsNil)
   196  	return nodes
   197  }
   198  
   199  func (d *SwarmDaemon) updateSwarm(c *check.C, f ...specConstructor) {
   200  	var sw swarm.Swarm
   201  	status, out, err := d.SockRequest("GET", "/swarm", nil)
   202  	c.Assert(err, checker.IsNil)
   203  	c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
   204  	c.Assert(json.Unmarshal(out, &sw), checker.IsNil)
   205  
   206  	for _, fn := range f {
   207  		fn(&sw.Spec)
   208  	}
   209  	url := fmt.Sprintf("/swarm/update?version=%d", sw.Version.Index)
   210  	status, out, err = d.SockRequest("POST", url, sw.Spec)
   211  	c.Assert(err, checker.IsNil)
   212  	c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
   213  }