diff --git a/integration-cli/daemon/daemon.go b/integration-cli/daemon/daemon.go index aa1da1a690..05b5255661 100644 --- a/integration-cli/daemon/daemon.go +++ b/integration-cli/daemon/daemon.go @@ -14,8 +14,10 @@ import ( "strings" "time" + "github.com/docker/docker/api" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/events" + "github.com/docker/docker/client" "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/request" "github.com/docker/docker/opts" @@ -752,6 +754,16 @@ func (d *Daemon) ReloadConfig() error { return nil } +// NewClient creates new client based on daemon's socket path +func (d *Daemon) NewClient() (*client.Client, error) { + httpClient, err := request.NewHTTPClient(d.Sock()) + if err != nil { + return nil, err + } + + return client.NewClient(d.Sock(), api.DefaultVersion, httpClient, nil) +} + // WaitInspectWithArgs waits for the specified expression to be equals to the specified expected string in the given time. // Deprecated: use cli.WaitCmd instead func WaitInspectWithArgs(dockerBinary, name, expr, expected string, timeout time.Duration, arg ...string) error { diff --git a/integration-cli/daemon/daemon_swarm.go b/integration-cli/daemon/daemon_swarm.go index ba414066cc..c37c7269f5 100644 --- a/integration-cli/daemon/daemon_swarm.go +++ b/integration-cli/daemon/daemon_swarm.go @@ -1,7 +1,6 @@ package daemon import ( - "context" "encoding/json" "fmt" "net/http" @@ -11,10 +10,10 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/client" "github.com/docker/docker/integration-cli/checker" "github.com/go-check/check" "github.com/pkg/errors" + "golang.org/x/net/context" ) // Swarm is a test daemon with helpers for participating in a swarm. @@ -30,10 +29,12 @@ func (d *Swarm) Init(req swarm.InitRequest) error { if req.ListenAddr == "" { req.ListenAddr = d.ListenAddr } - status, out, err := d.SockRequest("POST", "/swarm/init", req) - if status != http.StatusOK { - return fmt.Errorf("initializing swarm: invalid statuscode %v, %q", status, out) + cli, err := d.NewClient() + if err != nil { + return fmt.Errorf("initializing swarm: failed to create client %v", err) } + defer cli.Close() + _, err = cli.SwarmInit(context.Background(), req) if err != nil { return fmt.Errorf("initializing swarm: %v", err) } @@ -50,10 +51,12 @@ func (d *Swarm) Join(req swarm.JoinRequest) error { if req.ListenAddr == "" { req.ListenAddr = d.ListenAddr } - status, out, err := d.SockRequest("POST", "/swarm/join", req) - if status != http.StatusOK { - return fmt.Errorf("joining swarm: invalid statuscode %v, %q", status, out) + cli, err := d.NewClient() + if err != nil { + return fmt.Errorf("joining swarm: failed to create client %v", err) } + defer cli.Close() + err = cli.SwarmJoin(context.Background(), req) if err != nil { return fmt.Errorf("joining swarm: %v", err) } @@ -67,14 +70,12 @@ func (d *Swarm) Join(req swarm.JoinRequest) error { // Leave forces daemon to leave current cluster. func (d *Swarm) Leave(force bool) error { - url := "/swarm/leave" - if force { - url += "?force=1" - } - status, out, err := d.SockRequest("POST", url, nil) - if status != http.StatusOK { - return fmt.Errorf("leaving swarm: invalid statuscode %v, %q", status, out) + cli, err := d.NewClient() + if err != nil { + return fmt.Errorf("leaving swarm: failed to create client %v", err) } + defer cli.Close() + err = cli.SwarmLeave(context.Background(), force) if err != nil { err = fmt.Errorf("leaving swarm: %v", err) } @@ -83,28 +84,27 @@ func (d *Swarm) Leave(force bool) error { // SwarmInfo returns the swarm information of the daemon func (d *Swarm) SwarmInfo() (swarm.Info, error) { - var info struct { - Swarm swarm.Info - } - status, dt, err := d.SockRequest("GET", "/info", nil) - if status != http.StatusOK { - return info.Swarm, fmt.Errorf("get swarm info: invalid statuscode %v", status) - } + cli, err := d.NewClient() if err != nil { - return info.Swarm, fmt.Errorf("get swarm info: %v", err) + return swarm.Info{}, fmt.Errorf("get swarm info: %v", err) } - if err := json.Unmarshal(dt, &info); err != nil { - return info.Swarm, err + + info, err := cli.Info(context.Background()) + if err != nil { + return swarm.Info{}, fmt.Errorf("get swarm info: %v", err) } + return info.Swarm, nil } // Unlock tries to unlock a locked swarm func (d *Swarm) Unlock(req swarm.UnlockRequest) error { - status, out, err := d.SockRequest("POST", "/swarm/unlock", req) - if status != http.StatusOK { - return fmt.Errorf("unlocking swarm: invalid statuscode %v, %q", status, out) + cli, err := d.NewClient() + if err != nil { + return fmt.Errorf("unlocking swarm: failed to create client %v", err) } + defer cli.Close() + err = cli.SwarmUnlock(context.Background(), req) if err != nil { err = errors.Wrap(err, "unlocking swarm") } @@ -129,19 +129,19 @@ type SpecConstructor func(*swarm.Spec) // CreateServiceWithOptions creates a swarm service given the specified service constructors // and auth config func (d *Swarm) CreateServiceWithOptions(c *check.C, opts types.ServiceCreateOptions, f ...ServiceConstructor) string { - cl, err := client.NewClient(d.Sock(), "", nil, nil) - c.Assert(err, checker.IsNil, check.Commentf("failed to create client")) - defer cl.Close() - var service swarm.Service for _, fn := range f { fn(&service) } + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() - res, err := cl.ServiceCreate(ctx, service.Spec, opts) + res, err := cli.ServiceCreate(ctx, service.Spec, opts) c.Assert(err, checker.IsNil) return res.ID } @@ -153,28 +153,31 @@ func (d *Swarm) CreateService(c *check.C, f ...ServiceConstructor) string { // GetService returns the swarm service corresponding to the specified id func (d *Swarm) GetService(c *check.C, id string) *swarm.Service { - var service swarm.Service - status, out, err := d.SockRequest("GET", "/services/"+id, nil) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) - c.Assert(json.Unmarshal(out, &service), checker.IsNil) + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + service, _, err := cli.ServiceInspectWithRaw(context.Background(), id, types.ServiceInspectOptions{}) + c.Assert(err, checker.IsNil) return &service } // GetServiceTasks returns the swarm tasks for the specified service func (d *Swarm) GetServiceTasks(c *check.C, service string) []swarm.Task { - var tasks []swarm.Task + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() filterArgs := filters.NewArgs() filterArgs.Add("desired-state", "running") filterArgs.Add("service", service) - filters, err := filters.ToParam(filterArgs) - c.Assert(err, checker.IsNil) - status, out, err := d.SockRequest("GET", "/tasks?filters="+filters, nil) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) - c.Assert(json.Unmarshal(out, &tasks), checker.IsNil) + options := types.TaskListOptions{ + Filters: filterArgs, + } + + tasks, err := cli.TaskList(context.Background(), options) + c.Assert(err, checker.IsNil) return tasks } @@ -252,17 +255,19 @@ func (d *Swarm) CheckServiceTasks(service string) func(*check.C) (interface{}, c // CheckRunningTaskNetworks returns the number of times each network is referenced from a task. func (d *Swarm) CheckRunningTaskNetworks(c *check.C) (interface{}, check.CommentInterface) { - var tasks []swarm.Task + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() filterArgs := filters.NewArgs() filterArgs.Add("desired-state", "running") - filters, err := filters.ToParam(filterArgs) - c.Assert(err, checker.IsNil) - status, out, err := d.SockRequest("GET", "/tasks?filters="+filters, nil) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) - c.Assert(json.Unmarshal(out, &tasks), checker.IsNil) + options := types.TaskListOptions{ + Filters: filterArgs, + } + + tasks, err := cli.TaskList(context.Background(), options) + c.Assert(err, checker.IsNil) result := make(map[string]int) for _, task := range tasks { @@ -275,17 +280,19 @@ func (d *Swarm) CheckRunningTaskNetworks(c *check.C) (interface{}, check.Comment // CheckRunningTaskImages returns the times each image is running as a task. func (d *Swarm) CheckRunningTaskImages(c *check.C) (interface{}, check.CommentInterface) { - var tasks []swarm.Task + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() filterArgs := filters.NewArgs() filterArgs.Add("desired-state", "running") - filters, err := filters.ToParam(filterArgs) - c.Assert(err, checker.IsNil) - status, out, err := d.SockRequest("GET", "/tasks?filters="+filters, nil) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) - c.Assert(json.Unmarshal(out, &tasks), checker.IsNil) + options := types.TaskListOptions{ + Filters: filterArgs, + } + + tasks, err := cli.TaskList(context.Background(), options) + c.Assert(err, checker.IsNil) result := make(map[string]int) for _, task := range tasks { @@ -310,246 +317,281 @@ func (d *Swarm) CheckNodeReadyCount(c *check.C) (interface{}, check.CommentInter // GetTask returns the swarm task identified by the specified id func (d *Swarm) GetTask(c *check.C, id string) swarm.Task { - var task swarm.Task + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() - status, out, err := d.SockRequest("GET", "/tasks/"+id, nil) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) - c.Assert(json.Unmarshal(out, &task), checker.IsNil) + task, _, err := cli.TaskInspectWithRaw(context.Background(), id) + c.Assert(err, checker.IsNil) return task } // UpdateService updates a swarm service with the specified service constructor func (d *Swarm) UpdateService(c *check.C, service *swarm.Service, f ...ServiceConstructor) { + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + for _, fn := range f { fn(service) } - url := fmt.Sprintf("/services/%s/update?version=%d", service.ID, service.Version.Index) - status, out, err := d.SockRequest("POST", url, service.Spec) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) + + _, err = cli.ServiceUpdate(context.Background(), service.ID, service.Version, service.Spec, types.ServiceUpdateOptions{}) + c.Assert(err, checker.IsNil) } // RemoveService removes the specified service func (d *Swarm) RemoveService(c *check.C, id string) { - status, out, err := d.SockRequest("DELETE", "/services/"+id, nil) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + err = cli.ServiceRemove(context.Background(), id) + c.Assert(err, checker.IsNil) } // GetNode returns a swarm node identified by the specified id func (d *Swarm) GetNode(c *check.C, id string) *swarm.Node { - var node swarm.Node - status, out, err := d.SockRequest("GET", "/nodes/"+id, nil) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) - c.Assert(json.Unmarshal(out, &node), checker.IsNil) + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + node, _, err := cli.NodeInspectWithRaw(context.Background(), id) + c.Assert(err, checker.IsNil) c.Assert(node.ID, checker.Equals, id) return &node } // RemoveNode removes the specified node func (d *Swarm) RemoveNode(c *check.C, id string, force bool) { - url := "/nodes/" + id - if force { - url += "?force=1" - } + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() - status, out, err := d.SockRequest("DELETE", url, nil) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) + options := types.NodeRemoveOptions{ + Force: force, + } + err = cli.NodeRemove(context.Background(), id, options) + c.Assert(err, checker.IsNil) } // UpdateNode updates a swarm node with the specified node constructor func (d *Swarm) UpdateNode(c *check.C, id string, f ...NodeConstructor) { + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + for i := 0; ; i++ { node := d.GetNode(c, id) for _, fn := range f { fn(node) } - url := fmt.Sprintf("/nodes/%s/update?version=%d", node.ID, node.Version.Index) - status, out, err := d.SockRequest("POST", url, node.Spec) - if i < 10 && strings.Contains(string(out), "update out of sequence") { + + err = cli.NodeUpdate(context.Background(), node.ID, node.Version, node.Spec) + if i < 10 && err != nil && strings.Contains(err.Error(), "update out of sequence") { time.Sleep(100 * time.Millisecond) continue } - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) + c.Assert(err, checker.IsNil) return } } // ListNodes returns the list of the current swarm nodes func (d *Swarm) ListNodes(c *check.C) []swarm.Node { - status, out, err := d.SockRequest("GET", "/nodes", nil) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + nodes, err := cli.NodeList(context.Background(), types.NodeListOptions{}) + c.Assert(err, checker.IsNil) - nodes := []swarm.Node{} - c.Assert(json.Unmarshal(out, &nodes), checker.IsNil) return nodes } // ListServices returns the list of the current swarm services func (d *Swarm) ListServices(c *check.C) []swarm.Service { - status, out, err := d.SockRequest("GET", "/services", nil) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() - services := []swarm.Service{} - c.Assert(json.Unmarshal(out, &services), checker.IsNil) + services, err := cli.ServiceList(context.Background(), types.ServiceListOptions{}) + c.Assert(err, checker.IsNil) return services } // CreateSecret creates a secret given the specified spec func (d *Swarm) CreateSecret(c *check.C, secretSpec swarm.SecretSpec) string { - status, out, err := d.SockRequest("POST", "/secrets/create", secretSpec) + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusCreated, check.Commentf("output: %q", string(out))) + scr, err := cli.SecretCreate(context.Background(), secretSpec) + c.Assert(err, checker.IsNil) - var scr types.SecretCreateResponse - c.Assert(json.Unmarshal(out, &scr), checker.IsNil) return scr.ID } // ListSecrets returns the list of the current swarm secrets func (d *Swarm) ListSecrets(c *check.C) []swarm.Secret { - status, out, err := d.SockRequest("GET", "/secrets", nil) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() - secrets := []swarm.Secret{} - c.Assert(json.Unmarshal(out, &secrets), checker.IsNil) + secrets, err := cli.SecretList(context.Background(), types.SecretListOptions{}) + c.Assert(err, checker.IsNil) return secrets } // GetSecret returns a swarm secret identified by the specified id func (d *Swarm) GetSecret(c *check.C, id string) *swarm.Secret { - var secret swarm.Secret - status, out, err := d.SockRequest("GET", "/secrets/"+id, nil) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) - c.Assert(json.Unmarshal(out, &secret), checker.IsNil) + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + secret, _, err := cli.SecretInspectWithRaw(context.Background(), id) + c.Assert(err, checker.IsNil) return &secret } // DeleteSecret removes the swarm secret identified by the specified id func (d *Swarm) DeleteSecret(c *check.C, id string) { - status, out, err := d.SockRequest("DELETE", "/secrets/"+id, nil) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusNoContent, check.Commentf("output: %q", string(out))) + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + err = cli.SecretRemove(context.Background(), id) + c.Assert(err, checker.IsNil) } // UpdateSecret updates the swarm secret identified by the specified id // Currently, only label update is supported. func (d *Swarm) UpdateSecret(c *check.C, id string, f ...SecretConstructor) { + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + secret := d.GetSecret(c, id) for _, fn := range f { fn(secret) } - url := fmt.Sprintf("/secrets/%s/update?version=%d", secret.ID, secret.Version.Index) - status, out, err := d.SockRequest("POST", url, secret.Spec) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) + + err = cli.SecretUpdate(context.Background(), secret.ID, secret.Version, secret.Spec) + + c.Assert(err, checker.IsNil) } // CreateConfig creates a config given the specified spec func (d *Swarm) CreateConfig(c *check.C, configSpec swarm.ConfigSpec) string { - status, out, err := d.SockRequest("POST", "/configs/create", configSpec) + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusCreated, check.Commentf("output: %q", string(out))) - - var scr types.ConfigCreateResponse - c.Assert(json.Unmarshal(out, &scr), checker.IsNil) + scr, err := cli.ConfigCreate(context.Background(), configSpec) + c.Assert(err, checker.IsNil) return scr.ID } // ListConfigs returns the list of the current swarm configs func (d *Swarm) ListConfigs(c *check.C) []swarm.Config { - status, out, err := d.SockRequest("GET", "/configs", nil) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() - configs := []swarm.Config{} - c.Assert(json.Unmarshal(out, &configs), checker.IsNil) + configs, err := cli.ConfigList(context.Background(), types.ConfigListOptions{}) + c.Assert(err, checker.IsNil) return configs } // GetConfig returns a swarm config identified by the specified id func (d *Swarm) GetConfig(c *check.C, id string) *swarm.Config { - var config swarm.Config - status, out, err := d.SockRequest("GET", "/configs/"+id, nil) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) - c.Assert(json.Unmarshal(out, &config), checker.IsNil) + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + config, _, err := cli.ConfigInspectWithRaw(context.Background(), id) + c.Assert(err, checker.IsNil) return &config } // DeleteConfig removes the swarm config identified by the specified id func (d *Swarm) DeleteConfig(c *check.C, id string) { - status, out, err := d.SockRequest("DELETE", "/configs/"+id, nil) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusNoContent, check.Commentf("output: %q", string(out))) + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + err = cli.ConfigRemove(context.Background(), id) + c.Assert(err, checker.IsNil) } // UpdateConfig updates the swarm config identified by the specified id // Currently, only label update is supported. func (d *Swarm) UpdateConfig(c *check.C, id string, f ...ConfigConstructor) { + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + config := d.GetConfig(c, id) for _, fn := range f { fn(config) } - url := fmt.Sprintf("/configs/%s/update?version=%d", config.ID, config.Version.Index) - status, out, err := d.SockRequest("POST", url, config.Spec) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) + + err = cli.ConfigUpdate(context.Background(), config.ID, config.Version, config.Spec) + c.Assert(err, checker.IsNil) } // GetSwarm returns the current swarm object func (d *Swarm) GetSwarm(c *check.C) swarm.Swarm { - var sw swarm.Swarm - status, out, err := d.SockRequest("GET", "/swarm", nil) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) - c.Assert(json.Unmarshal(out, &sw), checker.IsNil) + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + sw, err := cli.SwarmInspect(context.Background()) + c.Assert(err, checker.IsNil) return sw } // UpdateSwarm updates the current swarm object with the specified spec constructors func (d *Swarm) UpdateSwarm(c *check.C, f ...SpecConstructor) { + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + sw := d.GetSwarm(c) for _, fn := range f { fn(&sw.Spec) } - url := fmt.Sprintf("/swarm/update?version=%d", sw.Version.Index) - status, out, err := d.SockRequest("POST", url, sw.Spec) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) + + err = cli.SwarmUpdate(context.Background(), sw.Version, sw.Spec, swarm.UpdateFlags{}) + c.Assert(err, checker.IsNil) } // RotateTokens update the swarm to rotate tokens func (d *Swarm) RotateTokens(c *check.C) { - var sw swarm.Swarm - status, out, err := d.SockRequest("GET", "/swarm", nil) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) - c.Assert(json.Unmarshal(out, &sw), checker.IsNil) + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() - url := fmt.Sprintf("/swarm/update?version=%d&rotateWorkerToken=true&rotateManagerToken=true", sw.Version.Index) - status, out, err = d.SockRequest("POST", url, sw.Spec) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) + sw, err := cli.SwarmInspect(context.Background()) + c.Assert(err, checker.IsNil) + + flags := swarm.UpdateFlags{ + RotateManagerToken: true, + RotateWorkerToken: true, + } + + err = cli.SwarmUpdate(context.Background(), sw.Version, sw.Spec, flags) + c.Assert(err, checker.IsNil) } // JoinTokens returns the current swarm join tokens func (d *Swarm) JoinTokens(c *check.C) swarm.JoinTokens { - var sw swarm.Swarm - status, out, err := d.SockRequest("GET", "/swarm", nil) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) - c.Assert(json.Unmarshal(out, &sw), checker.IsNil) + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + sw, err := cli.SwarmInspect(context.Background()) + c.Assert(err, checker.IsNil) return sw.JoinTokens } @@ -570,17 +612,14 @@ func (d *Swarm) CheckControlAvailable(c *check.C) (interface{}, check.CommentInt // CheckLeader returns whether there is a leader on the swarm or not func (d *Swarm) CheckLeader(c *check.C) (interface{}, check.CommentInterface) { - errList := check.Commentf("could not get node list") - status, out, err := d.SockRequest("GET", "/nodes", nil) - if err != nil { - return err, errList - } - if status != http.StatusOK { - return fmt.Errorf("expected http status OK, got: %d", status), errList - } + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() - var ls []swarm.Node - if err := json.Unmarshal(out, &ls); err != nil { + errList := check.Commentf("could not get node list") + + ls, err := cli.NodeList(context.Background(), types.NodeListOptions{}) + if err != nil { return err, errList } diff --git a/integration-cli/docker_api_attach_test.go b/integration-cli/docker_api_attach_test.go index 20829335a1..a3aa40f6a4 100644 --- a/integration-cli/docker_api_attach_test.go +++ b/integration-cli/docker_api_attach_test.go @@ -86,11 +86,13 @@ func (s *DockerSuite) TestPostContainersAttachContainerNotFound(c *check.C) { } func (s *DockerSuite) TestGetContainersWsAttachContainerNotFound(c *check.C) { - status, body, err := request.SockRequest("GET", "/containers/doesnotexist/attach/ws", nil, daemonHost()) - c.Assert(status, checker.Equals, http.StatusNotFound) + res, body, err := request.Get("/containers/doesnotexist/attach/ws") + c.Assert(res.StatusCode, checker.Equals, http.StatusNotFound) + c.Assert(err, checker.IsNil) + b, err := request.ReadBody(body) c.Assert(err, checker.IsNil) expected := "No such container: doesnotexist" - c.Assert(getErrorMessage(c, body), checker.Contains, expected) + c.Assert(getErrorMessage(c, b), checker.Contains, expected) } func (s *DockerSuite) TestPostContainersAttach(c *check.C) { @@ -177,6 +179,7 @@ func (s *DockerSuite) TestPostContainersAttach(c *check.C) { // Make sure we don't see "hello" if Logs is false client, err := client.NewEnvClient() c.Assert(err, checker.IsNil) + defer client.Close() cid, _ = dockerCmd(c, "run", "-di", "busybox", "/bin/sh", "-c", "echo hello; cat") cid = strings.TrimSpace(cid) diff --git a/integration-cli/docker_api_auth_test.go b/integration-cli/docker_api_auth_test.go index cc903c01ff..a1f7a098cd 100644 --- a/integration-cli/docker_api_auth_test.go +++ b/integration-cli/docker_api_auth_test.go @@ -1,12 +1,11 @@ package main import ( - "net/http" - "github.com/docker/docker/api/types" + "github.com/docker/docker/client" "github.com/docker/docker/integration-cli/checker" - "github.com/docker/docker/integration-cli/request" "github.com/go-check/check" + "golang.org/x/net/context" ) // Test case for #22244 @@ -16,11 +15,11 @@ func (s *DockerSuite) TestAuthAPI(c *check.C) { Username: "no-user", Password: "no-password", } + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + _, err = cli.RegistryLogin(context.Background(), config) expected := "Get https://registry-1.docker.io/v2/: unauthorized: incorrect username or password" - status, body, err := request.SockRequest("POST", "/auth", config, daemonHost()) - c.Assert(err, check.IsNil) - c.Assert(status, check.Equals, http.StatusUnauthorized) - msg := getErrorMessage(c, body) - c.Assert(msg, checker.Contains, expected, check.Commentf("Expected: %v, got: %v", expected, msg)) + c.Assert(err.Error(), checker.Contains, expected) } diff --git a/integration-cli/docker_api_containers_test.go b/integration-cli/docker_api_containers_test.go index cd3992a6f9..554d68760a 100644 --- a/integration-cli/docker_api_containers_test.go +++ b/integration-cli/docker_api_containers_test.go @@ -8,7 +8,6 @@ import ( "io" "io/ioutil" "net/http" - "net/url" "os" "path/filepath" "regexp" @@ -20,6 +19,7 @@ import ( containertypes "github.com/docker/docker/api/types/container" mounttypes "github.com/docker/docker/api/types/mount" networktypes "github.com/docker/docker/api/types/network" + "github.com/docker/docker/client" "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/cli" "github.com/docker/docker/integration-cli/cli/build" @@ -28,7 +28,9 @@ import ( "github.com/docker/docker/pkg/mount" "github.com/docker/docker/pkg/stringid" "github.com/docker/docker/volume" + "github.com/docker/go-connections/nat" "github.com/go-check/check" + "golang.org/x/net/context" ) func (s *DockerSuite) TestContainerAPIGetAll(c *check.C) { @@ -36,35 +38,43 @@ func (s *DockerSuite) TestContainerAPIGetAll(c *check.C) { name := "getall" dockerCmd(c, "run", "--name", name, "busybox", "true") - status, body, err := request.SockRequest("GET", "/containers/json?all=1", nil, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusOK) + defer cli.Close() - var inspectJSON []struct { - Names []string + options := types.ContainerListOptions{ + All: true, } - err = json.Unmarshal(body, &inspectJSON) - c.Assert(err, checker.IsNil, check.Commentf("unable to unmarshal response body")) - - c.Assert(inspectJSON, checker.HasLen, startCount+1) - - actual := inspectJSON[0].Names[0] + containers, err := cli.ContainerList(context.Background(), options) + c.Assert(err, checker.IsNil) + c.Assert(containers, checker.HasLen, startCount+1) + actual := containers[0].Names[0] c.Assert(actual, checker.Equals, "/"+name) } // regression test for empty json field being omitted #13691 func (s *DockerSuite) TestContainerAPIGetJSONNoFieldsOmitted(c *check.C) { + startCount := getContainerCount(c) dockerCmd(c, "run", "busybox", "true") - status, body, err := request.SockRequest("GET", "/containers/json?all=1", nil, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusOK) + defer cli.Close() + + options := types.ContainerListOptions{ + All: true, + } + containers, err := cli.ContainerList(context.Background(), options) + c.Assert(err, checker.IsNil) + c.Assert(containers, checker.HasLen, startCount+1) + actual := fmt.Sprintf("%+v", containers[0]) + fmt.Println(actual) // empty Labels field triggered this bug, make sense to check for everything // cause even Ports for instance can trigger this bug // better safe than sorry.. fields := []string{ - "Id", + "ID", "Names", "Image", "Command", @@ -78,7 +88,7 @@ func (s *DockerSuite) TestContainerAPIGetJSONNoFieldsOmitted(c *check.C) { // decoding into types.Container do not work since it eventually unmarshal // and empty field to an empty go map, so we just check for a string for _, f := range fields { - if !strings.Contains(string(body), f) { + if !strings.Contains(actual, f) { c.Fatalf("Field %s is missing and it shouldn't", f) } } @@ -86,7 +96,7 @@ func (s *DockerSuite) TestContainerAPIGetJSONNoFieldsOmitted(c *check.C) { type containerPs struct { Names []string - Ports []map[string]interface{} + Ports []types.Port } // regression test for non-empty fields from #13901 @@ -97,30 +107,30 @@ func (s *DockerSuite) TestContainerAPIPsOmitFields(c *check.C) { port := 80 runSleepingContainer(c, "--name", name, "--expose", strconv.Itoa(port)) - status, body, err := request.SockRequest("GET", "/containers/json?all=1", nil, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusOK) + defer cli.Close() - var resp []containerPs - err = json.Unmarshal(body, &resp) + options := types.ContainerListOptions{ + All: true, + } + containers, err := cli.ContainerList(context.Background(), options) c.Assert(err, checker.IsNil) - - var foundContainer *containerPs - for _, container := range resp { - for _, testName := range container.Names { + var foundContainer containerPs + for _, c := range containers { + for _, testName := range c.Names { if "/"+name == testName { - foundContainer = &container + foundContainer.Names = c.Names + foundContainer.Ports = c.Ports break } } } c.Assert(foundContainer.Ports, checker.HasLen, 1) - c.Assert(foundContainer.Ports[0]["PrivatePort"], checker.Equals, float64(port)) - _, ok := foundContainer.Ports[0]["PublicPort"] - c.Assert(ok, checker.Not(checker.Equals), true) - _, ok = foundContainer.Ports[0]["IP"] - c.Assert(ok, checker.Not(checker.Equals), true) + c.Assert(foundContainer.Ports[0].PrivatePort, checker.Equals, uint16(port)) + c.Assert(foundContainer.Ports[0].PublicPort, checker.NotNil) + c.Assert(foundContainer.Ports[0].IP, checker.NotNil) } func (s *DockerSuite) TestContainerAPIGetExport(c *check.C) { @@ -129,12 +139,15 @@ func (s *DockerSuite) TestContainerAPIGetExport(c *check.C) { name := "exportcontainer" dockerCmd(c, "run", "--name", name, "busybox", "touch", "/test") - status, body, err := request.SockRequest("GET", "/containers/"+name+"/export", nil, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusOK) + defer cli.Close() + body, err := cli.ContainerExport(context.Background(), name) + c.Assert(err, checker.IsNil) + defer body.Close() found := false - for tarReader := tar.NewReader(bytes.NewReader(body)); ; { + for tarReader := tar.NewReader(body); ; { h, err := tarReader.Next() if err != nil && err == io.EOF { break @@ -153,15 +166,12 @@ func (s *DockerSuite) TestContainerAPIGetChanges(c *check.C) { name := "changescontainer" dockerCmd(c, "run", "--name", name, "busybox", "rm", "/etc/passwd") - status, body, err := request.SockRequest("GET", "/containers/"+name+"/changes", nil, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusOK) + defer cli.Close() - changes := []struct { - Kind int - Path string - }{} - c.Assert(json.Unmarshal(body, &changes), checker.IsNil, check.Commentf("unable to unmarshal response body")) + changes, err := cli.ContainerDiff(context.Background(), name) + c.Assert(err, checker.IsNil) // Check the changelog for removal of /etc/passwd success := false @@ -180,14 +190,19 @@ func (s *DockerSuite) TestGetContainerStats(c *check.C) { runSleepingContainer(c, "--name", name) type b struct { - status int - body []byte - err error + stats types.ContainerStats + err error } + bc := make(chan b, 1) go func() { - status, body, err := request.SockRequest("GET", "/containers/"+name+"/stats", nil, daemonHost()) - bc <- b{status, body, err} + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + stats, err := cli.ContainerStats(context.Background(), name, true) + c.Assert(err, checker.IsNil) + bc <- b{stats, err} }() // allow some time to stream the stats from the container @@ -200,10 +215,8 @@ func (s *DockerSuite) TestGetContainerStats(c *check.C) { case <-time.After(2 * time.Second): c.Fatal("stream was not closed after container was removed") case sr := <-bc: - c.Assert(sr.err, checker.IsNil) - c.Assert(sr.status, checker.Equals, http.StatusOK) - - dec := json.NewDecoder(bytes.NewBuffer(sr.body)) + dec := json.NewDecoder(sr.stats.Body) + defer sr.stats.Body.Close() var s *types.Stats // decode only one object from the stream c.Assert(dec.Decode(&s), checker.IsNil) @@ -217,13 +230,17 @@ func (s *DockerSuite) TestGetContainerStatsRmRunning(c *check.C) { buf := &ChannelBuffer{C: make(chan []byte, 1)} defer buf.Close() - _, body, err := request.Get("/containers/"+id+"/stats?stream=1", request.JSON) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - defer body.Close() + defer cli.Close() + + stats, err := cli.ContainerStats(context.Background(), id, true) + c.Assert(err, checker.IsNil) + defer stats.Body.Close() chErr := make(chan error, 1) go func() { - _, err = io.Copy(buf, body) + _, err = io.Copy(buf, stats.Body) chErr <- err }() @@ -278,14 +295,19 @@ func (s *DockerSuite) TestGetContainerStatsStream(c *check.C) { runSleepingContainer(c, "--name", name) type b struct { - status int - body io.ReadCloser - err error + stats types.ContainerStats + err error } + bc := make(chan b, 1) go func() { - status, body, err := request.Get("/containers/" + name + "/stats") - bc <- b{status.StatusCode, body, err} + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + stats, err := cli.ContainerStats(context.Background(), name, true) + c.Assert(err, checker.IsNil) + bc <- b{stats, err} }() // allow some time to stream the stats from the container @@ -298,10 +320,8 @@ func (s *DockerSuite) TestGetContainerStatsStream(c *check.C) { case <-time.After(2 * time.Second): c.Fatal("stream was not closed after container was removed") case sr := <-bc: - c.Assert(sr.err, checker.IsNil) - c.Assert(sr.status, checker.Equals, http.StatusOK) - - b, err := ioutil.ReadAll(sr.body) + b, err := ioutil.ReadAll(sr.stats.Body) + defer sr.stats.Body.Close() c.Assert(err, checker.IsNil) s := string(b) // count occurrences of "read" of types.Stats @@ -316,14 +336,20 @@ func (s *DockerSuite) TestGetContainerStatsNoStream(c *check.C) { runSleepingContainer(c, "--name", name) type b struct { - status int - body []byte - err error + stats types.ContainerStats + err error } + bc := make(chan b, 1) + go func() { - status, body, err := request.SockRequest("GET", "/containers/"+name+"/stats?stream=0", nil, daemonHost()) - bc <- b{status, body, err} + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + stats, err := cli.ContainerStats(context.Background(), name, false) + c.Assert(err, checker.IsNil) + bc <- b{stats, err} }() // allow some time to stream the stats from the container @@ -336,10 +362,10 @@ func (s *DockerSuite) TestGetContainerStatsNoStream(c *check.C) { case <-time.After(2 * time.Second): c.Fatal("stream was not closed after container was removed") case sr := <-bc: - c.Assert(sr.err, checker.IsNil) - c.Assert(sr.status, checker.Equals, http.StatusOK) - - s := string(sr.body) + b, err := ioutil.ReadAll(sr.stats.Body) + defer sr.stats.Body.Close() + c.Assert(err, checker.IsNil) + s := string(b) // count occurrences of `"read"` of types.Stats c.Assert(strings.Count(s, `"read"`), checker.Equals, 1, check.Commentf("Expected only one stat streamed, got %d", strings.Count(s, `"read"`))) } @@ -349,24 +375,23 @@ func (s *DockerSuite) TestGetStoppedContainerStats(c *check.C) { name := "statscontainer" dockerCmd(c, "create", "--name", name, "busybox", "ps") - type stats struct { - status int - err error - } - chResp := make(chan stats) + chResp := make(chan error) // We expect an immediate response, but if it's not immediate, the test would hang, so put it in a goroutine // below we'll check this on a timeout. go func() { - resp, body, err := request.Get("/containers/" + name + "/stats") - body.Close() - chResp <- stats{resp.StatusCode, err} + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + resp, err := cli.ContainerStats(context.Background(), name, false) + defer resp.Body.Close() + chResp <- err }() select { - case r := <-chResp: - c.Assert(r.err, checker.IsNil) - c.Assert(r.status, checker.Equals, http.StatusOK) + case err := <-chResp: + c.Assert(err, checker.IsNil) case <-time.After(10 * time.Second): c.Fatal("timeout waiting for stats response for stopped container") } @@ -383,9 +408,12 @@ func (s *DockerSuite) TestContainerAPIPause(c *check.C) { out := cli.DockerCmd(c, "run", "-d", "busybox", "sleep", "30").Combined() ContainerID := strings.TrimSpace(out) - resp, _, err := request.Post("/containers/" + ContainerID + "/pause") + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + err = cli.ContainerPause(context.Background(), ContainerID) c.Assert(err, checker.IsNil) - c.Assert(resp.StatusCode, checker.Equals, http.StatusNoContent) pausedContainers := getPaused(c) @@ -393,9 +421,8 @@ func (s *DockerSuite) TestContainerAPIPause(c *check.C) { c.Fatalf("there should be one paused container and not %d", len(pausedContainers)) } - resp, _, err = request.Post("/containers/" + ContainerID + "/unpause") + err = cli.ContainerUnpause(context.Background(), ContainerID) c.Assert(err, checker.IsNil) - c.Assert(resp.StatusCode, checker.Equals, http.StatusNoContent) pausedContainers = getPaused(c) c.Assert(pausedContainers, checker.HasLen, 0, check.Commentf("There should be no paused container.")) @@ -407,15 +434,12 @@ func (s *DockerSuite) TestContainerAPITop(c *check.C) { id := strings.TrimSpace(string(out)) c.Assert(waitRun(id), checker.IsNil) - type topResp struct { - Titles []string - Processes [][]string - } - var top topResp - status, b, err := request.SockRequest("GET", "/containers/"+id+"/top?ps_args=aux", nil, daemonHost()) + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + top, err := cli.ContainerTop(context.Background(), id, []string{"aux"}) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusOK) - c.Assert(json.Unmarshal(b, &top), checker.IsNil) c.Assert(top.Titles, checker.HasLen, 11, check.Commentf("expected 11 titles, found %d: %v", len(top.Titles), top.Titles)) if top.Titles[0] != "USER" || top.Titles[10] != "COMMAND" { @@ -432,15 +456,12 @@ func (s *DockerSuite) TestContainerAPITopWindows(c *check.C) { id := strings.TrimSpace(string(out)) c.Assert(waitRun(id), checker.IsNil) - type topResp struct { - Titles []string - Processes [][]string - } - var top topResp - status, b, err := request.SockRequest("GET", "/containers/"+id+"/top", nil, daemonHost()) + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + top, err := cli.ContainerTop(context.Background(), id, nil) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusOK) - c.Assert(json.Unmarshal(b, &top), checker.IsNil) c.Assert(top.Titles, checker.HasLen, 4, check.Commentf("expected 4 titles, found %d: %v", len(top.Titles), top.Titles)) if top.Titles[0] != "Name" || top.Titles[3] != "Private Working Set" { @@ -464,16 +485,16 @@ func (s *DockerSuite) TestContainerAPICommit(c *check.C) { cName := "testapicommit" dockerCmd(c, "run", "--name="+cName, "busybox", "/bin/sh", "-c", "touch /test") - name := "testcontainerapicommit" - status, b, err := request.SockRequest("POST", "/commit?repo="+name+"&testtag=tag&container="+cName, nil, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusCreated) + defer cli.Close() - type resp struct { - ID string + options := types.ContainerCommitOptions{ + Reference: "testcontainerapicommit:testtag", } - var img resp - c.Assert(json.Unmarshal(b, &img), checker.IsNil) + + img, err := cli.ContainerCommit(context.Background(), cName, options) + c.Assert(err, checker.IsNil) cmd := inspectField(c, img.ID, "Config.Cmd") c.Assert(cmd, checker.Equals, "[/bin/sh -c touch /test]", check.Commentf("got wrong Cmd from commit: %q", cmd)) @@ -486,20 +507,20 @@ func (s *DockerSuite) TestContainerAPICommitWithLabelInConfig(c *check.C) { cName := "testapicommitwithconfig" dockerCmd(c, "run", "--name="+cName, "busybox", "/bin/sh", "-c", "touch /test") - config := map[string]interface{}{ - "Labels": map[string]string{"key1": "value1", "key2": "value2"}, - } - - name := "testcontainerapicommitwithconfig" - status, b, err := request.SockRequest("POST", "/commit?repo="+name+"&container="+cName, config, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusCreated) + defer cli.Close() - type resp struct { - ID string + config := containertypes.Config{ + Labels: map[string]string{"key1": "value1", "key2": "value2"}} + + options := types.ContainerCommitOptions{ + Reference: "testcontainerapicommitwithconfig", + Config: &config, } - var img resp - c.Assert(json.Unmarshal(b, &img), checker.IsNil) + + img, err := cli.ContainerCommit(context.Background(), cName, options) + c.Assert(err, checker.IsNil) label1 := inspectFieldMap(c, img.ID, "Config.Labels", "key1") c.Assert(label1, checker.Equals, "value1") @@ -517,76 +538,79 @@ func (s *DockerSuite) TestContainerAPICommitWithLabelInConfig(c *check.C) { func (s *DockerSuite) TestContainerAPIBadPort(c *check.C) { // TODO Windows to Windows CI - Port this test testRequires(c, DaemonIsLinux) - config := map[string]interface{}{ - "Image": "busybox", - "Cmd": []string{"/bin/sh", "-c", "echo test"}, - "PortBindings": map[string]interface{}{ - "8080/tcp": []map[string]interface{}{ + + config := containertypes.Config{ + Image: "busybox", + Cmd: []string{"/bin/sh", "-c", "echo test"}, + } + + hostConfig := containertypes.HostConfig{ + PortBindings: nat.PortMap{ + "8080/tcp": []nat.PortBinding{ { - "HostIP": "", - "HostPort": "aa80", - }, + HostIP: "", + HostPort: "aa80"}, }, }, } - jsonData := bytes.NewBuffer(nil) - json.NewEncoder(jsonData).Encode(config) - - status, body, err := request.SockRequest("POST", "/containers/create", config, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusBadRequest) - c.Assert(getErrorMessage(c, body), checker.Equals, `invalid port specification: "aa80"`, check.Commentf("Incorrect error msg: %s", body)) + defer cli.Close() + + _, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, "") + c.Assert(err.Error(), checker.Contains, `invalid port specification: "aa80"`) } func (s *DockerSuite) TestContainerAPICreate(c *check.C) { - config := map[string]interface{}{ - "Image": "busybox", - "Cmd": []string{"/bin/sh", "-c", "touch /test && ls /test"}, + config := containertypes.Config{ + Image: "busybox", + Cmd: []string{"/bin/sh", "-c", "touch /test && ls /test"}, } - status, b, err := request.SockRequest("POST", "/containers/create", config, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusCreated) + defer cli.Close() - type createResp struct { - ID string - } - var container createResp - c.Assert(json.Unmarshal(b, &container), checker.IsNil) + container, err := cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, "") + c.Assert(err, checker.IsNil) out, _ := dockerCmd(c, "start", "-a", container.ID) c.Assert(strings.TrimSpace(out), checker.Equals, "/test") } func (s *DockerSuite) TestContainerAPICreateEmptyConfig(c *check.C) { - config := map[string]interface{}{} - status, body, err := request.SockRequest("POST", "/containers/create", config, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusBadRequest) + defer cli.Close() - expected := "Config cannot be empty in order to create a container" - c.Assert(getErrorMessage(c, body), checker.Equals, expected) + _, err = cli.ContainerCreate(context.Background(), &containertypes.Config{}, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, "") + + expected := "No command specified" + c.Assert(err.Error(), checker.Contains, expected) } func (s *DockerSuite) TestContainerAPICreateMultipleNetworksConfig(c *check.C) { // Container creation must fail if client specified configurations for more than one network - config := map[string]interface{}{ - "Image": "busybox", - "NetworkingConfig": networktypes.NetworkingConfig{ - EndpointsConfig: map[string]*networktypes.EndpointSettings{ - "net1": {}, - "net2": {}, - "net3": {}, - }, + config := containertypes.Config{ + Image: "busybox", + } + + networkingConfig := networktypes.NetworkingConfig{ + EndpointsConfig: map[string]*networktypes.EndpointSettings{ + "net1": {}, + "net2": {}, + "net3": {}, }, } - status, body, err := request.SockRequest("POST", "/containers/create", config, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusBadRequest) - msg := getErrorMessage(c, body) + defer cli.Close() + + _, err = cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networkingConfig, "") + msg := err.Error() // network name order in error message is not deterministic c.Assert(msg, checker.Contains, "Container cannot be connected to network endpoints") c.Assert(msg, checker.Contains, "net1") @@ -597,25 +621,22 @@ func (s *DockerSuite) TestContainerAPICreateMultipleNetworksConfig(c *check.C) { func (s *DockerSuite) TestContainerAPICreateWithHostName(c *check.C) { domainName := "test-domain" hostName := "test-hostname" - config := map[string]interface{}{ - "Image": "busybox", - "Hostname": hostName, - "Domainname": domainName, + config := containertypes.Config{ + Image: "busybox", + Hostname: hostName, + Domainname: domainName, } - status, body, err := request.SockRequest("POST", "/containers/create", config, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusCreated) + defer cli.Close() - var container containertypes.ContainerCreateCreatedBody - c.Assert(json.Unmarshal(body, &container), checker.IsNil) - - status, body, err = request.SockRequest("GET", "/containers/"+container.ID+"/json", nil, daemonHost()) + container, err := cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, "") + c.Assert(err, checker.IsNil) + + containerJSON, err := cli.ContainerInspect(context.Background(), container.ID) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusOK) - var containerJSON types.ContainerJSON - c.Assert(json.Unmarshal(body, &containerJSON), checker.IsNil) c.Assert(containerJSON.Config.Hostname, checker.Equals, hostName, check.Commentf("Mismatched Hostname")) c.Assert(containerJSON.Config.Domainname, checker.Equals, domainName, check.Commentf("Mismatched Domainname")) } @@ -633,51 +654,51 @@ func (s *DockerSuite) TestContainerAPICreateOtherNetworkModes(c *check.C) { UtilCreateNetworkMode(c, "container:web1") } -func UtilCreateNetworkMode(c *check.C, networkMode string) { - config := map[string]interface{}{ - "Image": "busybox", - "HostConfig": map[string]interface{}{"NetworkMode": networkMode}, +func UtilCreateNetworkMode(c *check.C, networkMode containertypes.NetworkMode) { + config := containertypes.Config{ + Image: "busybox", } - status, body, err := request.SockRequest("POST", "/containers/create", config, daemonHost()) + hostConfig := containertypes.HostConfig{ + NetworkMode: networkMode, + } + + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusCreated) + defer cli.Close() - var container containertypes.ContainerCreateCreatedBody - c.Assert(json.Unmarshal(body, &container), checker.IsNil) - - status, body, err = request.SockRequest("GET", "/containers/"+container.ID+"/json", nil, daemonHost()) + container, err := cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, "") + c.Assert(err, checker.IsNil) + + containerJSON, err := cli.ContainerInspect(context.Background(), container.ID) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusOK) - var containerJSON types.ContainerJSON - c.Assert(json.Unmarshal(body, &containerJSON), checker.IsNil) c.Assert(containerJSON.HostConfig.NetworkMode, checker.Equals, containertypes.NetworkMode(networkMode), check.Commentf("Mismatched NetworkMode")) } func (s *DockerSuite) TestContainerAPICreateWithCpuSharesCpuset(c *check.C) { // TODO Windows to Windows CI. The CpuShares part could be ported. testRequires(c, DaemonIsLinux) - config := map[string]interface{}{ - "Image": "busybox", - "CpuShares": 512, - "CpusetCpus": "0", + config := containertypes.Config{ + Image: "busybox", } - status, body, err := request.SockRequest("POST", "/containers/create", config, daemonHost()) + hostConfig := containertypes.HostConfig{ + Resources: containertypes.Resources{ + CPUShares: 512, + CpusetCpus: "0", + }, + } + + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusCreated) + defer cli.Close() - var container containertypes.ContainerCreateCreatedBody - c.Assert(json.Unmarshal(body, &container), checker.IsNil) - - status, body, err = request.SockRequest("GET", "/containers/"+container.ID+"/json", nil, daemonHost()) + container, err := cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, "") c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusOK) - var containerJSON types.ContainerJSON - - c.Assert(json.Unmarshal(body, &containerJSON), checker.IsNil) + containerJSON, err := cli.ContainerInspect(context.Background(), container.ID) + c.Assert(err, checker.IsNil) out := inspectField(c, containerJSON.ID, "HostConfig.CpuShares") c.Assert(out, checker.Equals, "512") @@ -886,10 +907,13 @@ func (s *DockerSuite) TestContainerAPIRename(c *check.C) { containerID := strings.TrimSpace(out) newName := "TestContainerAPIRenameNew" - statusCode, _, err := request.SockRequest("POST", "/containers/"+containerID+"/rename?name="+newName, nil, daemonHost()) + + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + err = cli.ContainerRename(context.Background(), containerID, newName) c.Assert(err, checker.IsNil) - // 204 No Content is expected, not 200 - c.Assert(statusCode, checker.Equals, http.StatusNoContent) name := inspectField(c, containerID, "Name") c.Assert(name, checker.Equals, "/"+newName, check.Commentf("Failed to rename container")) @@ -899,9 +923,12 @@ func (s *DockerSuite) TestContainerAPIKill(c *check.C) { name := "test-api-kill" runSleepingContainer(c, "-i", "--name", name) - status, _, err := request.SockRequest("POST", "/containers/"+name+"/kill", nil, daemonHost()) + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + err = cli.ContainerKill(context.Background(), name, "SIGKILL") c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusNoContent) state := inspectField(c, name, "State.Running") c.Assert(state, checker.Equals, "false", check.Commentf("got wrong State from container %s: %q", name, state)) @@ -910,10 +937,14 @@ func (s *DockerSuite) TestContainerAPIKill(c *check.C) { func (s *DockerSuite) TestContainerAPIRestart(c *check.C) { name := "test-api-restart" runSleepingContainer(c, "-di", "--name", name) - - status, _, err := request.SockRequest("POST", "/containers/"+name+"/restart?t=1", nil, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusNoContent) + defer cli.Close() + + timeout := 1 * time.Second + err = cli.ContainerRestart(context.Background(), name, &timeout) + c.Assert(err, checker.IsNil) + c.Assert(waitInspect(name, "{{ .State.Restarting }} {{ .State.Running }}", "false true", 15*time.Second), checker.IsNil) } @@ -923,51 +954,59 @@ func (s *DockerSuite) TestContainerAPIRestartNotimeoutParam(c *check.C) { id := strings.TrimSpace(out) c.Assert(waitRun(id), checker.IsNil) - status, _, err := request.SockRequest("POST", "/containers/"+name+"/restart", nil, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusNoContent) + defer cli.Close() + + err = cli.ContainerRestart(context.Background(), name, nil) + c.Assert(err, checker.IsNil) + c.Assert(waitInspect(name, "{{ .State.Restarting }} {{ .State.Running }}", "false true", 15*time.Second), checker.IsNil) } func (s *DockerSuite) TestContainerAPIStart(c *check.C) { name := "testing-start" - config := map[string]interface{}{ - "Image": "busybox", - "Cmd": append([]string{"/bin/sh", "-c"}, sleepCommandForDaemonPlatform()...), - "OpenStdin": true, + config := containertypes.Config{ + Image: "busybox", + Cmd: append([]string{"/bin/sh", "-c"}, sleepCommandForDaemonPlatform()...), + OpenStdin: true, } - status, _, err := request.SockRequest("POST", "/containers/create?name="+name, config, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusCreated) + defer cli.Close() - status, _, err = request.SockRequest("POST", "/containers/"+name+"/start", nil, daemonHost()) + _, err = cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, name) + c.Assert(err, checker.IsNil) + + err = cli.ContainerStart(context.Background(), name, types.ContainerStartOptions{}) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusNoContent) // second call to start should give 304 - status, _, err = request.SockRequest("POST", "/containers/"+name+"/start", nil, daemonHost()) + // maybe add ContainerStartWithRaw to test it + err = cli.ContainerStart(context.Background(), name, types.ContainerStartOptions{}) c.Assert(err, checker.IsNil) // TODO(tibor): figure out why this doesn't work on windows - if testEnv.LocalDaemon() { - c.Assert(status, checker.Equals, http.StatusNotModified) - } } func (s *DockerSuite) TestContainerAPIStop(c *check.C) { name := "test-api-stop" runSleepingContainer(c, "-i", "--name", name) + timeout := 30 * time.Second - status, _, err := request.SockRequest("POST", "/containers/"+name+"/stop?t=30", nil, daemonHost()) + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + err = cli.ContainerStop(context.Background(), name, &timeout) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusNoContent) c.Assert(waitInspect(name, "{{ .State.Running }}", "false", 60*time.Second), checker.IsNil) // second call to start should give 304 - status, _, err = request.SockRequest("POST", "/containers/"+name+"/stop?t=30", nil, daemonHost()) + // maybe add ContainerStartWithRaw to test it + err = cli.ContainerStop(context.Background(), name, &timeout) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusNotModified) } func (s *DockerSuite) TestContainerAPIWait(c *check.C) { @@ -979,14 +1018,18 @@ func (s *DockerSuite) TestContainerAPIWait(c *check.C) { } dockerCmd(c, "run", "--name", name, "busybox", sleepCmd, "2") - status, body, err := request.SockRequest("POST", "/containers/"+name+"/wait", nil, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusOK) - c.Assert(waitInspect(name, "{{ .State.Running }}", "false", 60*time.Second), checker.IsNil) + defer cli.Close() - var waitres containertypes.ContainerWaitOKBody - c.Assert(json.Unmarshal(body, &waitres), checker.IsNil) - c.Assert(waitres.StatusCode, checker.Equals, int64(0)) + waitresC, errC := cli.ContainerWait(context.Background(), name, "") + + select { + case err = <-errC: + c.Assert(err, checker.IsNil) + case waitres := <-waitresC: + c.Assert(waitres.StatusCode, checker.Equals, int64(0)) + } } func (s *DockerSuite) TestContainerAPICopyNotExistsAnyMore(c *check.C) { @@ -996,10 +1039,10 @@ func (s *DockerSuite) TestContainerAPICopyNotExistsAnyMore(c *check.C) { postData := types.CopyConfig{ Resource: "/test.txt", } - - status, _, err := request.SockRequest("POST", "/containers/"+name+"/copy", postData, daemonHost()) + // no copy in client/ + res, _, err := request.Post("/containers/"+name+"/copy", request.JSONBody(postData)) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusNotFound) + c.Assert(res.StatusCode, checker.Equals, http.StatusNotFound) } func (s *DockerSuite) TestContainerAPICopyPre124(c *check.C) { @@ -1011,12 +1054,12 @@ func (s *DockerSuite) TestContainerAPICopyPre124(c *check.C) { Resource: "/test.txt", } - status, body, err := request.SockRequest("POST", "/v1.23/containers/"+name+"/copy", postData, daemonHost()) + res, body, err := request.Post("/v1.23/containers/"+name+"/copy", request.JSONBody(postData)) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusOK) + c.Assert(res.StatusCode, checker.Equals, http.StatusOK) found := false - for tarReader := tar.NewReader(bytes.NewReader(body)); ; { + for tarReader := tar.NewReader(body); ; { h, err := tarReader.Next() if err != nil { if err == io.EOF { @@ -1041,10 +1084,12 @@ func (s *DockerSuite) TestContainerAPICopyResourcePathEmptyPre124(c *check.C) { Resource: "", } - status, body, err := request.SockRequest("POST", "/v1.23/containers/"+name+"/copy", postData, daemonHost()) + res, body, err := request.Post("/v1.23/containers/"+name+"/copy", request.JSONBody(postData)) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusBadRequest) - c.Assert(string(body), checker.Matches, "Path cannot be empty\n") + c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest) + b, err := request.ReadBody(body) + c.Assert(err, checker.IsNil) + c.Assert(string(b), checker.Matches, "Path cannot be empty\n") } func (s *DockerSuite) TestContainerAPICopyResourcePathNotFoundPre124(c *check.C) { @@ -1056,10 +1101,13 @@ func (s *DockerSuite) TestContainerAPICopyResourcePathNotFoundPre124(c *check.C) Resource: "/notexist", } - status, body, err := request.SockRequest("POST", "/v1.23/containers/"+name+"/copy", postData, daemonHost()) + res, body, err := request.Post("/v1.23/containers/"+name+"/copy", request.JSONBody(postData)) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusNotFound) - c.Assert(string(body), checker.Matches, "Could not find the file /notexist in container "+name+"\n") + c.Assert(res.StatusCode, checker.Equals, http.StatusNotFound) + + b, err := request.ReadBody(body) + c.Assert(err, checker.IsNil) + c.Assert(string(b), checker.Matches, "Could not find the file /notexist in container "+name+"\n") } func (s *DockerSuite) TestContainerAPICopyContainerNotFoundPr124(c *check.C) { @@ -1068,9 +1116,9 @@ func (s *DockerSuite) TestContainerAPICopyContainerNotFoundPr124(c *check.C) { Resource: "/something", } - status, _, err := request.SockRequest("POST", "/v1.23/containers/notexists/copy", postData, daemonHost()) + res, _, err := request.Post("/v1.23/containers/notexists/copy", request.JSONBody(postData)) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusNotFound) + c.Assert(res.StatusCode, checker.Equals, http.StatusNotFound) } func (s *DockerSuite) TestContainerAPIDelete(c *check.C) { @@ -1081,27 +1129,38 @@ func (s *DockerSuite) TestContainerAPIDelete(c *check.C) { dockerCmd(c, "stop", id) - status, _, err := request.SockRequest("DELETE", "/containers/"+id, nil, daemonHost()) + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + err = cli.ContainerRemove(context.Background(), id, types.ContainerRemoveOptions{}) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusNoContent) } func (s *DockerSuite) TestContainerAPIDeleteNotExist(c *check.C) { - status, body, err := request.SockRequest("DELETE", "/containers/doesnotexist", nil, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusNotFound) - c.Assert(getErrorMessage(c, body), checker.Matches, "No such container: doesnotexist") + defer cli.Close() + + err = cli.ContainerRemove(context.Background(), "doesnotexist", types.ContainerRemoveOptions{}) + c.Assert(err.Error(), checker.Contains, "No such container: doesnotexist") } func (s *DockerSuite) TestContainerAPIDeleteForce(c *check.C) { out := runSleepingContainer(c) - id := strings.TrimSpace(out) c.Assert(waitRun(id), checker.IsNil) - status, _, err := request.SockRequest("DELETE", "/containers/"+id+"?force=1", nil, daemonHost()) + removeOptions := types.ContainerRemoveOptions{ + Force: true, + } + + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + err = cli.ContainerRemove(context.Background(), id, removeOptions) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusNoContent) } func (s *DockerSuite) TestContainerAPIDeleteRemoveLinks(c *check.C) { @@ -1120,9 +1179,16 @@ func (s *DockerSuite) TestContainerAPIDeleteRemoveLinks(c *check.C) { links := inspectFieldJSON(c, id2, "HostConfig.Links") c.Assert(links, checker.Equals, "[\"/tlink1:/tlink2/tlink1\"]", check.Commentf("expected to have links between containers")) - status, b, err := request.SockRequest("DELETE", "/containers/tlink2/tlink1?link=1", nil, daemonHost()) + removeOptions := types.ContainerRemoveOptions{ + RemoveLinks: true, + } + + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + err = cli.ContainerRemove(context.Background(), "tlink2/tlink1", removeOptions) c.Assert(err, check.IsNil) - c.Assert(status, check.Equals, http.StatusNoContent, check.Commentf(string(b))) linksPostRm := inspectFieldJSON(c, id2, "HostConfig.Links") c.Assert(linksPostRm, checker.Equals, "null", check.Commentf("call to api deleteContainer links should have removed the specified links")) @@ -1134,9 +1200,13 @@ func (s *DockerSuite) TestContainerAPIDeleteConflict(c *check.C) { id := strings.TrimSpace(out) c.Assert(waitRun(id), checker.IsNil) - status, _, err := request.SockRequest("DELETE", "/containers/"+id, nil, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusConflict) + defer cli.Close() + + err = cli.ContainerRemove(context.Background(), id, types.ContainerRemoveOptions{}) + expected := "cannot remove a running container" + c.Assert(err.Error(), checker.Contains, expected) } func (s *DockerSuite) TestContainerAPIDeleteRemoveVolume(c *check.C) { @@ -1156,9 +1226,18 @@ func (s *DockerSuite) TestContainerAPIDeleteRemoveVolume(c *check.C) { _, err = os.Stat(source) c.Assert(err, checker.IsNil) - status, _, err := request.SockRequest("DELETE", "/containers/"+id+"?v=1&force=1", nil, daemonHost()) + removeOptions := types.ContainerRemoveOptions{ + Force: true, + RemoveVolumes: true, + } + + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusNoContent) + defer cli.Close() + + err = cli.ContainerRemove(context.Background(), id, removeOptions) + c.Assert(err, check.IsNil) + _, err = os.Stat(source) c.Assert(os.IsNotExist(err), checker.True, check.Commentf("expected to get ErrNotExist error, got %v", err)) } @@ -1190,31 +1269,38 @@ func (s *DockerSuite) TestContainerAPIPostContainerStop(c *check.C) { containerID := strings.TrimSpace(out) c.Assert(waitRun(containerID), checker.IsNil) - statusCode, _, err := request.SockRequest("POST", "/containers/"+containerID+"/stop", nil, daemonHost()) + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + err = cli.ContainerStop(context.Background(), containerID, nil) c.Assert(err, checker.IsNil) - // 204 No Content is expected, not 200 - c.Assert(statusCode, checker.Equals, http.StatusNoContent) c.Assert(waitInspect(containerID, "{{ .State.Running }}", "false", 60*time.Second), checker.IsNil) } // #14170 func (s *DockerSuite) TestPostContainerAPICreateWithStringOrSliceEntrypoint(c *check.C) { - config := struct { - Image string - Entrypoint string - Cmd []string - }{"busybox", "echo", []string{"hello", "world"}} - _, _, err := request.SockRequest("POST", "/containers/create?name=echotest", config, daemonHost()) + config := containertypes.Config{ + Image: "busybox", + Entrypoint: []string{"echo"}, + Cmd: []string{"hello", "world"}, + } + + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + _, err = cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, "echotest") c.Assert(err, checker.IsNil) out, _ := dockerCmd(c, "start", "-a", "echotest") c.Assert(strings.TrimSpace(out), checker.Equals, "hello world") config2 := struct { Image string - Entrypoint []string + Entrypoint string Cmd []string - }{"busybox", []string{"echo"}, []string{"hello", "world"}} - _, _, err = request.SockRequest("POST", "/containers/create?name=echotest2", config2, daemonHost()) + }{"busybox", "echo", []string{"hello", "world"}} + _, _, err = request.Post("/containers/create?name=echotest2", request.JSONBody(config2)) c.Assert(err, checker.IsNil) out, _ = dockerCmd(c, "start", "-a", "echotest2") c.Assert(strings.TrimSpace(out), checker.Equals, "hello world") @@ -1222,21 +1308,26 @@ func (s *DockerSuite) TestPostContainerAPICreateWithStringOrSliceEntrypoint(c *c // #14170 func (s *DockerSuite) TestPostContainersCreateWithStringOrSliceCmd(c *check.C) { - config := struct { - Image string - Entrypoint string - Cmd string - }{"busybox", "echo", "hello world"} - _, _, err := request.SockRequest("POST", "/containers/create?name=echotest", config, daemonHost()) + config := containertypes.Config{ + Image: "busybox", + Cmd: []string{"echo", "hello", "world"}, + } + + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + _, err = cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, "echotest") c.Assert(err, checker.IsNil) out, _ := dockerCmd(c, "start", "-a", "echotest") c.Assert(strings.TrimSpace(out), checker.Equals, "hello world") config2 := struct { - Image string - Cmd []string - }{"busybox", []string{"echo", "hello", "world"}} - _, _, err = request.SockRequest("POST", "/containers/create?name=echotest2", config2, daemonHost()) + Image string + Entrypoint string + Cmd string + }{"busybox", "echo", "hello world"} + _, _, err = request.Post("/containers/create?name=echotest2", request.JSONBody(config2)) c.Assert(err, checker.IsNil) out, _ = dockerCmd(c, "start", "-a", "echotest2") c.Assert(strings.TrimSpace(out), checker.Equals, "hello world") @@ -1251,29 +1342,38 @@ func (s *DockerSuite) TestPostContainersCreateWithStringOrSliceCapAddDrop(c *che CapAdd string CapDrop string }{"busybox", "NET_ADMIN", "SYS_ADMIN"} - status, _, err := request.SockRequest("POST", "/containers/create?name=capaddtest0", config, daemonHost()) + res, _, err := request.Post("/containers/create?name=capaddtest0", request.JSONBody(config)) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusCreated) + c.Assert(res.StatusCode, checker.Equals, http.StatusCreated) - config2 := struct { - Image string - CapAdd []string - CapDrop []string - }{"busybox", []string{"NET_ADMIN", "SYS_ADMIN"}, []string{"SETGID"}} - status, _, err = request.SockRequest("POST", "/containers/create?name=capaddtest1", config2, daemonHost()) + config2 := containertypes.Config{ + Image: "busybox", + } + hostConfig := containertypes.HostConfig{ + CapAdd: []string{"NET_ADMIN", "SYS_ADMIN"}, + CapDrop: []string{"SETGID"}, + } + + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + _, err = cli.ContainerCreate(context.Background(), &config2, &hostConfig, &networktypes.NetworkingConfig{}, "capaddtest1") c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusCreated) } // #14915 func (s *DockerSuite) TestContainerAPICreateNoHostConfig118(c *check.C) { testRequires(c, DaemonIsLinux) // Windows only support 1.25 or later - config := struct { - Image string - }{"busybox"} - status, _, err := request.SockRequest("POST", "/v1.18/containers/create", config, daemonHost()) + config := containertypes.Config{ + Image: "busybox", + } + + var httpClient *http.Client + cli, err := client.NewClient(daemonHost(), "v1.18", httpClient, map[string]string{}) + + _, err = cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, "") c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusCreated) } // Ensure an error occurs when you have a container read-only rootfs but you @@ -1298,88 +1398,93 @@ func (s *DockerSuite) TestPutContainerArchiveErrSymlinkInVolumeToReadOnlyRootfs( // Attempt to extract to a symlink in the volume which points to a // directory outside the volume. This should cause an error because the // rootfs is read-only. - query := make(url.Values, 1) - query.Set("path", "/vol2/symlinkToAbsDir") - urlPath := fmt.Sprintf("/v1.20/containers/%s/archive?%s", cID, query.Encode()) - - statusCode, body, err := request.SockRequest("PUT", urlPath, nil, daemonHost()) + var httpClient *http.Client + cli, err := client.NewClient(daemonHost(), "v1.20", httpClient, map[string]string{}) c.Assert(err, checker.IsNil) - if !isCpCannotCopyReadOnly(fmt.Errorf(string(body))) { - c.Fatalf("expected ErrContainerRootfsReadonly error, but got %d: %s", statusCode, string(body)) - } + err = cli.CopyToContainer(context.Background(), cID, "/vol2/symlinkToAbsDir", nil, types.CopyToContainerOptions{}) + c.Assert(err.Error(), checker.Contains, "container rootfs is marked read-only") } func (s *DockerSuite) TestContainerAPIGetContainersJSONEmpty(c *check.C) { - status, body, err := request.SockRequest("GET", "/containers/json?all=1", nil, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusOK) - c.Assert(string(body), checker.Equals, "[]\n") + defer cli.Close() + + containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true}) + c.Assert(err, checker.IsNil) + c.Assert(containers, checker.HasLen, 0) } func (s *DockerSuite) TestPostContainersCreateWithWrongCpusetValues(c *check.C) { // Not supported on Windows testRequires(c, DaemonIsLinux) - c1 := struct { - Image string - CpusetCpus string - }{"busybox", "1-42,,"} - name := "wrong-cpuset-cpus" - status, body, err := request.SockRequest("POST", "/containers/create?name="+name, c1, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusBadRequest) - expected := "Invalid value 1-42,, for cpuset cpus" - c.Assert(getErrorMessage(c, body), checker.Equals, expected) + defer cli.Close() - c2 := struct { - Image string - CpusetMems string - }{"busybox", "42-3,1--"} + config := containertypes.Config{ + Image: "busybox", + } + hostConfig1 := containertypes.HostConfig{ + Resources: containertypes.Resources{ + CpusetCpus: "1-42,,", + }, + } + name := "wrong-cpuset-cpus" + + _, err = cli.ContainerCreate(context.Background(), &config, &hostConfig1, &networktypes.NetworkingConfig{}, name) + expected := "Invalid value 1-42,, for cpuset cpus" + c.Assert(err.Error(), checker.Contains, expected) + + hostConfig2 := containertypes.HostConfig{ + Resources: containertypes.Resources{ + CpusetMems: "42-3,1--", + }, + } name = "wrong-cpuset-mems" - status, body, err = request.SockRequest("POST", "/containers/create?name="+name, c2, daemonHost()) - c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusBadRequest) + _, err = cli.ContainerCreate(context.Background(), &config, &hostConfig2, &networktypes.NetworkingConfig{}, name) expected = "Invalid value 42-3,1-- for cpuset mems" - c.Assert(getErrorMessage(c, body), checker.Equals, expected) + c.Assert(err.Error(), checker.Contains, expected) } func (s *DockerSuite) TestPostContainersCreateShmSizeNegative(c *check.C) { // ShmSize is not supported on Windows testRequires(c, DaemonIsLinux) - config := map[string]interface{}{ - "Image": "busybox", - "HostConfig": map[string]interface{}{"ShmSize": -1}, + config := containertypes.Config{ + Image: "busybox", + } + hostConfig := containertypes.HostConfig{ + ShmSize: -1, } - status, body, err := request.SockRequest("POST", "/containers/create", config, daemonHost()) - c.Assert(err, check.IsNil) - c.Assert(status, check.Equals, http.StatusBadRequest) - c.Assert(getErrorMessage(c, body), checker.Contains, "SHM size can not be less than 0") + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + _, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, "") + c.Assert(err.Error(), checker.Contains, "SHM size can not be less than 0") } func (s *DockerSuite) TestPostContainersCreateShmSizeHostConfigOmitted(c *check.C) { // ShmSize is not supported on Windows testRequires(c, DaemonIsLinux) var defaultSHMSize int64 = 67108864 - config := map[string]interface{}{ - "Image": "busybox", - "Cmd": "mount", + config := containertypes.Config{ + Image: "busybox", + Cmd: []string{"mount"}, } - status, body, err := request.SockRequest("POST", "/containers/create", config, daemonHost()) + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + container, err := cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, "") c.Assert(err, check.IsNil) - c.Assert(status, check.Equals, http.StatusCreated) - var container containertypes.ContainerCreateCreatedBody - c.Assert(json.Unmarshal(body, &container), check.IsNil) - - status, body, err = request.SockRequest("GET", "/containers/"+container.ID+"/json", nil, daemonHost()) + containerJSON, err := cli.ContainerInspect(context.Background(), container.ID) c.Assert(err, check.IsNil) - c.Assert(status, check.Equals, http.StatusOK) - - var containerJSON types.ContainerJSON - c.Assert(json.Unmarshal(body, &containerJSON), check.IsNil) c.Assert(containerJSON.HostConfig.ShmSize, check.Equals, defaultSHMSize) @@ -1393,25 +1498,20 @@ func (s *DockerSuite) TestPostContainersCreateShmSizeHostConfigOmitted(c *check. func (s *DockerSuite) TestPostContainersCreateShmSizeOmitted(c *check.C) { // ShmSize is not supported on Windows testRequires(c, DaemonIsLinux) - config := map[string]interface{}{ - "Image": "busybox", - "HostConfig": map[string]interface{}{}, - "Cmd": "mount", + config := containertypes.Config{ + Image: "busybox", + Cmd: []string{"mount"}, } - status, body, err := request.SockRequest("POST", "/containers/create", config, daemonHost()) + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + container, err := cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, "") c.Assert(err, check.IsNil) - c.Assert(status, check.Equals, http.StatusCreated) - var container containertypes.ContainerCreateCreatedBody - c.Assert(json.Unmarshal(body, &container), check.IsNil) - - status, body, err = request.SockRequest("GET", "/containers/"+container.ID+"/json", nil, daemonHost()) + containerJSON, err := cli.ContainerInspect(context.Background(), container.ID) c.Assert(err, check.IsNil) - c.Assert(status, check.Equals, http.StatusOK) - - var containerJSON types.ContainerJSON - c.Assert(json.Unmarshal(body, &containerJSON), check.IsNil) c.Assert(containerJSON.HostConfig.ShmSize, check.Equals, int64(67108864)) @@ -1425,25 +1525,24 @@ func (s *DockerSuite) TestPostContainersCreateShmSizeOmitted(c *check.C) { func (s *DockerSuite) TestPostContainersCreateWithShmSize(c *check.C) { // ShmSize is not supported on Windows testRequires(c, DaemonIsLinux) - config := map[string]interface{}{ - "Image": "busybox", - "Cmd": "mount", - "HostConfig": map[string]interface{}{"ShmSize": 1073741824}, + config := containertypes.Config{ + Image: "busybox", + Cmd: []string{"mount"}, } - status, body, err := request.SockRequest("POST", "/containers/create", config, daemonHost()) + hostConfig := containertypes.HostConfig{ + ShmSize: 1073741824, + } + + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + container, err := cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, "") c.Assert(err, check.IsNil) - c.Assert(status, check.Equals, http.StatusCreated) - var container containertypes.ContainerCreateCreatedBody - c.Assert(json.Unmarshal(body, &container), check.IsNil) - - status, body, err = request.SockRequest("GET", "/containers/"+container.ID+"/json", nil, daemonHost()) + containerJSON, err := cli.ContainerInspect(context.Background(), container.ID) c.Assert(err, check.IsNil) - c.Assert(status, check.Equals, http.StatusOK) - - var containerJSON types.ContainerJSON - c.Assert(json.Unmarshal(body, &containerJSON), check.IsNil) c.Assert(containerJSON.HostConfig.ShmSize, check.Equals, int64(1073741824)) @@ -1457,23 +1556,19 @@ func (s *DockerSuite) TestPostContainersCreateWithShmSize(c *check.C) { func (s *DockerSuite) TestPostContainersCreateMemorySwappinessHostConfigOmitted(c *check.C) { // Swappiness is not supported on Windows testRequires(c, DaemonIsLinux) - config := map[string]interface{}{ - "Image": "busybox", + config := containertypes.Config{ + Image: "busybox", } - status, body, err := request.SockRequest("POST", "/containers/create", config, daemonHost()) + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + container, err := cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, "") c.Assert(err, check.IsNil) - c.Assert(status, check.Equals, http.StatusCreated) - var container containertypes.ContainerCreateCreatedBody - c.Assert(json.Unmarshal(body, &container), check.IsNil) - - status, body, err = request.SockRequest("GET", "/containers/"+container.ID+"/json", nil, daemonHost()) + containerJSON, err := cli.ContainerInspect(context.Background(), container.ID) c.Assert(err, check.IsNil) - c.Assert(status, check.Equals, http.StatusOK) - - var containerJSON types.ContainerJSON - c.Assert(json.Unmarshal(body, &containerJSON), check.IsNil) c.Assert(containerJSON.HostConfig.MemorySwappiness, check.IsNil) } @@ -1483,41 +1578,43 @@ func (s *DockerSuite) TestPostContainersCreateWithOomScoreAdjInvalidRange(c *che // OomScoreAdj is not supported on Windows testRequires(c, DaemonIsLinux) - config := struct { - Image string - OomScoreAdj int - }{"busybox", 1001} + config := containertypes.Config{ + Image: "busybox", + } + + hostConfig := containertypes.HostConfig{ + OomScoreAdj: 1001, + } + + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + name := "oomscoreadj-over" - status, b, err := request.SockRequest("POST", "/containers/create?name="+name, config, daemonHost()) - c.Assert(err, check.IsNil) - c.Assert(status, check.Equals, http.StatusBadRequest) + _, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, name) expected := "Invalid value 1001, range for oom score adj is [-1000, 1000]" - msg := getErrorMessage(c, b) - if !strings.Contains(msg, expected) { - c.Fatalf("Expected output to contain %q, got %q", expected, msg) + c.Assert(err.Error(), checker.Contains, expected) + + hostConfig = containertypes.HostConfig{ + OomScoreAdj: -1001, } - config = struct { - Image string - OomScoreAdj int - }{"busybox", -1001} name = "oomscoreadj-low" - status, b, err = request.SockRequest("POST", "/containers/create?name="+name, config, daemonHost()) - c.Assert(err, check.IsNil) - c.Assert(status, check.Equals, http.StatusBadRequest) + _, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, name) + expected = "Invalid value -1001, range for oom score adj is [-1000, 1000]" - msg = getErrorMessage(c, b) - if !strings.Contains(msg, expected) { - c.Fatalf("Expected output to contain %q, got %q", expected, msg) - } + c.Assert(err.Error(), checker.Contains, expected) } // test case for #22210 where an empty container name caused panic. func (s *DockerSuite) TestContainerAPIDeleteWithEmptyName(c *check.C) { - status, _, err := request.SockRequest("DELETE", "/containers/", nil, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusBadRequest) + defer cli.Close() + + err = cli.ContainerRemove(context.Background(), "", types.ContainerRemoveOptions{}) + c.Assert(err.Error(), checker.Contains, "Error response from daemon: page not found") } func (s *DockerSuite) TestContainerAPIStatsWithNetworkDisabled(c *check.C) { @@ -1525,31 +1622,33 @@ func (s *DockerSuite) TestContainerAPIStatsWithNetworkDisabled(c *check.C) { testRequires(c, DaemonIsLinux) name := "testing-network-disabled" - config := map[string]interface{}{ - "Image": "busybox", - "Cmd": []string{"top"}, - "NetworkDisabled": true, + + config := containertypes.Config{ + Image: "busybox", + Cmd: []string{"top"}, + NetworkDisabled: true, } - status, _, err := request.SockRequest("POST", "/containers/create?name="+name, config, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusCreated) + defer cli.Close() - status, _, err = request.SockRequest("POST", "/containers/"+name+"/start", nil, daemonHost()) + _, err = cli.ContainerCreate(context.Background(), &config, &containertypes.HostConfig{}, &networktypes.NetworkingConfig{}, name) + c.Assert(err, checker.IsNil) + + err = cli.ContainerStart(context.Background(), name, types.ContainerStartOptions{}) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusNoContent) c.Assert(waitRun(name), check.IsNil) type b struct { - status int - body []byte - err error + stats types.ContainerStats + err error } bc := make(chan b, 1) go func() { - status, body, err := request.SockRequest("GET", "/containers/"+name+"/stats", nil, daemonHost()) - bc <- b{status, body, err} + stats, err := cli.ContainerStats(context.Background(), name, false) + bc <- b{stats, err} }() // allow some time to stream the stats from the container @@ -1563,26 +1662,15 @@ func (s *DockerSuite) TestContainerAPIStatsWithNetworkDisabled(c *check.C) { c.Fatal("stream was not closed after container was removed") case sr := <-bc: c.Assert(sr.err, checker.IsNil) - c.Assert(sr.status, checker.Equals, http.StatusOK) - - // decode only one object from the stream - var s *types.Stats - dec := json.NewDecoder(bytes.NewBuffer(sr.body)) - c.Assert(dec.Decode(&s), checker.IsNil) + sr.stats.Body.Close() } } func (s *DockerSuite) TestContainersAPICreateMountsValidation(c *check.C) { - type m mounttypes.Mount - type hc struct{ Mounts []m } - type cfg struct { - Image string - HostConfig hc - } type testCase struct { - config cfg - status int - msg string + config containertypes.Config + hostConfig containertypes.HostConfig + msg string } prefix, slash := getPrefixAndSlashFromDaemonPlatform() @@ -1591,78 +1679,82 @@ func (s *DockerSuite) TestContainersAPICreateMountsValidation(c *check.C) { cases := []testCase{ { - config: cfg{ + config: containertypes.Config{ Image: "busybox", - HostConfig: hc{ - Mounts: []m{{ - Type: "notreal", - Target: destPath}}}}, - status: http.StatusBadRequest, - msg: "mount type unknown", + }, + hostConfig: containertypes.HostConfig{ + Mounts: []mounttypes.Mount{{ + Type: "notreal", + Target: destPath, + }, + }, + }, + + msg: "mount type unknown", }, { - config: cfg{ + config: containertypes.Config{ Image: "busybox", - HostConfig: hc{ - Mounts: []m{{ - Type: "bind"}}}}, - status: http.StatusBadRequest, - msg: "Target must not be empty", + }, + hostConfig: containertypes.HostConfig{ + Mounts: []mounttypes.Mount{{ + Type: "bind"}}}, + msg: "Target must not be empty", }, { - config: cfg{ + config: containertypes.Config{ Image: "busybox", - HostConfig: hc{ - Mounts: []m{{ - Type: "bind", - Target: destPath}}}}, - status: http.StatusBadRequest, - msg: "Source must not be empty", + }, + hostConfig: containertypes.HostConfig{ + Mounts: []mounttypes.Mount{{ + Type: "bind", + Target: destPath}}}, + msg: "Source must not be empty", }, { - config: cfg{ + config: containertypes.Config{ Image: "busybox", - HostConfig: hc{ - Mounts: []m{{ - Type: "bind", - Source: notExistPath, - Target: destPath}}}}, - status: http.StatusBadRequest, - msg: "bind source path does not exist", + }, + hostConfig: containertypes.HostConfig{ + Mounts: []mounttypes.Mount{{ + Type: "bind", + Source: notExistPath, + Target: destPath}}}, + msg: "bind source path does not exist", }, { - config: cfg{ + config: containertypes.Config{ Image: "busybox", - HostConfig: hc{ - Mounts: []m{{ - Type: "volume"}}}}, - status: http.StatusBadRequest, - msg: "Target must not be empty", + }, + hostConfig: containertypes.HostConfig{ + Mounts: []mounttypes.Mount{{ + Type: "volume"}}}, + msg: "Target must not be empty", }, { - config: cfg{ + config: containertypes.Config{ Image: "busybox", - HostConfig: hc{ - Mounts: []m{{ - Type: "volume", - Source: "hello", - Target: destPath}}}}, - status: http.StatusCreated, - msg: "", + }, + hostConfig: containertypes.HostConfig{ + Mounts: []mounttypes.Mount{{ + Type: "volume", + Source: "hello", + Target: destPath}}}, + msg: "", }, { - config: cfg{ + config: containertypes.Config{ Image: "busybox", - HostConfig: hc{ - Mounts: []m{{ - Type: "volume", - Source: "hello2", - Target: destPath, - VolumeOptions: &mounttypes.VolumeOptions{ - DriverConfig: &mounttypes.Driver{ - Name: "local"}}}}}}, - status: http.StatusCreated, - msg: "", + }, + hostConfig: containertypes.HostConfig{ + Mounts: []mounttypes.Mount{{ + Type: "volume", + Source: "hello2", + Target: destPath, + VolumeOptions: &mounttypes.VolumeOptions{ + DriverConfig: &mounttypes.Driver{ + Name: "local"}}}}}, + msg: "", }, } @@ -1672,27 +1764,27 @@ func (s *DockerSuite) TestContainersAPICreateMountsValidation(c *check.C) { defer os.RemoveAll(tmpDir) cases = append(cases, []testCase{ { - config: cfg{ + config: containertypes.Config{ Image: "busybox", - HostConfig: hc{ - Mounts: []m{{ - Type: "bind", - Source: tmpDir, - Target: destPath}}}}, - status: http.StatusCreated, - msg: "", + }, + hostConfig: containertypes.HostConfig{ + Mounts: []mounttypes.Mount{{ + Type: "bind", + Source: tmpDir, + Target: destPath}}}, + msg: "", }, { - config: cfg{ + config: containertypes.Config{ Image: "busybox", - HostConfig: hc{ - Mounts: []m{{ - Type: "bind", - Source: tmpDir, - Target: destPath, - VolumeOptions: &mounttypes.VolumeOptions{}}}}}, - status: http.StatusBadRequest, - msg: "VolumeOptions must not be specified", + }, + hostConfig: containertypes.HostConfig{ + Mounts: []mounttypes.Mount{{ + Type: "bind", + Source: tmpDir, + Target: destPath, + VolumeOptions: &mounttypes.VolumeOptions{}}}}, + msg: "VolumeOptions must not be specified", }, }...) } @@ -1700,67 +1792,70 @@ func (s *DockerSuite) TestContainersAPICreateMountsValidation(c *check.C) { if DaemonIsLinux() { cases = append(cases, []testCase{ { - config: cfg{ + config: containertypes.Config{ Image: "busybox", - HostConfig: hc{ - Mounts: []m{{ - Type: "volume", - Source: "hello3", - Target: destPath, - VolumeOptions: &mounttypes.VolumeOptions{ - DriverConfig: &mounttypes.Driver{ - Name: "local", - Options: map[string]string{"o": "size=1"}}}}}}}, - status: http.StatusCreated, - msg: "", + }, + hostConfig: containertypes.HostConfig{ + Mounts: []mounttypes.Mount{{ + Type: "volume", + Source: "hello3", + Target: destPath, + VolumeOptions: &mounttypes.VolumeOptions{ + DriverConfig: &mounttypes.Driver{ + Name: "local", + Options: map[string]string{"o": "size=1"}}}}}}, + msg: "", }, { - config: cfg{ + config: containertypes.Config{ Image: "busybox", - HostConfig: hc{ - Mounts: []m{{ - Type: "tmpfs", - Target: destPath}}}}, - status: http.StatusCreated, - msg: "", + }, + hostConfig: containertypes.HostConfig{ + Mounts: []mounttypes.Mount{{ + Type: "tmpfs", + Target: destPath}}}, + msg: "", }, { - config: cfg{ + config: containertypes.Config{ Image: "busybox", - HostConfig: hc{ - Mounts: []m{{ - Type: "tmpfs", - Target: destPath, - TmpfsOptions: &mounttypes.TmpfsOptions{ - SizeBytes: 4096 * 1024, - Mode: 0700, - }}}}}, - status: http.StatusCreated, - msg: "", + }, + hostConfig: containertypes.HostConfig{ + Mounts: []mounttypes.Mount{{ + Type: "tmpfs", + Target: destPath, + TmpfsOptions: &mounttypes.TmpfsOptions{ + SizeBytes: 4096 * 1024, + Mode: 0700, + }}}}, + msg: "", }, { - config: cfg{ + config: containertypes.Config{ Image: "busybox", - HostConfig: hc{ - Mounts: []m{{ - Type: "tmpfs", - Source: "/shouldnotbespecified", - Target: destPath}}}}, - status: http.StatusBadRequest, - msg: "Source must not be specified", + }, + hostConfig: containertypes.HostConfig{ + Mounts: []mounttypes.Mount{{ + Type: "tmpfs", + Source: "/shouldnotbespecified", + Target: destPath}}}, + msg: "Source must not be specified", }, }...) } + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() for i, x := range cases { c.Logf("case %d", i) - status, b, err := request.SockRequest("POST", "/containers/create", x.config, daemonHost()) - c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, x.status, check.Commentf("%s\n%v", string(b), cases[i].config)) + _, err = cli.ContainerCreate(context.Background(), &x.config, &x.hostConfig, &networktypes.NetworkingConfig{}, "") if len(x.msg) > 0 { - c.Assert(string(b), checker.Contains, x.msg, check.Commentf("%v", cases[i].config)) + c.Assert(err.Error(), checker.Contains, x.msg, check.Commentf("%v", cases[i].config)) + } else { + c.Assert(err, checker.IsNil) } } } @@ -1775,15 +1870,21 @@ func (s *DockerSuite) TestContainerAPICreateMountsBindRead(c *check.C) { defer os.RemoveAll(tmpDir) err = ioutil.WriteFile(filepath.Join(tmpDir, "bar"), []byte("hello"), 666) c.Assert(err, checker.IsNil) - - data := map[string]interface{}{ - "Image": "busybox", - "Cmd": []string{"/bin/sh", "-c", "cat /foo/bar"}, - "HostConfig": map[string]interface{}{"Mounts": []map[string]interface{}{{"Type": "bind", "Source": tmpDir, "Target": destPath}}}, + config := containertypes.Config{ + Image: "busybox", + Cmd: []string{"/bin/sh", "-c", "cat /foo/bar"}, } - status, resp, err := request.SockRequest("POST", "/containers/create?name=test", data, daemonHost()) - c.Assert(err, checker.IsNil, check.Commentf(string(resp))) - c.Assert(status, checker.Equals, http.StatusCreated, check.Commentf(string(resp))) + hostConfig := containertypes.HostConfig{ + Mounts: []mounttypes.Mount{ + {Type: "bind", Source: tmpDir, Target: destPath}, + }, + } + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + _, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, "test") + c.Assert(err, checker.IsNil) out, _ := dockerCmd(c, "start", "-a", "test") c.Assert(out, checker.Equals, "hello") @@ -1866,16 +1967,17 @@ func (s *DockerSuite) TestContainersAPICreateMountsCreate(c *check.C) { type createResp struct { ID string `json:"Id"` } + + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + for i, x := range cases { c.Logf("case %d - config: %v", i, x.cfg) - status, data, err := request.SockRequest("POST", "/containers/create", wrapper{containertypes.Config{Image: testImg}, containertypes.HostConfig{Mounts: []mounttypes.Mount{x.cfg}}}, daemonHost()) - c.Assert(err, checker.IsNil, check.Commentf(string(data))) - c.Assert(status, checker.Equals, http.StatusCreated, check.Commentf(string(data))) + container, err := cli.ContainerCreate(context.Background(), &containertypes.Config{Image: testImg}, &containertypes.HostConfig{Mounts: []mounttypes.Mount{x.cfg}}, &networktypes.NetworkingConfig{}, "") + c.Assert(err, checker.IsNil) - var resp createResp - err = json.Unmarshal(data, &resp) - c.Assert(err, checker.IsNil, check.Commentf(string(data))) - id := resp.ID + id := container.ID var mps []types.MountPoint err = json.NewDecoder(strings.NewReader(inspectFieldJSON(c, id, "Mounts"))).Decode(&mps) @@ -1921,38 +2023,43 @@ func (s *DockerSuite) TestContainersAPICreateMountsCreate(c *check.C) { func (s *DockerSuite) TestContainersAPICreateMountsTmpfs(c *check.C) { testRequires(c, DaemonIsLinux) type testCase struct { - cfg map[string]interface{} + cfg mounttypes.Mount expectedOptions []string } target := "/foo" cases := []testCase{ { - cfg: map[string]interface{}{ - "Type": "tmpfs", - "Target": target}, + cfg: mounttypes.Mount{ + Type: "tmpfs", + Target: target}, expectedOptions: []string{"rw", "nosuid", "nodev", "noexec", "relatime"}, }, { - cfg: map[string]interface{}{ - "Type": "tmpfs", - "Target": target, - "TmpfsOptions": map[string]interface{}{ - "SizeBytes": 4096 * 1024, "Mode": 0700}}, + cfg: mounttypes.Mount{ + Type: "tmpfs", + Target: target, + TmpfsOptions: &mounttypes.TmpfsOptions{ + SizeBytes: 4096 * 1024, Mode: 0700}}, expectedOptions: []string{"rw", "nosuid", "nodev", "noexec", "relatime", "size=4096k", "mode=700"}, }, } + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + config := containertypes.Config{ + Image: "busybox", + Cmd: []string{"/bin/sh", "-c", fmt.Sprintf("mount | grep 'tmpfs on %s'", target)}, + } for i, x := range cases { cName := fmt.Sprintf("test-tmpfs-%d", i) - data := map[string]interface{}{ - "Image": "busybox", - "Cmd": []string{"/bin/sh", "-c", - fmt.Sprintf("mount | grep 'tmpfs on %s'", target)}, - "HostConfig": map[string]interface{}{"Mounts": []map[string]interface{}{x.cfg}}, + hostConfig := containertypes.HostConfig{ + Mounts: []mounttypes.Mount{x.cfg}, } - status, resp, err := request.SockRequest("POST", "/containers/create?name="+cName, data, daemonHost()) - c.Assert(err, checker.IsNil, check.Commentf(string(resp))) - c.Assert(status, checker.Equals, http.StatusCreated, check.Commentf(string(resp))) + + _, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &networktypes.NetworkingConfig{}, cName) + c.Assert(err, checker.IsNil) out, _ := dockerCmd(c, "start", "-a", cName) for _, option := range x.expectedOptions { c.Assert(out, checker.Contains, option) diff --git a/integration-cli/docker_api_create_test.go b/integration-cli/docker_api_create_test.go index 58ae6e95ec..760e715b18 100644 --- a/integration-cli/docker_api_create_test.go +++ b/integration-cli/docker_api_create_test.go @@ -23,11 +23,15 @@ func (s *DockerSuite) TestAPICreateWithInvalidHealthcheckParams(c *check.C) { }, } - status, body, err := request.SockRequest("POST", "/containers/create?name="+name, config, daemonHost()) + res, body, err := request.Post("/containers/create?name="+name, request.JSONBody(config)) c.Assert(err, check.IsNil) - c.Assert(status, check.Equals, http.StatusBadRequest) + c.Assert(res.StatusCode, check.Equals, http.StatusBadRequest) + + buf, err := request.ReadBody(body) + c.Assert(err, checker.IsNil) + expected := fmt.Sprintf("Interval in Healthcheck cannot be less than %s", container.MinimumDuration) - c.Assert(getErrorMessage(c, body), checker.Contains, expected) + c.Assert(getErrorMessage(c, buf), checker.Contains, expected) // test invalid Interval in Healthcheck: larger than 0s but less than 1ms name = "test2" @@ -39,10 +43,14 @@ func (s *DockerSuite) TestAPICreateWithInvalidHealthcheckParams(c *check.C) { "Retries": int(1000), }, } - status, body, err = request.SockRequest("POST", "/containers/create?name="+name, config, daemonHost()) + res, body, err = request.Post("/containers/create?name="+name, request.JSONBody(config)) c.Assert(err, check.IsNil) - c.Assert(status, check.Equals, http.StatusBadRequest) - c.Assert(getErrorMessage(c, body), checker.Contains, expected) + + buf, err = request.ReadBody(body) + c.Assert(err, checker.IsNil) + + c.Assert(res.StatusCode, check.Equals, http.StatusBadRequest) + c.Assert(getErrorMessage(c, buf), checker.Contains, expected) // test invalid Timeout in Healthcheck: less than 1ms name = "test3" @@ -54,11 +62,15 @@ func (s *DockerSuite) TestAPICreateWithInvalidHealthcheckParams(c *check.C) { "Retries": int(1000), }, } - status, body, err = request.SockRequest("POST", "/containers/create?name="+name, config, daemonHost()) + res, body, err = request.Post("/containers/create?name="+name, request.JSONBody(config)) c.Assert(err, check.IsNil) - c.Assert(status, check.Equals, http.StatusBadRequest) + c.Assert(res.StatusCode, check.Equals, http.StatusBadRequest) + + buf, err = request.ReadBody(body) + c.Assert(err, checker.IsNil) + expected = fmt.Sprintf("Timeout in Healthcheck cannot be less than %s", container.MinimumDuration) - c.Assert(getErrorMessage(c, body), checker.Contains, expected) + c.Assert(getErrorMessage(c, buf), checker.Contains, expected) // test invalid Retries in Healthcheck: less than 0 name = "test4" @@ -70,11 +82,15 @@ func (s *DockerSuite) TestAPICreateWithInvalidHealthcheckParams(c *check.C) { "Retries": int(-10), }, } - status, body, err = request.SockRequest("POST", "/containers/create?name="+name, config, daemonHost()) + res, body, err = request.Post("/containers/create?name="+name, request.JSONBody(config)) c.Assert(err, check.IsNil) - c.Assert(status, check.Equals, http.StatusBadRequest) + c.Assert(res.StatusCode, check.Equals, http.StatusBadRequest) + + buf, err = request.ReadBody(body) + c.Assert(err, checker.IsNil) + expected = "Retries in Healthcheck cannot be negative" - c.Assert(getErrorMessage(c, body), checker.Contains, expected) + c.Assert(getErrorMessage(c, buf), checker.Contains, expected) // test invalid StartPeriod in Healthcheck: not 0 and less than 1ms name = "test3" @@ -87,9 +103,13 @@ func (s *DockerSuite) TestAPICreateWithInvalidHealthcheckParams(c *check.C) { "StartPeriod": 100 * time.Microsecond, }, } - status, body, err = request.SockRequest("POST", "/containers/create?name="+name, config, daemonHost()) + res, body, err = request.Post("/containers/create?name="+name, request.JSONBody(config)) c.Assert(err, check.IsNil) - c.Assert(status, check.Equals, http.StatusBadRequest) + c.Assert(res.StatusCode, check.Equals, http.StatusBadRequest) + + buf, err = request.ReadBody(body) + c.Assert(err, checker.IsNil) + expected = fmt.Sprintf("StartPeriod in Healthcheck cannot be less than %s", container.MinimumDuration) - c.Assert(getErrorMessage(c, body), checker.Contains, expected) + c.Assert(getErrorMessage(c, buf), checker.Contains, expected) } diff --git a/integration-cli/docker_api_exec_resize_test.go b/integration-cli/docker_api_exec_resize_test.go index 169b70a4a7..961d911cbd 100644 --- a/integration-cli/docker_api_exec_resize_test.go +++ b/integration-cli/docker_api_exec_resize_test.go @@ -20,9 +20,9 @@ func (s *DockerSuite) TestExecResizeAPIHeightWidthNoInt(c *check.C) { cleanedContainerID := strings.TrimSpace(out) endpoint := "/exec/" + cleanedContainerID + "/resize?h=foo&w=bar" - status, _, err := request.SockRequest("POST", endpoint, nil, daemonHost()) + res, _, err := request.Post(endpoint) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusBadRequest) + c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest) } // Part of #14845 @@ -36,16 +36,19 @@ func (s *DockerSuite) TestExecResizeImmediatelyAfterExecStart(c *check.C) { "Cmd": []string{"/bin/sh"}, } uri := fmt.Sprintf("/containers/%s/exec", name) - status, body, err := request.SockRequest("POST", uri, data, daemonHost()) + res, body, err := request.Post(uri, request.JSONBody(data)) if err != nil { return err } - if status != http.StatusCreated { - return fmt.Errorf("POST %s is expected to return %d, got %d", uri, http.StatusCreated, status) + if res.StatusCode != http.StatusCreated { + return fmt.Errorf("POST %s is expected to return %d, got %d", uri, http.StatusCreated, res.StatusCode) } + buf, err := request.ReadBody(body) + c.Assert(err, checker.IsNil) + out := map[string]string{} - err = json.Unmarshal(body, &out) + err = json.Unmarshal(buf, &out) if err != nil { return fmt.Errorf("ExecCreate returned invalid json. Error: %q", err.Error()) } diff --git a/integration-cli/docker_api_exec_test.go b/integration-cli/docker_api_exec_test.go index 1d7a773d9b..6e18df8fee 100644 --- a/integration-cli/docker_api_exec_test.go +++ b/integration-cli/docker_api_exec_test.go @@ -10,9 +10,12 @@ import ( "net/http" "time" + "github.com/docker/docker/api/types" + "github.com/docker/docker/client" "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/request" "github.com/go-check/check" + "golang.org/x/net/context" ) // Regression test for #9414 @@ -20,12 +23,15 @@ func (s *DockerSuite) TestExecAPICreateNoCmd(c *check.C) { name := "exec_test" dockerCmd(c, "run", "-d", "-t", "--name", name, "busybox", "/bin/sh") - status, body, err := request.SockRequest("POST", fmt.Sprintf("/containers/%s/exec", name), map[string]interface{}{"Cmd": nil}, daemonHost()) + res, body, err := request.Post(fmt.Sprintf("/containers/%s/exec", name), request.JSONBody(map[string]interface{}{"Cmd": nil})) + c.Assert(err, checker.IsNil) + c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest) + + b, err := request.ReadBody(body) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusBadRequest) comment := check.Commentf("Expected message when creating exec command with no Cmd specified") - c.Assert(getErrorMessage(c, body), checker.Contains, "No exec command specified", comment) + c.Assert(getErrorMessage(c, b), checker.Contains, "No exec command specified", comment) } func (s *DockerSuite) TestExecAPICreateNoValidContentType(c *check.C) { @@ -55,12 +61,18 @@ func (s *DockerSuite) TestExecAPICreateContainerPaused(c *check.C) { dockerCmd(c, "run", "-d", "-t", "--name", name, "busybox", "/bin/sh") dockerCmd(c, "pause", name) - status, body, err := request.SockRequest("POST", fmt.Sprintf("/containers/%s/exec", name), map[string]interface{}{"Cmd": []string{"true"}}, daemonHost()) + + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusConflict) + defer cli.Close() + + config := types.ExecConfig{ + Cmd: []string{"true"}, + } + _, err = cli.ContainerExecCreate(context.Background(), name, config) comment := check.Commentf("Expected message when creating exec command with Container %s is paused", name) - c.Assert(getErrorMessage(c, body), checker.Contains, "Container "+name+" is paused, unpause the container before exec", comment) + c.Assert(err.Error(), checker.Contains, "Container "+name+" is paused, unpause the container before exec", comment) } func (s *DockerSuite) TestExecAPIStart(c *check.C) { @@ -128,22 +140,23 @@ func (s *DockerSuite) TestExecAPIStartMultipleTimesError(c *check.C) { func (s *DockerSuite) TestExecAPIStartWithDetach(c *check.C) { name := "foo" runSleepingContainer(c, "-d", "-t", "--name", name) - data := map[string]interface{}{ - "cmd": []string{"true"}, - "AttachStdin": true, - } - _, b, err := request.SockRequest("POST", fmt.Sprintf("/containers/%s/exec", name), data, daemonHost()) - c.Assert(err, checker.IsNil, check.Commentf(string(b))) - createResp := struct { - ID string `json:"Id"` - }{} - c.Assert(json.Unmarshal(b, &createResp), checker.IsNil, check.Commentf(string(b))) + config := types.ExecConfig{ + Cmd: []string{"true"}, + AttachStderr: true, + } + + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + createResp, err := cli.ContainerExecCreate(context.Background(), name, config) + c.Assert(err, checker.IsNil) _, body, err := request.Post(fmt.Sprintf("/exec/%s/start", createResp.ID), request.RawString(`{"Detach": true}`), request.JSON) c.Assert(err, checker.IsNil) - b, err = request.ReadBody(body) + b, err := request.ReadBody(body) comment := check.Commentf("response body: %s", b) c.Assert(err, checker.IsNil, comment) diff --git a/integration-cli/docker_api_images_test.go b/integration-cli/docker_api_images_test.go index 0cdd50685a..8ad12fb77d 100644 --- a/integration-cli/docker_api_images_test.go +++ b/integration-cli/docker_api_images_test.go @@ -1,38 +1,40 @@ package main import ( - "encoding/json" "net/http" "net/http/httptest" - "net/url" "strings" "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/image" + "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/client" "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/cli" "github.com/docker/docker/integration-cli/cli/build" "github.com/docker/docker/integration-cli/request" "github.com/go-check/check" + "golang.org/x/net/context" ) func (s *DockerSuite) TestAPIImagesFilter(c *check.C) { + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + name := "utest:tag1" name2 := "utest/docker:tag2" name3 := "utest:5000/docker:tag3" for _, n := range []string{name, name2, name3} { dockerCmd(c, "tag", "busybox", n) } - type image types.ImageSummary - getImages := func(filter string) []image { - v := url.Values{} - v.Set("filter", filter) - status, b, err := request.SockRequest("GET", "/images/json?"+v.Encode(), nil, daemonHost()) - c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusOK) - - var images []image - err = json.Unmarshal(b, &images) + getImages := func(filter string) []types.ImageSummary { + filters := filters.NewArgs() + filters.Add("reference", filter) + options := types.ImageListOptions{ + All: false, + Filters: filters, + } + images, err := cli.ImageList(context.Background(), options) c.Assert(err, checker.IsNil) return images @@ -74,6 +76,10 @@ func (s *DockerSuite) TestAPIImagesSaveAndLoad(c *check.C) { } func (s *DockerSuite) TestAPIImagesDelete(c *check.C) { + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + if testEnv.DaemonPlatform() != "windows" { testRequires(c, Network) } @@ -83,20 +89,21 @@ func (s *DockerSuite) TestAPIImagesDelete(c *check.C) { dockerCmd(c, "tag", name, "test:tag1") - status, _, err := request.SockRequest("DELETE", "/images/"+id, nil, daemonHost()) - c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusConflict) + _, err = cli.ImageRemove(context.Background(), id, types.ImageRemoveOptions{}) + c.Assert(err.Error(), checker.Contains, "unable to delete") - status, _, err = request.SockRequest("DELETE", "/images/test:noexist", nil, daemonHost()) - c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusNotFound) //Status Codes:404 – no such image + _, err = cli.ImageRemove(context.Background(), "test:noexist", types.ImageRemoveOptions{}) + c.Assert(err.Error(), checker.Contains, "No such image") - status, _, err = request.SockRequest("DELETE", "/images/test:tag1", nil, daemonHost()) + _, err = cli.ImageRemove(context.Background(), "test:tag1", types.ImageRemoveOptions{}) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusOK) } func (s *DockerSuite) TestAPIImagesHistory(c *check.C) { + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + if testEnv.DaemonPlatform() != "windows" { testRequires(c, Network) } @@ -104,13 +111,8 @@ func (s *DockerSuite) TestAPIImagesHistory(c *check.C) { buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nENV FOO bar")) id := getIDByName(c, name) - status, body, err := request.SockRequest("GET", "/images/"+id+"/history", nil, daemonHost()) + historydata, err := cli.ImageHistory(context.Background(), id) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusOK) - - var historydata []image.HistoryResponseItem - err = json.Unmarshal(body, &historydata) - c.Assert(err, checker.IsNil, check.Commentf("Error on unmarshal")) c.Assert(historydata, checker.Not(checker.HasLen), 0) c.Assert(historydata[0].Tags[0], checker.Equals, "test-api-images-history:latest") @@ -133,9 +135,8 @@ func (s *DockerSuite) TestAPIImagesImportBadSrc(c *check.C) { } for _, te := range tt { - res, b, err := request.SockRequestRaw("POST", strings.Join([]string{"/images/create?fromSrc=", te.fromSrc}, ""), nil, "application/json", daemonHost()) + res, _, err := request.Post(strings.Join([]string{"/images/create?fromSrc=", te.fromSrc}, ""), request.JSON) c.Assert(err, check.IsNil) - b.Close() c.Assert(res.StatusCode, checker.Equals, te.statusExp) c.Assert(res.Header.Get("Content-Type"), checker.Equals, "application/json") } @@ -156,11 +157,11 @@ func (s *DockerSuite) TestAPIImagesSearchJSONContentType(c *check.C) { // Test case for 30027: image size reported as -1 in v1.12 client against v1.13 daemon. // This test checks to make sure both v1.12 and v1.13 client against v1.13 daemon get correct `Size` after the fix. func (s *DockerSuite) TestAPIImagesSizeCompatibility(c *check.C) { - status, b, err := request.SockRequest("GET", "/images/json", nil, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusOK) - var images []types.ImageSummary - err = json.Unmarshal(b, &images) + defer cli.Close() + + images, err := cli.ImageList(context.Background(), types.ImageListOptions{}) c.Assert(err, checker.IsNil) c.Assert(len(images), checker.Not(checker.Equals), 0) for _, image := range images { @@ -177,11 +178,13 @@ func (s *DockerSuite) TestAPIImagesSizeCompatibility(c *check.C) { VirtualSize int64 Labels map[string]string } - status, b, err = request.SockRequest("GET", "/v1.24/images/json", nil, daemonHost()) + + var httpClient *http.Client + cli, err = client.NewClient(daemonHost(), "v1.24", httpClient, nil) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusOK) - var v124Images []v124Image - err = json.Unmarshal(b, &v124Images) + defer cli.Close() + + v124Images, err := cli.ImageList(context.Background(), types.ImageListOptions{}) c.Assert(err, checker.IsNil) c.Assert(len(v124Images), checker.Not(checker.Equals), 0) for _, image := range v124Images { diff --git a/integration-cli/docker_api_info_test.go b/integration-cli/docker_api_info_test.go index 8bc437bf79..60ca4b928f 100644 --- a/integration-cli/docker_api_info_test.go +++ b/integration-cli/docker_api_info_test.go @@ -4,17 +4,23 @@ import ( "encoding/json" "net/http" + "fmt" + "github.com/docker/docker/api/types" + + "github.com/docker/docker/client" "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/request" "github.com/go-check/check" + "golang.org/x/net/context" ) func (s *DockerSuite) TestInfoAPI(c *check.C) { - endpoint := "/info" + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() - status, body, err := request.SockRequest("GET", endpoint, nil, daemonHost()) - c.Assert(status, checker.Equals, http.StatusOK) + info, err := cli.Info(context.Background()) c.Assert(err, checker.IsNil) // always shown fields @@ -36,7 +42,7 @@ func (s *DockerSuite) TestInfoAPI(c *check.C) { "ServerVersion", "SecurityOptions"} - out := string(body) + out := fmt.Sprintf("%+v", info) for _, linePrefix := range stringsToCheck { c.Assert(out, checker.Contains, linePrefix) } @@ -63,13 +69,15 @@ func (s *DockerSuite) TestInfoAPIRuncCommit(c *check.C) { func (s *DockerSuite) TestInfoAPIVersioned(c *check.C) { testRequires(c, DaemonIsLinux) // Windows only supports 1.25 or later - endpoint := "/v1.20/info" - status, body, err := request.SockRequest("GET", endpoint, nil, daemonHost()) - c.Assert(status, checker.Equals, http.StatusOK) + res, body, err := request.Get("/v1.20/info") + c.Assert(res.StatusCode, checker.Equals, http.StatusOK) c.Assert(err, checker.IsNil) - out := string(body) + b, err := request.ReadBody(body) + c.Assert(err, checker.IsNil) + + out := string(b) c.Assert(out, checker.Contains, "ExecutionDriver") c.Assert(out, checker.Contains, "not supported") } diff --git a/integration-cli/docker_api_inspect_test.go b/integration-cli/docker_api_inspect_test.go index f2aa883fa0..6386354945 100644 --- a/integration-cli/docker_api_inspect_test.go +++ b/integration-cli/docker_api_inspect_test.go @@ -2,13 +2,14 @@ package main import ( "encoding/json" - "net/http" "strings" + "golang.org/x/net/context" + "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/versions/v1p20" + "github.com/docker/docker/client" "github.com/docker/docker/integration-cli/checker" - "github.com/docker/docker/integration-cli/request" "github.com/docker/docker/pkg/stringutils" "github.com/go-check/check" ) @@ -106,18 +107,14 @@ func (s *DockerSuite) TestInspectAPIContainerVolumeDriver(c *check.C) { func (s *DockerSuite) TestInspectAPIImageResponse(c *check.C) { dockerCmd(c, "tag", "busybox:latest", "busybox:mytag") - - endpoint := "/images/busybox/json" - status, body, err := request.SockRequest("GET", endpoint, nil, daemonHost()) - + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + imageJSON, _, err := cli.ImageInspectWithRaw(context.Background(), "busybox") c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusOK) - var imageJSON types.ImageInspect - err = json.Unmarshal(body, &imageJSON) - c.Assert(err, checker.IsNil, check.Commentf("Unable to unmarshal body for latest version")) c.Assert(imageJSON.RepoTags, checker.HasLen, 2) - c.Assert(stringutils.InSlice(imageJSON.RepoTags, "busybox:latest"), checker.Equals, true) c.Assert(stringutils.InSlice(imageJSON.RepoTags, "busybox:mytag"), checker.Equals, true) } diff --git a/integration-cli/docker_api_inspect_unix_test.go b/integration-cli/docker_api_inspect_unix_test.go index f7731f3d97..93c40947af 100644 --- a/integration-cli/docker_api_inspect_unix_test.go +++ b/integration-cli/docker_api_inspect_unix_test.go @@ -4,12 +4,12 @@ package main import ( "encoding/json" - "fmt" "net/http" + "github.com/docker/docker/client" "github.com/docker/docker/integration-cli/checker" - "github.com/docker/docker/integration-cli/request" "github.com/go-check/check" + "golang.org/x/net/context" ) // #16665 @@ -19,9 +19,11 @@ func (s *DockerSuite) TestInspectAPICpusetInConfigPre120(c *check.C) { name := "cpusetinconfig-pre120" dockerCmd(c, "run", "--name", name, "--cpuset-cpus", "0", "busybox", "true") - - status, body, err := request.SockRequest("GET", fmt.Sprintf("/v1.19/containers/%s/json", name), nil, daemonHost()) - c.Assert(status, check.Equals, http.StatusOK) + var httpClient *http.Client + cli, err := client.NewClient(daemonHost(), "v1.19", httpClient, nil) + c.Assert(err, checker.IsNil) + defer cli.Close() + _, body, err := cli.ContainerInspectWithRaw(context.Background(), name, false) c.Assert(err, check.IsNil) var inspectJSON map[string]interface{} diff --git a/integration-cli/docker_api_logs_test.go b/integration-cli/docker_api_logs_test.go index 5e953b79de..1f2a30a929 100644 --- a/integration-cli/docker_api_logs_test.go +++ b/integration-cli/docker_api_logs_test.go @@ -7,9 +7,12 @@ import ( "strings" "time" + "github.com/docker/docker/api/types" + "github.com/docker/docker/client" "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/request" "github.com/go-check/check" + "golang.org/x/net/context" ) func (s *DockerSuite) TestLogsAPIWithStdout(c *check.C) { @@ -51,13 +54,13 @@ func (s *DockerSuite) TestLogsAPIWithStdout(c *check.C) { func (s *DockerSuite) TestLogsAPINoStdoutNorStderr(c *check.C) { name := "logs_test" dockerCmd(c, "run", "-d", "-t", "--name", name, "busybox", "/bin/sh") - - status, body, err := request.SockRequest("GET", fmt.Sprintf("/containers/%s/logs", name), nil, daemonHost()) - c.Assert(status, checker.Equals, http.StatusBadRequest) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) + defer cli.Close() + _, err = cli.ContainerLogs(context.Background(), name, types.ContainerLogsOptions{}) expected := "Bad parameters: you must choose at least one stream" - c.Assert(getErrorMessage(c, body), checker.Contains, expected) + c.Assert(err.Error(), checker.Contains, expected) } // Regression test for #12704 diff --git a/integration-cli/docker_api_resize_test.go b/integration-cli/docker_api_resize_test.go index 68ac67f8e7..8ecf540a72 100644 --- a/integration-cli/docker_api_resize_test.go +++ b/integration-cli/docker_api_resize_test.go @@ -1,9 +1,12 @@ package main import ( + "context" "net/http" "strings" + "github.com/docker/docker/api/types" + "github.com/docker/docker/client" "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/request" "github.com/go-check/check" @@ -12,10 +15,15 @@ import ( func (s *DockerSuite) TestResizeAPIResponse(c *check.C) { out := runSleepingContainer(c, "-d") cleanedContainerID := strings.TrimSpace(out) + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() - endpoint := "/containers/" + cleanedContainerID + "/resize?h=40&w=40" - status, _, err := request.SockRequest("POST", endpoint, nil, daemonHost()) - c.Assert(status, check.Equals, http.StatusOK) + options := types.ResizeOptions{ + Height: 40, + Width: 40, + } + err = cli.ContainerResize(context.Background(), cleanedContainerID, options) c.Assert(err, check.IsNil) } @@ -24,8 +32,8 @@ func (s *DockerSuite) TestResizeAPIHeightWidthNoInt(c *check.C) { cleanedContainerID := strings.TrimSpace(out) endpoint := "/containers/" + cleanedContainerID + "/resize?h=foo&w=bar" - status, _, err := request.SockRequest("POST", endpoint, nil, daemonHost()) - c.Assert(status, check.Equals, http.StatusBadRequest) + res, _, err := request.Post(endpoint) + c.Assert(res.StatusCode, check.Equals, http.StatusBadRequest) c.Assert(err, check.IsNil) } @@ -36,10 +44,15 @@ func (s *DockerSuite) TestResizeAPIResponseWhenContainerNotStarted(c *check.C) { // make sure the exited container is not running dockerCmd(c, "wait", cleanedContainerID) - endpoint := "/containers/" + cleanedContainerID + "/resize?h=40&w=40" - status, body, err := request.SockRequest("POST", endpoint, nil, daemonHost()) - c.Assert(status, check.Equals, http.StatusConflict) - c.Assert(err, check.IsNil) + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() - c.Assert(getErrorMessage(c, body), checker.Contains, "is not running", check.Commentf("resize should fail with message 'Container is not running'")) + options := types.ResizeOptions{ + Height: 40, + Width: 40, + } + + err = cli.ContainerResize(context.Background(), cleanedContainerID, options) + c.Assert(err.Error(), checker.Contains, "is not running") } diff --git a/integration-cli/docker_api_stats_test.go b/integration-cli/docker_api_stats_test.go index f1cb5bb4ad..2e8515a3f6 100644 --- a/integration-cli/docker_api_stats_test.go +++ b/integration-cli/docker_api_stats_test.go @@ -13,9 +13,11 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/versions" + "github.com/docker/docker/client" "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/request" "github.com/go-check/check" + "golang.org/x/net/context" ) var expectedNetworkInterfaceStats = strings.Split("rx_bytes rx_dropped rx_errors rx_packets tx_bytes tx_dropped tx_errors tx_packets", " ") @@ -260,14 +262,16 @@ func jsonBlobHasGTE121NetworkStats(blob map[string]interface{}) bool { func (s *DockerSuite) TestAPIStatsContainerNotFound(c *check.C) { testRequires(c, DaemonIsLinux) - - status, _, err := request.SockRequest("GET", "/containers/nonexistent/stats", nil, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusNotFound) + defer cli.Close() - status, _, err = request.SockRequest("GET", "/containers/nonexistent/stats?stream=0", nil, daemonHost()) - c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusNotFound) + expected := "No such container: nonexistent" + + _, err = cli.ContainerStats(context.Background(), "nonexistent", true) + c.Assert(err.Error(), checker.Contains, expected) + _, err = cli.ContainerStats(context.Background(), "nonexistent", false) + c.Assert(err.Error(), checker.Contains, expected) } func (s *DockerSuite) TestAPIStatsNoStreamConnectedContainers(c *check.C) { diff --git a/integration-cli/docker_api_swarm_config_test.go b/integration-cli/docker_api_swarm_config_test.go index fab65ccbd0..c06f3c45ea 100644 --- a/integration-cli/docker_api_swarm_config_test.go +++ b/integration-cli/docker_api_swarm_config_test.go @@ -3,12 +3,10 @@ package main import ( - "fmt" - "net/http" - "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/integration-cli/checker" "github.com/go-check/check" + "golang.org/x/net/context" ) func (s *DockerSwarmSuite) TestAPISwarmConfigsEmptyList(c *check.C) { @@ -52,9 +50,15 @@ func (s *DockerSwarmSuite) TestAPISwarmConfigsDelete(c *check.C) { c.Assert(config.ID, checker.Equals, id, check.Commentf("config: %v", config)) d.DeleteConfig(c, config.ID) - status, out, err := d.SockRequest("GET", "/configs/"+id, nil) + + cli, err := d.NewClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusNotFound, check.Commentf("config delete: %s", string(out))) + defer cli.Close() + + expected := "no such config" + + _, _, err = cli.ConfigInspectWithRaw(context.Background(), id) + c.Assert(err.Error(), checker.Contains, expected) } func (s *DockerSwarmSuite) TestAPISwarmConfigsUpdate(c *check.C) { @@ -110,9 +114,12 @@ func (s *DockerSwarmSuite) TestAPISwarmConfigsUpdate(c *check.C) { config = d.GetConfig(c, id) config.Spec.Data = []byte("TESTINGDATA2") - url := fmt.Sprintf("/configs/%s/update?version=%d", config.ID, config.Version.Index) - status, out, err := d.SockRequest("POST", url, config.Spec) + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusBadRequest, check.Commentf("output: %q", string(out))) + expected := "only updates to Labels are allowed" + + err = cli.ConfigUpdate(context.Background(), config.ID, config.Version, config.Spec) + c.Assert(err.Error(), checker.Contains, expected) } diff --git a/integration-cli/docker_api_swarm_secret_test.go b/integration-cli/docker_api_swarm_secret_test.go index cb82af8e2e..db346dd283 100644 --- a/integration-cli/docker_api_swarm_secret_test.go +++ b/integration-cli/docker_api_swarm_secret_test.go @@ -3,12 +3,12 @@ package main import ( - "fmt" "net/http" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/integration-cli/checker" "github.com/go-check/check" + "golang.org/x/net/context" ) func (s *DockerSwarmSuite) TestAPISwarmSecretsEmptyList(c *check.C) { @@ -59,16 +59,19 @@ func (s *DockerSwarmSuite) TestAPISwarmSecretsDelete(c *check.C) { c.Assert(secret.ID, checker.Equals, id, check.Commentf("secret: %v", secret)) d.DeleteSecret(c, secret.ID) - status, out, err := d.SockRequest("GET", "/secrets/"+id, nil) - c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusNotFound, check.Commentf("secret delete: %s", string(out))) - // delete non-existing secret, daemon should return a status code of 404 + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + expected := "no such secret" + _, _, err = cli.SecretInspectWithRaw(context.Background(), id) + c.Assert(err.Error(), checker.Contains, expected) + id = "non-existing" - status, out, err = d.SockRequest("DELETE", "/secrets/"+id, nil) - c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusNotFound, check.Commentf("secret delete: %s", string(out))) - + expected = "secret non-existing not found" + err = cli.SecretRemove(context.Background(), id) + c.Assert(err.Error(), checker.Contains, expected) } func (s *DockerSwarmSuite) TestAPISwarmSecretsUpdate(c *check.C) { @@ -124,9 +127,12 @@ func (s *DockerSwarmSuite) TestAPISwarmSecretsUpdate(c *check.C) { secret = d.GetSecret(c, id) secret.Spec.Data = []byte("TESTINGDATA2") - url := fmt.Sprintf("/secrets/%s/update?version=%d", secret.ID, secret.Version.Index) - status, out, err := d.SockRequest("POST", url, secret.Spec) + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusBadRequest, check.Commentf("output: %q", string(out))) + expected := "only updates to Labels are allowed" + + err = cli.SecretUpdate(context.Background(), secret.ID, secret.Version, secret.Spec) + c.Assert(err.Error(), checker.Contains, expected) } diff --git a/integration-cli/docker_api_swarm_service_test.go b/integration-cli/docker_api_swarm_service_test.go index 1530ea1ab3..68b78b6453 100644 --- a/integration-cli/docker_api_swarm_service_test.go +++ b/integration-cli/docker_api_swarm_service_test.go @@ -9,6 +9,7 @@ import ( "strings" "time" + "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/api/types/swarm/runtime" "github.com/docker/docker/integration-cli/checker" @@ -64,14 +65,24 @@ func (s *DockerSwarmSuite) TestAPISwarmServicesCreate(c *check.C) { id := d.CreateService(c, simpleTestService, setInstances(instances)) waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, instances) - // insertDefaults inserts UpdateConfig when service is fetched by ID - _, out, err := d.SockRequest("GET", "/services/"+id+"?insertDefaults=true", nil) - c.Assert(err, checker.IsNil, check.Commentf("%s", out)) - c.Assert(string(out), checker.Contains, "UpdateConfig") + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + options := types.ServiceInspectOptions{ + InsertDefaults: true, + } // insertDefaults inserts UpdateConfig when service is fetched by ID - _, out, err = d.SockRequest("GET", "/services/top?insertDefaults=true", nil) - c.Assert(err, checker.IsNil, check.Commentf("%s", out)) + resp, _, err := cli.ServiceInspectWithRaw(context.Background(), id, options) + out := fmt.Sprintf("%+v", resp) + c.Assert(err, checker.IsNil) + c.Assert(out, checker.Contains, "UpdateConfig") + + // insertDefaults inserts UpdateConfig when service is fetched by ID + resp, _, err = cli.ServiceInspectWithRaw(context.Background(), "top", options) + out = fmt.Sprintf("%+v", resp) + c.Assert(err, checker.IsNil) c.Assert(string(out), checker.Contains, "UpdateConfig") service := d.GetService(c, id) @@ -195,7 +206,7 @@ func (s *DockerSwarmSuite) TestAPISwarmServicesUpdateStartFirst(c *check.C) { // service image at start image1 := "busybox:latest" // target image in update - image2 := "testhealth" + image2 := "testhealth:latest" // service started from this image won't pass health check _, _, err := d.BuildImageWithOut(image2, diff --git a/integration-cli/docker_api_swarm_test.go b/integration-cli/docker_api_swarm_test.go index 9d24757b4f..8f8b8eb138 100644 --- a/integration-cli/docker_api_swarm_test.go +++ b/integration-cli/docker_api_swarm_test.go @@ -23,8 +23,10 @@ import ( "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/daemon" + "github.com/docker/docker/integration-cli/request" "github.com/docker/swarmkit/ca" "github.com/go-check/check" + "golang.org/x/net/context" ) var defaultReconciliationTimeout = 30 * time.Second @@ -228,17 +230,20 @@ func (s *DockerSwarmSuite) TestAPISwarmPromoteDemote(c *check.C) { node := d1.GetNode(c, d1.NodeID) node.Spec.Role = swarm.NodeRoleWorker url := fmt.Sprintf("/nodes/%s/update?version=%d", node.ID, node.Version.Index) - status, out, err := d1.SockRequest("POST", url, node.Spec) + res, body, err := request.DoOnHost(d1.Sock(), url, request.Method("POST"), request.JSONBody(node.Spec)) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusBadRequest, check.Commentf("output: %q", string(out))) + b, err := request.ReadBody(body) + c.Assert(err, checker.IsNil) + c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest, check.Commentf("output: %q", string(b))) + // The warning specific to demoting the last manager is best-effort and // won't appear until the Role field of the demoted manager has been // updated. // Yes, I know this looks silly, but checker.Matches is broken, since // it anchors the regexp contrary to the documentation, and this makes // it impossible to match something that includes a line break. - if !strings.Contains(string(out), "last manager of the swarm") { - c.Assert(string(out), checker.Contains, "this would result in a loss of quorum") + if !strings.Contains(string(b), "last manager of the swarm") { + c.Assert(string(b), checker.Contains, "this would result in a loss of quorum") } info, err = d1.SwarmInfo() c.Assert(err, checker.IsNil) @@ -362,9 +367,11 @@ func (s *DockerSwarmSuite) TestAPISwarmRaftQuorum(c *check.C) { var service swarm.Service simpleTestService(&service) service.Spec.Name = "top2" - status, out, err := d1.SockRequest("POST", "/services/create", service.Spec) + cli, err := d1.NewClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusInternalServerError, check.Commentf("deadline exceeded", string(out))) + defer cli.Close() + _, err = cli.ServiceCreate(context.Background(), service.Spec, types.ServiceCreateOptions{}) + c.Assert(err.Error(), checker.Contains, "deadline exceeded") d2.Start(c) @@ -505,17 +512,17 @@ func (s *DockerSwarmSuite) TestAPISwarmInvalidAddress(c *check.C) { req := swarm.InitRequest{ ListenAddr: "", } - status, _, err := d.SockRequest("POST", "/swarm/init", req) + res, _, err := request.DoOnHost(d.Sock(), "/swarm/init", request.Method("POST"), request.JSONBody(req)) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusBadRequest) + c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest) req2 := swarm.JoinRequest{ ListenAddr: "0.0.0.0:2377", RemoteAddrs: []string{""}, } - status, _, err = d.SockRequest("POST", "/swarm/join", req2) + res, _, err = request.DoOnHost(d.Sock(), "/swarm/join", request.Method("POST"), request.JSONBody(req2)) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusBadRequest) + c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest) } func (s *DockerSwarmSuite) TestAPISwarmForceNewCluster(c *check.C) { @@ -836,10 +843,11 @@ func (s *DockerSwarmSuite) TestAPISwarmServicesUpdateWithName(c *check.C) { instances = 5 setInstances(instances)(service) - url := fmt.Sprintf("/services/%s/update?version=%d", service.Spec.Name, service.Version.Index) - status, out, err := d.SockRequest("POST", url, service.Spec) + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + _, err = cli.ServiceUpdate(context.Background(), service.Spec.Name, service.Version, service.Spec, types.ServiceUpdateOptions{}) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out))) waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, instances) } @@ -867,51 +875,31 @@ func (s *DockerSwarmSuite) TestAPISwarmErrorHandling(c *check.C) { // This test makes sure the fixes correctly output scopes instead. func (s *DockerSwarmSuite) TestAPIDuplicateNetworks(c *check.C) { d := s.AddDaemon(c, true, true) + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() name := "foo" - networkCreateRequest := types.NetworkCreateRequest{ - Name: name, - NetworkCreate: types.NetworkCreate{ - CheckDuplicate: false, - }, + networkCreate := types.NetworkCreate{ + CheckDuplicate: false, } - var n1 types.NetworkCreateResponse - networkCreateRequest.NetworkCreate.Driver = "bridge" + networkCreate.Driver = "bridge" - status, out, err := d.SockRequest("POST", "/networks/create", networkCreateRequest) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusCreated, check.Commentf(string(out))) + n1, err := cli.NetworkCreate(context.Background(), name, networkCreate) + c.Assert(err, checker.IsNil) - c.Assert(json.Unmarshal(out, &n1), checker.IsNil) + networkCreate.Driver = "overlay" - var n2 types.NetworkCreateResponse - networkCreateRequest.NetworkCreate.Driver = "overlay" - - status, out, err = d.SockRequest("POST", "/networks/create", networkCreateRequest) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusCreated, check.Commentf(string(out))) - - c.Assert(json.Unmarshal(out, &n2), checker.IsNil) - - var r1 types.NetworkResource - - status, out, err = d.SockRequest("GET", "/networks/"+n1.ID, nil) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf(string(out))) - - c.Assert(json.Unmarshal(out, &r1), checker.IsNil) + n2, err := cli.NetworkCreate(context.Background(), name, networkCreate) + c.Assert(err, checker.IsNil) + r1, err := cli.NetworkInspect(context.Background(), n1.ID, types.NetworkInspectOptions{}) + c.Assert(err, checker.IsNil) c.Assert(r1.Scope, checker.Equals, "local") - var r2 types.NetworkResource - - status, out, err = d.SockRequest("GET", "/networks/"+n2.ID, nil) - c.Assert(err, checker.IsNil, check.Commentf(string(out))) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf(string(out))) - - c.Assert(json.Unmarshal(out, &r2), checker.IsNil) - + r2, err := cli.NetworkInspect(context.Background(), n2.ID, types.NetworkInspectOptions{}) + c.Assert(err, checker.IsNil) c.Assert(r2.Scope, checker.Equals, "swarm") } diff --git a/integration-cli/docker_api_update_unix_test.go b/integration-cli/docker_api_update_unix_test.go index 1af6ed1e7c..e2e1b092be 100644 --- a/integration-cli/docker_api_update_unix_test.go +++ b/integration-cli/docker_api_update_unix_test.go @@ -5,9 +5,11 @@ package main import ( "strings" + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/client" "github.com/docker/docker/integration-cli/checker" - "github.com/docker/docker/integration-cli/request" "github.com/go-check/check" + "golang.org/x/net/context" ) func (s *DockerSuite) TestAPIUpdateContainer(c *check.C) { @@ -16,12 +18,19 @@ func (s *DockerSuite) TestAPIUpdateContainer(c *check.C) { testRequires(c, swapMemorySupport) name := "apiUpdateContainer" - hostConfig := map[string]interface{}{ - "Memory": 314572800, - "MemorySwap": 524288000, + updateConfig := container.UpdateConfig{ + Resources: container.Resources{ + Memory: 314572800, + MemorySwap: 524288000, + }, } dockerCmd(c, "run", "-d", "--name", name, "-m", "200M", "busybox", "top") - _, _, err := request.SockRequest("POST", "/containers/"+name+"/update", hostConfig, daemonHost()) + cli, err := client.NewEnvClient() + c.Assert(err, check.IsNil) + defer cli.Close() + + _, err = cli.ContainerUpdate(context.Background(), name, updateConfig) + c.Assert(err, check.IsNil) c.Assert(inspectField(c, name, "HostConfig.Memory"), checker.Equals, "314572800") diff --git a/integration-cli/docker_api_version_test.go b/integration-cli/docker_api_version_test.go index 5f919deb75..0b995f7a15 100644 --- a/integration-cli/docker_api_version_test.go +++ b/integration-cli/docker_api_version_test.go @@ -1,24 +1,18 @@ package main import ( - "encoding/json" - "net/http" - - "github.com/docker/docker/api/types" + "github.com/docker/docker/client" "github.com/docker/docker/dockerversion" "github.com/docker/docker/integration-cli/checker" - "github.com/docker/docker/integration-cli/request" "github.com/go-check/check" + "golang.org/x/net/context" ) func (s *DockerSuite) TestGetVersion(c *check.C) { - status, body, err := request.SockRequest("GET", "/version", nil, daemonHost()) - c.Assert(status, checker.Equals, http.StatusOK) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) + defer cli.Close() - var v types.Version - - c.Assert(json.Unmarshal(body, &v), checker.IsNil) - + v, err := cli.ServerVersion(context.Background()) c.Assert(v.Version, checker.Equals, dockerversion.Version, check.Commentf("Version mismatch")) } diff --git a/integration-cli/docker_api_volumes_test.go b/integration-cli/docker_api_volumes_test.go index f354856d32..5e3d6a929a 100644 --- a/integration-cli/docker_api_volumes_test.go +++ b/integration-cli/docker_api_volumes_test.go @@ -1,30 +1,29 @@ package main import ( - "encoding/json" "fmt" - "net/http" "path/filepath" "strings" "time" - "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" volumetypes "github.com/docker/docker/api/types/volume" + "github.com/docker/docker/client" "github.com/docker/docker/integration-cli/checker" - "github.com/docker/docker/integration-cli/request" "github.com/go-check/check" + "golang.org/x/net/context" ) func (s *DockerSuite) TestVolumesAPIList(c *check.C) { prefix, _ := getPrefixAndSlashFromDaemonPlatform() dockerCmd(c, "run", "-v", prefix+"/foo", "busybox") - status, b, err := request.SockRequest("GET", "/volumes", nil, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusOK) + defer cli.Close() - var volumes volumetypes.VolumesListOKBody - c.Assert(json.Unmarshal(b, &volumes), checker.IsNil) + volumes, err := cli.VolumeList(context.Background(), filters.Args{}) + c.Assert(err, checker.IsNil) c.Assert(len(volumes.Volumes), checker.Equals, 1, check.Commentf("\n%v", volumes.Volumes)) } @@ -33,13 +32,13 @@ func (s *DockerSuite) TestVolumesAPICreate(c *check.C) { config := volumetypes.VolumesCreateBody{ Name: "test", } - status, b, err := request.SockRequest("POST", "/volumes/create", config, daemonHost()) - c.Assert(err, check.IsNil) - c.Assert(status, check.Equals, http.StatusCreated, check.Commentf(string(b))) - var vol types.Volume - err = json.Unmarshal(b, &vol) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) + defer cli.Close() + + vol, err := cli.VolumeCreate(context.Background(), config) + c.Assert(err, check.IsNil) c.Assert(filepath.Base(filepath.Dir(vol.Mountpoint)), checker.Equals, config.Name) } @@ -48,49 +47,43 @@ func (s *DockerSuite) TestVolumesAPIRemove(c *check.C) { prefix, _ := getPrefixAndSlashFromDaemonPlatform() dockerCmd(c, "run", "-v", prefix+"/foo", "--name=test", "busybox") - status, b, err := request.SockRequest("GET", "/volumes", nil, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusOK) + defer cli.Close() - var volumes volumetypes.VolumesListOKBody - c.Assert(json.Unmarshal(b, &volumes), checker.IsNil) - c.Assert(len(volumes.Volumes), checker.Equals, 1, check.Commentf("\n%v", volumes.Volumes)) + volumes, err := cli.VolumeList(context.Background(), filters.Args{}) + c.Assert(err, checker.IsNil) v := volumes.Volumes[0] - status, _, err = request.SockRequest("DELETE", "/volumes/"+v.Name, nil, daemonHost()) - c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusConflict, check.Commentf("Should not be able to remove a volume that is in use")) + err = cli.VolumeRemove(context.Background(), v.Name, false) + c.Assert(err.Error(), checker.Contains, "volume is in use") dockerCmd(c, "rm", "-f", "test") - status, data, err := request.SockRequest("DELETE", "/volumes/"+v.Name, nil, daemonHost()) + err = cli.VolumeRemove(context.Background(), v.Name, false) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusNoContent, check.Commentf(string(data))) - } func (s *DockerSuite) TestVolumesAPIInspect(c *check.C) { config := volumetypes.VolumesCreateBody{ Name: "test", } + // sampling current time minus a minute so to now have false positive in case of delays now := time.Now().Truncate(time.Minute) - status, b, err := request.SockRequest("POST", "/volumes/create", config, daemonHost()) - c.Assert(err, check.IsNil) - c.Assert(status, check.Equals, http.StatusCreated, check.Commentf(string(b))) - status, b, err = request.SockRequest("GET", "/volumes", nil, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf(string(b))) + defer cli.Close() - var volumes volumetypes.VolumesListOKBody - c.Assert(json.Unmarshal(b, &volumes), checker.IsNil) + _, err = cli.VolumeCreate(context.Background(), config) + c.Assert(err, check.IsNil) + + volumes, err := cli.VolumeList(context.Background(), filters.Args{}) + c.Assert(err, checker.IsNil) c.Assert(len(volumes.Volumes), checker.Equals, 1, check.Commentf("\n%v", volumes.Volumes)) - var vol types.Volume - status, b, err = request.SockRequest("GET", "/volumes/"+config.Name, nil, daemonHost()) + vol, err := cli.VolumeInspect(context.Background(), config.Name) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusOK, check.Commentf(string(b))) - c.Assert(json.Unmarshal(b, &vol), checker.IsNil) c.Assert(vol.Name, checker.Equals, config.Name) // comparing CreatedAt field time for the new volume to now. Removing a minute from both to avoid false positive diff --git a/integration-cli/docker_cli_events_test.go b/integration-cli/docker_cli_events_test.go index f3d839a317..d98c9fee94 100644 --- a/integration-cli/docker_cli_events_test.go +++ b/integration-cli/docker_cli_events_test.go @@ -6,20 +6,22 @@ import ( "fmt" "io" "io/ioutil" - "net/http" "os" "os/exec" "strings" "time" + "github.com/docker/docker/api/types" eventtypes "github.com/docker/docker/api/types/events" + "github.com/docker/docker/client" eventstestutils "github.com/docker/docker/daemon/events/testutils" "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/cli" "github.com/docker/docker/integration-cli/cli/build" - "github.com/docker/docker/integration-cli/request" + icmd "github.com/docker/docker/pkg/testutil/cmd" "github.com/go-check/check" + "golang.org/x/net/context" ) func (s *DockerSuite) TestEventsTimestampFormats(c *check.C) { @@ -498,9 +500,15 @@ func (s *DockerSuite) TestEventsResize(c *check.C) { cID := strings.TrimSpace(out) c.Assert(waitRun(cID), checker.IsNil) - endpoint := "/containers/" + cID + "/resize?h=80&w=24" - status, _, err := request.SockRequest("POST", endpoint, nil, daemonHost()) - c.Assert(status, checker.Equals, http.StatusOK) + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + options := types.ResizeOptions{ + Height: 80, + Width: 24, + } + err = cli.ContainerResize(context.Background(), cID, options) c.Assert(err, checker.IsNil) dockerCmd(c, "stop", cID) diff --git a/integration-cli/docker_cli_exec_test.go b/integration-cli/docker_cli_exec_test.go index be228ab2da..dfe062b5c8 100644 --- a/integration-cli/docker_cli_exec_test.go +++ b/integration-cli/docker_cli_exec_test.go @@ -5,7 +5,6 @@ package main import ( "bufio" "fmt" - "net/http" "os" "os/exec" "reflect" @@ -15,12 +14,13 @@ import ( "sync" "time" + "github.com/docker/docker/client" "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/cli" "github.com/docker/docker/integration-cli/cli/build" - "github.com/docker/docker/integration-cli/request" icmd "github.com/docker/docker/pkg/testutil/cmd" "github.com/go-check/check" + "golang.org/x/net/context" ) func (s *DockerSuite) TestExec(c *check.C) { @@ -357,16 +357,21 @@ func (s *DockerSuite) TestExecInspectID(c *check.C) { } // But we should still be able to query the execID - sc, body, _ := request.SockRequest("GET", "/exec/"+execID+"/json", nil, daemonHost()) + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() - c.Assert(sc, checker.Equals, http.StatusOK, check.Commentf("received status != 200 OK: %d\n%s", sc, body)) + _, err = cli.ContainerExecInspect(context.Background(), execID) + c.Assert(err, checker.IsNil) // Now delete the container and then an 'inspect' on the exec should // result in a 404 (not 'container not running') out, ec := dockerCmd(c, "rm", "-f", id) c.Assert(ec, checker.Equals, 0, check.Commentf("error removing container: %s", out)) - sc, body, _ = request.SockRequest("GET", "/exec/"+execID+"/json", nil, daemonHost()) - c.Assert(sc, checker.Equals, http.StatusNotFound, check.Commentf("received status != 404: %d\n%s", sc, body)) + + _, err = cli.ContainerExecInspect(context.Background(), execID) + expected := "No such exec instance" + c.Assert(err.Error(), checker.Contains, expected) } func (s *DockerSuite) TestLinksPingLinkedContainersOnRename(c *check.C) { diff --git a/integration-cli/docker_cli_kill_test.go b/integration-cli/docker_cli_kill_test.go index 3273ecf1f8..b4fb91c9ea 100644 --- a/integration-cli/docker_cli_kill_test.go +++ b/integration-cli/docker_cli_kill_test.go @@ -1,16 +1,16 @@ package main import ( - "fmt" "net/http" "strings" "time" + "github.com/docker/docker/client" "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/cli" - "github.com/docker/docker/integration-cli/request" icmd "github.com/docker/docker/pkg/testutil/cmd" "github.com/go-check/check" + "golang.org/x/net/context" ) func (s *DockerSuite) TestKillContainer(c *check.C) { @@ -131,8 +131,10 @@ func (s *DockerSuite) TestKillStoppedContainerAPIPre120(c *check.C) { testRequires(c, DaemonIsLinux) // Windows only supports 1.25 or later runSleepingContainer(c, "--name", "docker-kill-test-api", "-d") dockerCmd(c, "stop", "docker-kill-test-api") - - status, _, err := request.SockRequest("POST", fmt.Sprintf("/v1.19/containers/%s/kill", "docker-kill-test-api"), nil, daemonHost()) + var httpClient *http.Client + cli, err := client.NewClient(daemonHost(), "v1.19", httpClient, nil) + c.Assert(err, check.IsNil) + defer cli.Close() + err = cli.ContainerKill(context.Background(), "docker-kill-test-api", "SIGKILL") c.Assert(err, check.IsNil) - c.Assert(status, check.Equals, http.StatusNoContent) } diff --git a/integration-cli/docker_cli_plugins_logdriver_test.go b/integration-cli/docker_cli_plugins_logdriver_test.go index d74256656a..8104b3b766 100644 --- a/integration-cli/docker_cli_plugins_logdriver_test.go +++ b/integration-cli/docker_cli_plugins_logdriver_test.go @@ -1,14 +1,12 @@ package main import ( - "encoding/json" - "net/http" "strings" - "github.com/docker/docker/api/types" + "github.com/docker/docker/client" "github.com/docker/docker/integration-cli/checker" - "github.com/docker/docker/integration-cli/request" "github.com/go-check/check" + "golang.org/x/net/context" ) func (s *DockerSuite) TestPluginLogDriver(c *check.C) { @@ -36,13 +34,14 @@ func (s *DockerSuite) TestPluginLogDriverInfoList(c *check.C) { pluginName := "cpuguy83/docker-logdriver-test" dockerCmd(c, "plugin", "install", pluginName) - status, body, err := request.SockRequest("GET", "/info", nil, daemonHost()) - c.Assert(status, checker.Equals, http.StatusOK) + + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + info, err := cli.Info(context.Background()) c.Assert(err, checker.IsNil) - var info types.Info - err = json.Unmarshal(body, &info) - c.Assert(err, checker.IsNil) drivers := strings.Join(info.Plugins.Log, " ") c.Assert(drivers, checker.Contains, "json-file") c.Assert(drivers, checker.Not(checker.Contains), pluginName) diff --git a/integration-cli/docker_cli_swarm_test.go b/integration-cli/docker_cli_swarm_test.go index e5f3a794ae..b5297a5e72 100644 --- a/integration-cli/docker_cli_swarm_test.go +++ b/integration-cli/docker_cli_swarm_test.go @@ -29,6 +29,7 @@ import ( remoteipam "github.com/docker/libnetwork/ipams/remote/api" "github.com/go-check/check" "github.com/vishvananda/netlink" + "golang.org/x/net/context" ) func (s *DockerSwarmSuite) TestSwarmUpdate(c *check.C) { @@ -1843,19 +1844,17 @@ func (s *DockerSwarmSuite) TestNetworkInspectWithDuplicateNames(c *check.C) { d := s.AddDaemon(c, true, true) name := "foo" - networkCreateRequest := types.NetworkCreateRequest{ - Name: name, - NetworkCreate: types.NetworkCreate{ - CheckDuplicate: false, - Driver: "bridge", - }, + options := types.NetworkCreate{ + CheckDuplicate: false, + Driver: "bridge", } - var n1 types.NetworkCreateResponse - status, body, err := d.SockRequest("POST", "/networks/create", networkCreateRequest) - c.Assert(err, checker.IsNil, check.Commentf(string(body))) - c.Assert(status, checker.Equals, http.StatusCreated, check.Commentf(string(body))) - c.Assert(json.Unmarshal(body, &n1), checker.IsNil) + cli, err := d.NewClient() + c.Assert(err, checker.IsNil) + defer cli.Close() + + n1, err := cli.NetworkCreate(context.Background(), name, options) + c.Assert(err, checker.IsNil) // Full ID always works out, err := d.Cmd("network", "inspect", "--format", "{{.ID}}", n1.ID) @@ -1867,12 +1866,8 @@ func (s *DockerSwarmSuite) TestNetworkInspectWithDuplicateNames(c *check.C) { c.Assert(err, checker.IsNil, check.Commentf(out)) c.Assert(strings.TrimSpace(out), checker.Equals, n1.ID) - var n2 types.NetworkCreateResponse - status, body, err = d.SockRequest("POST", "/networks/create", networkCreateRequest) - c.Assert(err, checker.IsNil, check.Commentf(string(body))) - c.Assert(status, checker.Equals, http.StatusCreated, check.Commentf(string(body))) - c.Assert(json.Unmarshal(body, &n2), checker.IsNil) - + n2, err := cli.NetworkCreate(context.Background(), name, options) + c.Assert(err, checker.IsNil) // Full ID always works out, err = d.Cmd("network", "inspect", "--format", "{{.ID}}", n1.ID) c.Assert(err, checker.IsNil, check.Commentf(out)) @@ -1890,13 +1885,11 @@ func (s *DockerSwarmSuite) TestNetworkInspectWithDuplicateNames(c *check.C) { out, err = d.Cmd("network", "rm", n2.ID) c.Assert(err, checker.IsNil, check.Commentf(out)) - // Duplicates with name but with different driver - networkCreateRequest.NetworkCreate.Driver = "overlay" + // Dupliates with name but with different driver + options.Driver = "overlay" - status, body, err = d.SockRequest("POST", "/networks/create", networkCreateRequest) - c.Assert(err, checker.IsNil, check.Commentf(string(body))) - c.Assert(status, checker.Equals, http.StatusCreated, check.Commentf(string(body))) - c.Assert(json.Unmarshal(body, &n2), checker.IsNil) + n2, err = cli.NetworkCreate(context.Background(), name, options) + c.Assert(err, checker.IsNil) // Full ID always works out, err = d.Cmd("network", "inspect", "--format", "{{.ID}}", n1.ID) diff --git a/integration-cli/docker_cli_volume_test.go b/integration-cli/docker_cli_volume_test.go index e0bf7cafe3..0a2a74fc31 100644 --- a/integration-cli/docker_cli_volume_test.go +++ b/integration-cli/docker_cli_volume_test.go @@ -3,17 +3,20 @@ package main import ( "fmt" "io/ioutil" - "net/http" "os" "os/exec" "path/filepath" "strings" + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/mount" + "github.com/docker/docker/api/types/network" + "github.com/docker/docker/client" "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/cli/build" - "github.com/docker/docker/integration-cli/request" icmd "github.com/docker/docker/pkg/testutil/cmd" "github.com/go-check/check" + "golang.org/x/net/context" ) func (s *DockerSuite) TestVolumeCLICreate(c *check.C) { @@ -607,25 +610,28 @@ func (s *DockerSuite) TestDuplicateMountpointsForVolumesFromAndMounts(c *check.C err := os.MkdirAll("/tmp/data", 0755) c.Assert(err, checker.IsNil) // Mounts is available in API - status, body, err := request.SockRequest("POST", "/containers/create?name=app", map[string]interface{}{ - "Image": "busybox", - "Cmd": []string{"top"}, - "HostConfig": map[string]interface{}{ - "VolumesFrom": []string{ - "data1", - "data2", - }, - "Mounts": []map[string]interface{}{ - { - "Type": "bind", - "Source": "/tmp/data", - "Target": "/tmp/data", - }, - }}, - }, daemonHost()) + cli, err := client.NewEnvClient() + c.Assert(err, checker.IsNil) + defer cli.Close() - c.Assert(err, checker.IsNil, check.Commentf(string(body))) - c.Assert(status, checker.Equals, http.StatusCreated, check.Commentf(string(body))) + config := container.Config{ + Cmd: []string{"top"}, + Image: "busybox", + } + + hostConfig := container.HostConfig{ + VolumesFrom: []string{"data1", "data2"}, + Mounts: []mount.Mount{ + { + Type: "bind", + Source: "/tmp/data", + Target: "/tmp/data", + }, + }, + } + _, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &network.NetworkingConfig{}, "app") + + c.Assert(err, checker.IsNil) // No volume will be referenced (mount is /tmp/data), this is backward compatible out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "app") diff --git a/integration-cli/docker_deprecated_api_v124_test.go b/integration-cli/docker_deprecated_api_v124_test.go index 482425bf12..edf3e570f5 100644 --- a/integration-cli/docker_deprecated_api_v124_test.go +++ b/integration-cli/docker_deprecated_api_v124_test.go @@ -22,9 +22,14 @@ func (s *DockerSuite) TestDeprecatedContainerAPIStartHostConfig(c *check.C) { config := map[string]interface{}{ "Binds": []string{"/aa:/bb"}, } - status, _, err := request.SockRequest("POST", "/containers/"+name+"/start", config, daemonHost()) + res, body, err := request.Post("/containers/"+name+"/start", request.JSONBody(config)) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusBadRequest) + + buf, err := request.ReadBody(body) + c.Assert(err, checker.IsNil) + + c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest) + c.Assert(string(buf), checker.Contains, "was deprecated since API v1.22") } func (s *DockerSuite) TestDeprecatedContainerAPIStartVolumeBinds(c *check.C) { @@ -40,17 +45,17 @@ func (s *DockerSuite) TestDeprecatedContainerAPIStartVolumeBinds(c *check.C) { "Volumes": map[string]struct{}{path: {}}, } - status, _, err := request.SockRequest("POST", formatV123StartAPIURL("/containers/create?name="+name), config, daemonHost()) + res, _, err := request.Post(formatV123StartAPIURL("/containers/create?name="+name), request.JSONBody(config)) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusCreated) + c.Assert(res.StatusCode, checker.Equals, http.StatusCreated) bindPath := RandomTmpDirPath("test", testEnv.DaemonPlatform()) config = map[string]interface{}{ "Binds": []string{bindPath + ":" + path}, } - status, _, err = request.SockRequest("POST", formatV123StartAPIURL("/containers/"+name+"/start"), config, daemonHost()) + res, _, err = request.Post(formatV123StartAPIURL("/containers/"+name+"/start"), request.JSONBody(config)) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusNoContent) + c.Assert(res.StatusCode, checker.Equals, http.StatusNoContent) pth, err := inspectMountSourceField(name, path) c.Assert(err, checker.IsNil) @@ -67,9 +72,9 @@ func (s *DockerSuite) TestDeprecatedContainerAPIStartDupVolumeBinds(c *check.C) "Volumes": map[string]struct{}{"/tmp": {}}, } - status, _, err := request.SockRequest("POST", formatV123StartAPIURL("/containers/create?name="+name), config, daemonHost()) + res, _, err := request.Post(formatV123StartAPIURL("/containers/create?name="+name), request.JSONBody(config)) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusCreated) + c.Assert(res.StatusCode, checker.Equals, http.StatusCreated) bindPath1 := RandomTmpDirPath("test1", testEnv.DaemonPlatform()) bindPath2 := RandomTmpDirPath("test2", testEnv.DaemonPlatform()) @@ -77,10 +82,14 @@ func (s *DockerSuite) TestDeprecatedContainerAPIStartDupVolumeBinds(c *check.C) config = map[string]interface{}{ "Binds": []string{bindPath1 + ":/tmp", bindPath2 + ":/tmp"}, } - status, body, err := request.SockRequest("POST", formatV123StartAPIURL("/containers/"+name+"/start"), config, daemonHost()) + res, body, err := request.Post(formatV123StartAPIURL("/containers/"+name+"/start"), request.JSONBody(config)) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusBadRequest) - c.Assert(string(body), checker.Contains, "Duplicate mount point", check.Commentf("Expected failure due to duplicate bind mounts to same path, instead got: %q with error: %v", string(body), err)) + + buf, err := request.ReadBody(body) + c.Assert(err, checker.IsNil) + + c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest) + c.Assert(string(buf), checker.Contains, "Duplicate mount point", check.Commentf("Expected failure due to duplicate bind mounts to same path, instead got: %q with error: %v", string(buf), err)) } func (s *DockerSuite) TestDeprecatedContainerAPIStartVolumesFrom(c *check.C) { @@ -97,16 +106,16 @@ func (s *DockerSuite) TestDeprecatedContainerAPIStartVolumesFrom(c *check.C) { "Volumes": map[string]struct{}{volPath: {}}, } - status, _, err := request.SockRequest("POST", formatV123StartAPIURL("/containers/create?name="+name), config, daemonHost()) + res, _, err := request.Post(formatV123StartAPIURL("/containers/create?name="+name), request.JSONBody(config)) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusCreated) + c.Assert(res.StatusCode, checker.Equals, http.StatusCreated) config = map[string]interface{}{ "VolumesFrom": []string{volName}, } - status, _, err = request.SockRequest("POST", formatV123StartAPIURL("/containers/"+name+"/start"), config, daemonHost()) + res, _, err = request.Post(formatV123StartAPIURL("/containers/"+name+"/start"), request.JSONBody(config)) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusNoContent) + c.Assert(res.StatusCode, checker.Equals, http.StatusNoContent) pth, err := inspectMountSourceField(name, volPath) c.Assert(err, checker.IsNil) @@ -127,9 +136,9 @@ func (s *DockerSuite) TestDeprecatedPostContainerBindNormalVolume(c *check.C) { dockerCmd(c, "create", "-v", "/foo", "--name=two", "busybox") bindSpec := map[string][]string{"Binds": {fooDir + ":/foo"}} - status, _, err := request.SockRequest("POST", formatV123StartAPIURL("/containers/two/start"), bindSpec, daemonHost()) + res, _, err := request.Post(formatV123StartAPIURL("/containers/two/start"), request.JSONBody(bindSpec)) c.Assert(err, checker.IsNil) - c.Assert(status, checker.Equals, http.StatusNoContent) + c.Assert(res.StatusCode, checker.Equals, http.StatusNoContent) fooDir2, err := inspectMountSourceField("two", "/foo") c.Assert(err, checker.IsNil) diff --git a/integration-cli/docker_deprecated_api_v124_unix_test.go b/integration-cli/docker_deprecated_api_v124_unix_test.go index 5fc6c2ddfc..20a8885908 100644 --- a/integration-cli/docker_deprecated_api_v124_unix_test.go +++ b/integration-cli/docker_deprecated_api_v124_unix_test.go @@ -22,7 +22,7 @@ func (s *DockerNetworkSuite) TestDeprecatedDockerNetworkStartAPIWithHostconfig(c "NetworkMode": netName, }, } - _, _, err := request.SockRequest("POST", formatV123StartAPIURL("/containers/"+conName+"/start"), config, daemonHost()) + _, _, err := request.Post(formatV123StartAPIURL("/containers/"+conName+"/start"), request.JSONBody(config)) c.Assert(err, checker.IsNil) c.Assert(waitRun(conName), checker.IsNil) networks := inspectField(c, conName, "NetworkSettings.Networks") diff --git a/integration-cli/docker_utils_test.go b/integration-cli/docker_utils_test.go index 0c0a164837..5ccc5b9c68 100644 --- a/integration-cli/docker_utils_test.go +++ b/integration-cli/docker_utils_test.go @@ -15,6 +15,7 @@ import ( "time" "github.com/docker/docker/api/types" + "github.com/docker/docker/client" "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/cli" "github.com/docker/docker/integration-cli/daemon" @@ -22,6 +23,7 @@ import ( "github.com/docker/docker/integration-cli/request" icmd "github.com/docker/docker/pkg/testutil/cmd" "github.com/go-check/check" + "golang.org/x/net/context" ) // Deprecated @@ -267,17 +269,12 @@ func daemonTime(c *check.C) time.Time { if testEnv.LocalDaemon() { return time.Now() } - - status, body, err := request.SockRequest("GET", "/info", nil, daemonHost()) + cli, err := client.NewEnvClient() c.Assert(err, check.IsNil) - c.Assert(status, check.Equals, http.StatusOK) + defer cli.Close() - type infoJSON struct { - SystemTime string - } - var info infoJSON - err = json.Unmarshal(body, &info) - c.Assert(err, check.IsNil, check.Commentf("unable to unmarshal GET /info response")) + info, err := cli.Info(context.Background()) + c.Assert(err, check.IsNil) dt, err := time.Parse(time.RFC3339Nano, info.SystemTime) c.Assert(err, check.IsNil, check.Commentf("invalid time format in GET /info response")) @@ -376,10 +373,12 @@ func waitInspectWithArgs(name, expr, expected string, timeout time.Duration, arg } func getInspectBody(c *check.C, version, id string) []byte { - endpoint := fmt.Sprintf("/%s/containers/%s/json", version, id) - status, body, err := request.SockRequest("GET", endpoint, nil, daemonHost()) + var httpClient *http.Client + cli, err := client.NewClient(daemonHost(), version, httpClient, nil) + c.Assert(err, check.IsNil) + defer cli.Close() + _, body, err := cli.ContainerInspectWithRaw(context.Background(), id, false) c.Assert(err, check.IsNil) - c.Assert(status, check.Equals, http.StatusOK) return body } @@ -406,20 +405,17 @@ func minimalBaseImage() string { } func getGoroutineNumber() (int, error) { - i := struct { - NGoroutines int - }{} - status, b, err := request.SockRequest("GET", "/info", nil, daemonHost()) + cli, err := client.NewEnvClient() if err != nil { return 0, err } - if status != http.StatusOK { - return 0, fmt.Errorf("http status code: %d", status) - } - if err := json.Unmarshal(b, &i); err != nil { + defer cli.Close() + + info, err := cli.Info(context.Background()) + if err != nil { return 0, err } - return i.NGoroutines, nil + return info.NGoroutines, nil } func waitForGoroutines(expected int) error { diff --git a/integration-cli/environment/clean.go b/integration-cli/environment/clean.go index 809baa7b52..2d4f32a979 100644 --- a/integration-cli/environment/clean.go +++ b/integration-cli/environment/clean.go @@ -1,16 +1,14 @@ package environment import ( - "encoding/json" - "fmt" - "net/http" "regexp" "strings" "github.com/docker/docker/api/types" - volumetypes "github.com/docker/docker/api/types/volume" - "github.com/docker/docker/integration-cli/request" + "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/client" icmd "github.com/docker/docker/pkg/testutil/cmd" + "golang.org/x/net/context" ) type testingT interface { @@ -26,15 +24,21 @@ type logT interface { // and removing everything else. It's meant to run after any tests so that they don't // depend on each others. func (e *Execution) Clean(t testingT, dockerBinary string) { + cli, err := client.NewEnvClient() + if err != nil { + t.Fatalf("%v", err) + } + defer cli.Close() + if (e.DaemonPlatform() != "windows") || (e.DaemonPlatform() == "windows" && e.Isolation() == "hyperv") { unpauseAllContainers(t, dockerBinary) } deleteAllContainers(t, dockerBinary) deleteAllImages(t, dockerBinary, e.protectedElements.images) - deleteAllVolumes(t, dockerBinary) - deleteAllNetworks(t, dockerBinary, e.DaemonPlatform()) + deleteAllVolumes(t, cli) + deleteAllNetworks(t, cli, e.DaemonPlatform()) if e.DaemonPlatform() == "linux" { - deleteAllPlugins(t, dockerBinary) + deleteAllPlugins(t, cli, dockerBinary) } } @@ -108,41 +112,34 @@ func deleteAllImages(t testingT, dockerBinary string, protectedImages map[string } } -func deleteAllVolumes(t testingT, dockerBinary string) { - volumes, err := getAllVolumes() +func deleteAllVolumes(t testingT, c client.APIClient) { + var errs []string + volumes, err := getAllVolumes(c) if err != nil { t.Fatalf("%v", err) } - var errs []string for _, v := range volumes { - status, b, err := request.SockRequest("DELETE", "/volumes/"+v.Name, nil, request.DaemonHost()) + err := c.VolumeRemove(context.Background(), v.Name, true) if err != nil { errs = append(errs, err.Error()) continue } - if status != http.StatusNoContent { - errs = append(errs, fmt.Sprintf("error deleting volume %s: %s", v.Name, string(b))) - } } if len(errs) > 0 { t.Fatalf("%v", strings.Join(errs, "\n")) } } -func getAllVolumes() ([]*types.Volume, error) { - var volumes volumetypes.VolumesListOKBody - _, b, err := request.SockRequest("GET", "/volumes", nil, request.DaemonHost()) +func getAllVolumes(c client.APIClient) ([]*types.Volume, error) { + volumes, err := c.VolumeList(context.Background(), filters.Args{}) if err != nil { return nil, err } - if err := json.Unmarshal(b, &volumes); err != nil { - return nil, err - } return volumes.Volumes, nil } -func deleteAllNetworks(t testingT, dockerBinary string, daemonPlatform string) { - networks, err := getAllNetworks() +func deleteAllNetworks(t testingT, c client.APIClient, daemonPlatform string) { + networks, err := getAllNetworks(c) if err != nil { t.Fatalf("%v", err) } @@ -155,62 +152,47 @@ func deleteAllNetworks(t testingT, dockerBinary string, daemonPlatform string) { // nat is a pre-defined network on Windows and cannot be removed continue } - status, b, err := request.SockRequest("DELETE", "/networks/"+n.Name, nil, request.DaemonHost()) + err := c.NetworkRemove(context.Background(), n.ID) if err != nil { errs = append(errs, err.Error()) continue } - if status != http.StatusNoContent { - errs = append(errs, fmt.Sprintf("error deleting network %s: %s", n.Name, string(b))) - } } if len(errs) > 0 { t.Fatalf("%v", strings.Join(errs, "\n")) } } -func getAllNetworks() ([]types.NetworkResource, error) { - var networks []types.NetworkResource - _, b, err := request.SockRequest("GET", "/networks", nil, request.DaemonHost()) +func getAllNetworks(c client.APIClient) ([]types.NetworkResource, error) { + networks, err := c.NetworkList(context.Background(), types.NetworkListOptions{}) if err != nil { return nil, err } - if err := json.Unmarshal(b, &networks); err != nil { - return nil, err - } return networks, nil } -func deleteAllPlugins(t testingT, dockerBinary string) { - plugins, err := getAllPlugins() +func deleteAllPlugins(t testingT, c client.APIClient, dockerBinary string) { + plugins, err := getAllPlugins(c) if err != nil { t.Fatalf("%v", err) } var errs []string for _, p := range plugins { - pluginName := p.Name - status, b, err := request.SockRequest("DELETE", "/plugins/"+pluginName+"?force=1", nil, request.DaemonHost()) + err := c.PluginRemove(context.Background(), p.Name, types.PluginRemoveOptions{Force: true}) if err != nil { errs = append(errs, err.Error()) continue } - if status != http.StatusOK { - errs = append(errs, fmt.Sprintf("error deleting plugin %s: %s", p.Name, string(b))) - } } if len(errs) > 0 { t.Fatalf("%v", strings.Join(errs, "\n")) } } -func getAllPlugins() (types.PluginsListResponse, error) { - var plugins types.PluginsListResponse - _, b, err := request.SockRequest("GET", "/plugins", nil, request.DaemonHost()) +func getAllPlugins(c client.APIClient) (types.PluginsListResponse, error) { + plugins, err := c.PluginList(context.Background(), filters.Args{}) if err != nil { return nil, err } - if err := json.Unmarshal(b, &plugins); err != nil { - return nil, err - } return plugins, nil }