First commit
This commit is contained in:
583
third_party/github.com/fsouza/go-dockerclient/container.go
vendored
Normal file
583
third_party/github.com/fsouza/go-dockerclient/container.go
vendored
Normal file
@@ -0,0 +1,583 @@
|
||||
// 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
|
||||
}
|
Reference in New Issue
Block a user