diff --git a/api/handlers.go b/api/handlers.go index d39bf3d7ea..66a70e18bc 100644 --- a/api/handlers.go +++ b/api/handlers.go @@ -394,7 +394,7 @@ func getContainersJSON(c *context, w http.ResponseWriter, r *http.Request) { if !filters.MatchKVList("label", container.Config.Labels) { continue } - if !filters.Match("status", container.Info.State.StateString()) { + if !filters.Match("status", cluster.StateString(container.Info.State)) { continue } if !filters.Match("node", container.Engine.Name) { @@ -423,8 +423,8 @@ func getContainersJSON(c *context, w http.ResponseWriter, r *http.Request) { candidates = candidates[:limit] } - // Convert cluster.Container back into dockerclient.Container. - out := []*dockerclient.Container{} + // Convert cluster.Container back into apitypes.Container. + out := []*apitypes.Container{} for _, container := range candidates { if before != nil { if container.ID == before.ID { @@ -432,13 +432,13 @@ func getContainersJSON(c *context, w http.ResponseWriter, r *http.Request) { } continue } - // Create a copy of the underlying dockerclient.Container so we can + // Create a copy of the underlying apitypes.Container so we can // make changes without messing with cluster.Container. tmp := (*container).Container // Update the Status. The one we have is stale from the last `docker ps` the engine sent. // `Status()` will generate a new one - tmp.Status = container.Info.State.String() + tmp.Status = cluster.FullStateString(container.Info.State) if !container.Engine.IsHealthy() { tmp.Status = "Host Down" } @@ -455,7 +455,7 @@ func getContainersJSON(c *context, w http.ResponseWriter, r *http.Request) { } // insert node IP - tmp.Ports = make([]dockerclient.Port, len(container.Ports)) + tmp.Ports = make([]apitypes.Port, len(container.Ports)) for i, port := range container.Ports { tmp.Ports[i] = port if port.IP == "0.0.0.0" { @@ -526,15 +526,13 @@ func getContainerJSON(c *context, w http.ResponseWriter, r *http.Request) { func postContainersCreate(c *context, w http.ResponseWriter, r *http.Request) { r.ParseForm() var ( - oldConfig = dockerclient.ContainerConfig{ - HostConfig: dockerclient.HostConfig{ - MemorySwappiness: -1, - }, - } - name = r.Form.Get("name") - config = cluster.ContainerConfig{ + defaultMemorySwappiness = int64(-1) + name = r.Form.Get("name") + config = cluster.ContainerConfig{ HostConfig: containertypes.HostConfig{ - MemorySwappiness: -1, + Resources: containertypes.Resources{ + MemorySwappiness: &(defaultMemorySwappiness), + }, }, } ) diff --git a/cluster/cluster.go b/cluster/cluster.go index aa13d15965..b97a6940c2 100644 --- a/cluster/cluster.go +++ b/cluster/cluster.go @@ -10,7 +10,7 @@ import ( // Cluster is exported type Cluster interface { // Create a container - CreateContainer(config *ContainerConfig, name string, authConfig *dockerclient.AuthConfig) (*Container, error) + CreateContainer(config *ContainerConfig, name string, authConfig *types.AuthConfig) (*Container, error) // Remove a container RemoveContainer(container *Container, force, volumes bool) error diff --git a/cluster/container.go b/cluster/container.go index 645f63a805..2c5984f851 100644 --- a/cluster/container.go +++ b/cluster/container.go @@ -1,10 +1,13 @@ package cluster import ( + "fmt" "strings" + "time" "github.com/docker/docker/pkg/stringid" "github.com/docker/engine-api/types" + "github.com/docker/go-units" ) // Container is exported @@ -16,6 +19,50 @@ type Container struct { Engine *Engine } +// StateString returns a single string to describe state +func StateString(state *types.ContainerState) string { + if state.Running { + if state.Paused { + return "paused" + } + if state.Restarting { + return "restarting" + } + return "running" + } + + if state.Dead { + return "dead" + } + + return "exited" +} + +// FullStateString returns human-readable description of the state +func FullStateString(state *types.ContainerState) string { + startedAt, _ := time.Parse(time.RFC3339Nano, state.StartedAt) + finishedAt, _ := time.Parse(time.RFC3339Nano, state.FinishedAt) + if state.Running { + if state.Paused { + return fmt.Sprintf("Up %s (Paused)", units.HumanDuration(time.Now().UTC().Sub(startedAt))) + } + if state.Restarting { + return fmt.Sprintf("Restarting (%d) %s ago", state.ExitCode, units.HumanDuration(time.Now().UTC().Sub(finishedAt))) + } + return fmt.Sprintf("Up %s", units.HumanDuration(time.Now().UTC().Sub(startedAt))) + } + + if state.Dead { + return "Dead" + } + + if finishedAt.IsZero() { + return "" + } + + return fmt.Sprintf("Exited (%d) %s ago", state.ExitCode, units.HumanDuration(time.Now().UTC().Sub(finishedAt))) +} + // Refresh container func (c *Container) Refresh() (*Container, error) { return c.Engine.refreshContainer(c.ID, true) diff --git a/cluster/engine.go b/cluster/engine.go index 5e235da3b9..70c3a9a649 100644 --- a/cluster/engine.go +++ b/cluster/engine.go @@ -632,7 +632,7 @@ func (e *Engine) RefreshContainers(full bool) error { All: true, Size: false, } - containers, err := e.apiClient.ContainerList(opts) + containers, err := e.apiClient.ContainerList(context.TODO(), opts) e.CheckConnectionErr(err) if err != nil { return err @@ -665,7 +665,7 @@ func (e *Engine) refreshContainer(ID string, full bool) (*Container, error) { Size: false, Filter: filterArgs, } - containers, err := e.apiClient.ContainerList(opts) + containers, err := e.apiClient.ContainerList(context.TODO(), opts) e.CheckConnectionErr(err) if err != nil { return nil, err @@ -720,7 +720,7 @@ func (e *Engine) updateContainer(c types.Container, containers map[string]*Conta // Update ContainerInfo. if full { - info, err := e.apiClient.ContainerInspect(c.ID) + info, err := e.apiClient.ContainerInspect(context.TODO(), c.ID) e.CheckConnectionErr(err) if err != nil { return nil, err @@ -858,7 +858,7 @@ func (e *Engine) TotalCpus() int { } // Create a new container -func (e *Engine) Create(config *ContainerConfig, name string, pullImage bool, authConfig *dockerclient.AuthConfig) (*Container, error) { +func (e *Engine) Create(config *ContainerConfig, name string, pullImage bool, authConfig *types.AuthConfig) (*Container, error) { var ( err error createResp types.ContainerCreateResponse @@ -874,7 +874,7 @@ func (e *Engine) Create(config *ContainerConfig, name string, pullImage bool, au // FIXME remove "duplicate" lines and move this to cluster/config.go dockerConfig.CPUShares = int64(math.Ceil(float64(config.CPUShares*1024) / float64(e.Cpus))) - createResp, err = e.apiClient.ContainerCreate(&dockerConfig.Config, &dockerConfig.HostConfig, &dockerConfig.NetworkingConfig, name) + createResp, err = e.apiClient.ContainerCreate(context.TODO(), &dockerConfig.Config, &dockerConfig.HostConfig, &dockerConfig.NetworkingConfig, name) e.CheckConnectionErr(err) if err != nil { // If the error is other than not found, abort immediately. @@ -886,7 +886,7 @@ func (e *Engine) Create(config *ContainerConfig, name string, pullImage bool, au return nil, err } // ...And try again. - createResp, err = e.apiClient.ContainerCreate(&dockerConfig.Config, &dockerConfig.HostConfig, &dockerConfig.NetworkingConfig, name) + createResp, err = e.apiClient.ContainerCreate(context.TODO(), &dockerConfig.Config, &dockerConfig.HostConfig, &dockerConfig.NetworkingConfig, name) e.CheckConnectionErr(err) if err != nil { return nil, err @@ -951,11 +951,14 @@ func (e *Engine) CreateVolume(request *types.VolumeCreateRequest) (*Volume, erro } // Pull an image on the engine -func (e *Engine) Pull(image string, authConfig *dockerclient.AuthConfig) error { +func (e *Engine) Pull(image string, authConfig *types.AuthConfig) error { if !strings.Contains(image, ":") { image = image + ":latest" } - err := e.client.PullImage(image, authConfig) + pullOpts := types.ImagePullOptions{ + ImageID: image, + } + _, err := e.apiClient.ImagePull(context.TODO(), pullOpts, nil) e.CheckConnectionErr(err) if err != nil { return err diff --git a/cluster/mesos/task/task.go b/cluster/mesos/task/task.go index 7c28fc659e..3131f3e2ce 100644 --- a/cluster/mesos/task/task.go +++ b/cluster/mesos/task/task.go @@ -91,7 +91,7 @@ func (t *Task) Build(slaveID string, offers map[string]*mesosproto.Offer) { for containerProtoPort, bindings := range t.config.HostConfig.PortBindings { for _, binding := range bindings { - containerInfo := strings.SplitN(containerProtoPort, "/", 2) + containerInfo := strings.SplitN(string(containerProtoPort), "/", 2) containerPort, err := strconv.ParseUint(containerInfo[0], 10, 32) if err != nil { log.Warn(err) @@ -135,7 +135,7 @@ func (t *Task) Build(slaveID string, offers map[string]*mesosproto.Offer) { t.Container.Docker.Network = mesosproto.ContainerInfo_DockerInfo_BRIDGE.Enum() } - if cpus := t.config.CpuShares; cpus > 0 { + if cpus := t.config.CPUShares; cpus > 0 { t.Resources = append(t.Resources, mesosutil.NewScalarResource("cpus", float64(cpus))) } diff --git a/cluster/swarm/cluster.go b/cluster/swarm/cluster.go index bf70436767..f0844837e9 100644 --- a/cluster/swarm/cluster.go +++ b/cluster/swarm/cluster.go @@ -138,7 +138,7 @@ func (c *Cluster) StartContainer(container *cluster.Container, hostConfig *docke } // CreateContainer aka schedule a brand new container into the cluster. -func (c *Cluster) CreateContainer(config *cluster.ContainerConfig, name string, authConfig *dockerclient.AuthConfig) (*cluster.Container, error) { +func (c *Cluster) CreateContainer(config *cluster.ContainerConfig, name string, authConfig *types.AuthConfig) (*cluster.Container, error) { container, err := c.createContainer(config, name, false, authConfig) if err != nil { @@ -162,7 +162,7 @@ func (c *Cluster) CreateContainer(config *cluster.ContainerConfig, name string, return container, err } -func (c *Cluster) createContainer(config *cluster.ContainerConfig, name string, withImageAffinity bool, authConfig *dockerclient.AuthConfig) (*cluster.Container, error) { +func (c *Cluster) createContainer(config *cluster.ContainerConfig, name string, withImageAffinity bool, authConfig *types.AuthConfig) (*cluster.Container, error) { c.scheduler.Lock() // Ensure the name is available