Files
kubernetes/third_party/github.com/fsouza/go-dockerclient/container.go
2014-06-06 16:40:48 -07:00

584 lines
14 KiB
Go

// Copyright 2014 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package docker
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"strconv"
"strings"
"sync"
"time"
)
// ListContainersOptions specify parameters to the ListContainers function.
//
// See http://goo.gl/QpCnDN for more details.
type ListContainersOptions struct {
All bool
Size bool
Limit int
Since string
Before string
}
type APIPort struct {
PrivatePort int64
PublicPort int64
Type string
IP string
}
// APIContainers represents a container.
//
// See http://goo.gl/QeFH7U for more details.
type APIContainers struct {
ID string `json:"Id"`
Image string
Command string
Created int64
Status string
Ports []APIPort
SizeRw int64
SizeRootFs int64
Names []string
}
// ListContainers returns a slice of containers matching the given criteria.
//
// See http://goo.gl/QpCnDN for more details.
func (c *Client) ListContainers(opts ListContainersOptions) ([]APIContainers, error) {
path := "/containers/json?" + queryString(opts)
body, _, err := c.do("GET", path, nil)
if err != nil {
return nil, err
}
var containers []APIContainers
err = json.Unmarshal(body, &containers)
if err != nil {
return nil, err
}
return containers, nil
}
// Port represents the port number and the protocol, in the form
// <number>/<protocol>. For example: 80/tcp.
type Port string
// Port returns the number of the port.
func (p Port) Port() string {
return strings.Split(string(p), "/")[0]
}
// Proto returns the name of the protocol.
func (p Port) Proto() string {
parts := strings.Split(string(p), "/")
if len(parts) == 1 {
return "tcp"
}
return parts[1]
}
// State represents the state of a container.
type State struct {
sync.RWMutex
Running bool
Pid int
ExitCode int
StartedAt time.Time
FinishedAt time.Time
Ghost bool
}
// String returns the string representation of a state.
func (s *State) String() string {
s.RLock()
defer s.RUnlock()
if s.Running {
if s.Ghost {
return "Ghost"
}
return fmt.Sprintf("Up %s", time.Now().UTC().Sub(s.StartedAt))
}
return fmt.Sprintf("Exit %d", s.ExitCode)
}
type PortBinding struct {
HostIp string
HostPort string
}
type PortMapping map[string]string
type NetworkSettings struct {
IPAddress string
IPPrefixLen int
Gateway string
Bridge string
PortMapping map[string]PortMapping
Ports map[Port][]PortBinding
}
func (settings *NetworkSettings) PortMappingAPI() []APIPort {
var mapping []APIPort
for port, bindings := range settings.Ports {
p, _ := parsePort(port.Port())
if len(bindings) == 0 {
mapping = append(mapping, APIPort{
PublicPort: int64(p),
Type: port.Proto(),
})
continue
}
for _, binding := range bindings {
p, _ := parsePort(port.Port())
h, _ := parsePort(binding.HostPort)
mapping = append(mapping, APIPort{
PrivatePort: int64(p),
PublicPort: int64(h),
Type: port.Proto(),
IP: binding.HostIp,
})
}
}
return mapping
}
func parsePort(rawPort string) (int, error) {
port, err := strconv.ParseUint(rawPort, 10, 16)
if err != nil {
return 0, err
}
return int(port), nil
}
type Config struct {
Hostname string
Domainname string
User string
Memory int64
MemorySwap int64
CpuShares int64
AttachStdin bool
AttachStdout bool
AttachStderr bool
PortSpecs []string
ExposedPorts map[Port]struct{}
Tty bool
OpenStdin bool
StdinOnce bool
Env []string
Cmd []string
Dns []string // For Docker API v1.9 and below only
Image string
Volumes map[string]struct{}
VolumesFrom string
WorkingDir string
Entrypoint []string
NetworkDisabled bool
}
type Container struct {
ID string
Created time.Time
Path string
Args []string
Config *Config
State State
Image string
NetworkSettings *NetworkSettings
SysInitPath string
ResolvConfPath string
HostnamePath string
HostsPath string
Name string
Driver string
Volumes map[string]string
VolumesRW map[string]bool
HostConfig *HostConfig
}
// InspectContainer returns information about a container by its ID.
//
// See http://goo.gl/2o52Sx for more details.
func (c *Client) InspectContainer(id string) (*Container, error) {
path := "/containers/" + id + "/json"
body, status, err := c.do("GET", path, nil)
if status == http.StatusNotFound {
return nil, &NoSuchContainer{ID: id}
}
if err != nil {
return nil, err
}
var container Container
err = json.Unmarshal(body, &container)
if err != nil {
return nil, err
}
return &container, nil
}
// ContainerChanges returns changes in the filesystem of the given container.
//
// See http://goo.gl/DpGyzK for more details.
func (c *Client) ContainerChanges(id string) ([]Change, error) {
path := "/containers/" + id + "/changes"
body, status, err := c.do("GET", path, nil)
if status == http.StatusNotFound {
return nil, &NoSuchContainer{ID: id}
}
if err != nil {
return nil, err
}
var changes []Change
err = json.Unmarshal(body, &changes)
if err != nil {
return nil, err
}
return changes, nil
}
// CreateContainerOptions specify parameters to the CreateContainer function.
//
// See http://goo.gl/WPPYtB for more details.
type CreateContainerOptions struct {
Name string
Config *Config `qs:"-"`
}
// CreateContainer creates a new container, returning the container instance,
// or an error in case of failure.
//
// See http://goo.gl/tjihUc for more details.
func (c *Client) CreateContainer(opts CreateContainerOptions) (*Container, error) {
path := "/containers/create?" + queryString(opts)
body, status, err := c.do("POST", path, opts.Config)
if status == http.StatusNotFound {
return nil, ErrNoSuchImage
}
if err != nil {
return nil, err
}
var container Container
err = json.Unmarshal(body, &container)
if err != nil {
return nil, err
}
container.Name = opts.Name
return &container, nil
}
type KeyValuePair struct {
Key string
Value string
}
type HostConfig struct {
Binds []string
ContainerIDFile string
LxcConf []KeyValuePair
Privileged bool
PortBindings map[Port][]PortBinding
Links []string
PublishAllPorts bool
Dns []string // For Docker API v1.10 and above only
}
// StartContainer starts a container, returning an errror in case of failure.
//
// See http://goo.gl/y5GZlE for more details.
func (c *Client) StartContainer(id string, hostConfig *HostConfig) error {
if hostConfig == nil {
hostConfig = &HostConfig{}
}
path := "/containers/" + id + "/start"
_, status, err := c.do("POST", path, hostConfig)
if status == http.StatusNotFound {
return &NoSuchContainer{ID: id}
}
if err != nil {
return err
}
return nil
}
// StopContainer stops a container, killing it after the given timeout (in
// seconds).
//
// See http://goo.gl/X2mj8t for more details.
func (c *Client) StopContainer(id string, timeout uint) error {
path := fmt.Sprintf("/containers/%s/stop?t=%d", id, timeout)
_, status, err := c.do("POST", path, nil)
if status == http.StatusNotFound {
return &NoSuchContainer{ID: id}
}
if err != nil {
return err
}
return nil
}
// RestartContainer stops a container, killing it after the given timeout (in
// seconds), during the stop process.
//
// See http://goo.gl/zms73Z for more details.
func (c *Client) RestartContainer(id string, timeout uint) error {
path := fmt.Sprintf("/containers/%s/restart?t=%d", id, timeout)
_, status, err := c.do("POST", path, nil)
if status == http.StatusNotFound {
return &NoSuchContainer{ID: id}
}
if err != nil {
return err
}
return nil
}
// KillContainerOptions represents the set of options that can be used in a
// call to KillContainer.
type KillContainerOptions struct {
// The ID of the container.
ID string `qs:"-"`
// The signal to send to the container. When omitted, Docker server
// will assume SIGKILL.
Signal Signal
}
// KillContainer kills a container, returning an error in case of failure.
//
// See http://goo.gl/DPbbBy for more details.
func (c *Client) KillContainer(opts KillContainerOptions) error {
path := "/containers/" + opts.ID + "/kill" + "?" + queryString(opts)
_, status, err := c.do("POST", path, nil)
if status == http.StatusNotFound {
return &NoSuchContainer{ID: opts.ID}
}
if err != nil {
return err
}
return nil
}
// RemoveContainerOptions encapsulates options to remove a container.
type RemoveContainerOptions struct {
// The ID of the container.
ID string `qs:"-"`
// A flag that indicates whether Docker should remove the volumes
// associated to the container.
RemoveVolumes bool `qs:"v"`
// A flag that indicates whether Docker should remove the container
// even if it is currently running.
Force bool
}
// RemoveContainer removes a container, returning an error in case of failure.
//
// See http://goo.gl/PBvGdU for more details.
func (c *Client) RemoveContainer(opts RemoveContainerOptions) error {
path := "/containers/" + opts.ID + "?" + queryString(opts)
_, status, err := c.do("DELETE", path, nil)
if status == http.StatusNotFound {
return &NoSuchContainer{ID: opts.ID}
}
if err != nil {
return err
}
return nil
}
// CopyFromContainerOptions is the set of options that can be used when copying
// files or folders from a container.
//
// See http://goo.gl/mnxRMl for more details.
type CopyFromContainerOptions struct {
OutputStream io.Writer `json:"-"`
Container string `json:"-"`
Resource string
}
// CopyFromContainer copy files or folders from a container, using a given
// resource.
//
// See http://goo.gl/mnxRMl for more details.
func (c *Client) CopyFromContainer(opts CopyFromContainerOptions) error {
if opts.Container == "" {
return &NoSuchContainer{ID: opts.Container}
}
url := fmt.Sprintf("/containers/%s/copy", opts.Container)
body, status, err := c.do("POST", url, opts)
if status == http.StatusNotFound {
return &NoSuchContainer{ID: opts.Container}
}
if err != nil {
return err
}
io.Copy(opts.OutputStream, bytes.NewBuffer(body))
return nil
}
// WaitContainer blocks until the given container stops, return the exit code
// of the container status.
//
// See http://goo.gl/gnHJL2 for more details.
func (c *Client) WaitContainer(id string) (int, error) {
body, status, err := c.do("POST", "/containers/"+id+"/wait", nil)
if status == http.StatusNotFound {
return 0, &NoSuchContainer{ID: id}
}
if err != nil {
return 0, err
}
var r struct{ StatusCode int }
err = json.Unmarshal(body, &r)
if err != nil {
return 0, err
}
return r.StatusCode, nil
}
// CommitContainerOptions aggregates parameters to the CommitContainer method.
//
// See http://goo.gl/628gxm for more details.
type CommitContainerOptions struct {
Container string
Repository string `qs:"repo"`
Tag string
Message string `qs:"m"`
Author string
Run *Config `qs:"-"`
}
type Image struct {
ID string `json:"id"`
Parent string `json:"parent,omitempty"`
Comment string `json:"comment,omitempty"`
Created time.Time `json:"created"`
Container string `json:"container,omitempty"`
ContainerConfig Config `json:"container_config,omitempty"`
DockerVersion string `json:"docker_version,omitempty"`
Author string `json:"author,omitempty"`
Config *Config `json:"config,omitempty"`
Architecture string `json:"architecture,omitempty"`
Size int64
}
// CommitContainer creates a new image from a container's changes.
//
// See http://goo.gl/628gxm for more details.
func (c *Client) CommitContainer(opts CommitContainerOptions) (*Image, error) {
path := "/commit?" + queryString(opts)
body, status, err := c.do("POST", path, opts.Run)
if status == http.StatusNotFound {
return nil, &NoSuchContainer{ID: opts.Container}
}
if err != nil {
return nil, err
}
var image Image
err = json.Unmarshal(body, &image)
if err != nil {
return nil, err
}
return &image, nil
}
// AttachToContainerOptions is the set of options that can be used when
// attaching to a container.
//
// See http://goo.gl/oPzcqH for more details.
type AttachToContainerOptions struct {
Container string `qs:"-"`
InputStream io.Reader `qs:"-"`
OutputStream io.Writer `qs:"-"`
ErrorStream io.Writer `qs:"-"`
// Get container logs, sending it to OutputStream.
Logs bool
// Stream the response?
Stream bool
// Attach to stdin, and use InputFile.
Stdin bool
// Attach to stdout, and use OutputStream.
Stdout bool
// Attach to stderr, and use ErrorStream.
Stderr bool
// If set, after a successful connect, a sentinel will be sent and then the
// client will block on receive before continuing.
//
// It must be an unbuffered channel. Using a buffered channel can lead
// to unexpected behavior.
Success chan struct{}
}
// AttachToContainer attaches to a container, using the given options.
//
// See http://goo.gl/oPzcqH for more details.
func (c *Client) AttachToContainer(opts AttachToContainerOptions) error {
if opts.Container == "" {
return &NoSuchContainer{ID: opts.Container}
}
path := "/containers/" + opts.Container + "/attach?" + queryString(opts)
return c.hijack("POST", path, opts.Success, opts.InputStream, opts.ErrorStream, opts.OutputStream)
}
// ResizeContainerTTY resizes the terminal to the given height and width.
func (c *Client) ResizeContainerTTY(id string, height, width int) error {
params := make(url.Values)
params.Set("h", strconv.Itoa(height))
params.Set("w", strconv.Itoa(width))
_, _, err := c.do("POST", "/containers/"+id+"/resize?"+params.Encode(), nil)
return err
}
// ExportContainerOptions is the set of parameters to the ExportContainer
// method.
//
// See http://goo.gl/Lqk0FZ for more details.
type ExportContainerOptions struct {
ID string
OutputStream io.Writer
}
// ExportContainer export the contents of container id as tar archive
// and prints the exported contents to stdout.
//
// See http://goo.gl/Lqk0FZ for more details.
func (c *Client) ExportContainer(opts ExportContainerOptions) error {
if opts.ID == "" {
return NoSuchContainer{ID: opts.ID}
}
url := fmt.Sprintf("/containers/%s/export", opts.ID)
return c.stream("GET", url, nil, nil, opts.OutputStream)
}
// NoSuchContainer is the error returned when a given container does not exist.
type NoSuchContainer struct {
ID string
}
func (err NoSuchContainer) Error() string {
return "No such container: " + err.ID
}