api/v1beta1: use go-dockerclient instead of docker-api-structs

This involves updating go-dockerclient and removing the patched code.

Related to #692 and fsouza/go-dockerclient#146.
This commit is contained in:
Francisco Souza 2014-09-05 17:31:13 -03:00
parent ee1c0838d8
commit 6d0f84c700
17 changed files with 389 additions and 273 deletions

4
Godeps/Godeps.json generated
View File

@ -47,8 +47,8 @@
}, },
{ {
"ImportPath": "github.com/fsouza/go-dockerclient", "ImportPath": "github.com/fsouza/go-dockerclient",
"Comment": "0.2.1-216-g9061c85", "Comment": "0.2.1-241-g0dbb508",
"Rev": "9061c8580ba4374f24de44bcf9e8b77ce0553933" "Rev": "0dbb508e94dd899a6743d035d8f249c7634d26da"
}, },
{ {
"ImportPath": "github.com/golang/glog", "ImportPath": "github.com/golang/glog",

View File

@ -2,7 +2,7 @@ language: go
go: go:
- 1.1.2 - 1.1.2
- 1.2 - 1.2
- 1.3 - 1.3.1
- tip - tip
env: env:
- GOARCH=amd64 - GOARCH=amd64

View File

@ -1,5 +1,6 @@
# This is the official list of go-dockerclient authors for copyright purposes. # This is the official list of go-dockerclient authors for copyright purposes.
Aldrin Leal <aldrin@leal.eng.br>
Andreas Jaekle <andreas@jaekle.net> Andreas Jaekle <andreas@jaekle.net>
Andrews Medina <andrewsmedina@gmail.com> Andrews Medina <andrewsmedina@gmail.com>
Andy Goldstein <andy.goldstein@redhat.com> Andy Goldstein <andy.goldstein@redhat.com>
@ -7,6 +8,8 @@ Ben McCann <benmccann.com>
Cezar Sa Espinola <cezar.sa@corp.globo.com> Cezar Sa Espinola <cezar.sa@corp.globo.com>
Cheah Chu Yeow <chuyeow@gmail.com> Cheah Chu Yeow <chuyeow@gmail.com>
cheneydeng <cheneydeng@qq.com> cheneydeng <cheneydeng@qq.com>
Daniel, Dao Quang Minh <dqminh89@gmail.com>
David Huie <dahuie@gmail.com>
Ed <edrocksit@gmail.com> Ed <edrocksit@gmail.com>
Eric Anderson <anderson@copperegg.com> Eric Anderson <anderson@copperegg.com>
Fabio Rehm <fgrehm@gmail.com> Fabio Rehm <fgrehm@gmail.com>
@ -19,6 +22,7 @@ Jeff Mitchell <jeffrey.mitchell@gmail.com>
Jeffrey Hulten <jhulten@gmail.com> Jeffrey Hulten <jhulten@gmail.com>
Johan Euphrosine <proppy@google.com> Johan Euphrosine <proppy@google.com>
Karan Misra <kidoman@gmail.com> Karan Misra <kidoman@gmail.com>
Kim, Hirokuni <hirokuni.kim@kvh.co.jp>
Lucas Clemente <lucas@clemente.io> Lucas Clemente <lucas@clemente.io>
Omeid Matten <public@omeid.me> Omeid Matten <public@omeid.me>
Paul Morie <pmorie@gmail.com> Paul Morie <pmorie@gmail.com>

View File

@ -264,7 +264,7 @@ func (c *Client) do(method, path string, data interface{}) ([]byte, int, error)
return body, resp.StatusCode, nil return body, resp.StatusCode, nil
} }
func (c *Client) stream(method, path string, setRawTerminal bool, headers map[string]string, in io.Reader, stdout, stderr io.Writer) error { func (c *Client) stream(method, path string, setRawTerminal, rawJSONStream bool, headers map[string]string, in io.Reader, stdout, stderr io.Writer) error {
if (method == "POST" || method == "PUT") && in == nil { if (method == "POST" || method == "PUT") && in == nil {
in = bytes.NewReader(nil) in = bytes.NewReader(nil)
} }
@ -320,6 +320,12 @@ func (c *Client) stream(method, path string, setRawTerminal bool, headers map[st
return newError(resp.StatusCode, body) return newError(resp.StatusCode, body)
} }
if resp.Header.Get("Content-Type") == "application/json" { if resp.Header.Get("Content-Type") == "application/json" {
// if we want to get raw json stream, just copy it back to output
// without decoding it
if rawJSONStream {
_, err = io.Copy(stdout, resp.Body)
return err
}
dec := json.NewDecoder(resp.Body) dec := json.NewDecoder(resp.Body)
for { for {
var m jsonMessage var m jsonMessage

View File

@ -248,16 +248,22 @@ func TestPingFailingWrongStatus(t *testing.T) {
type FakeRoundTripper struct { type FakeRoundTripper struct {
message string message string
status int status int
header map[string]string
requests []*http.Request requests []*http.Request
} }
func (rt *FakeRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) { func (rt *FakeRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
body := strings.NewReader(rt.message) body := strings.NewReader(rt.message)
rt.requests = append(rt.requests, r) rt.requests = append(rt.requests, r)
return &http.Response{ res := &http.Response{
StatusCode: rt.status, StatusCode: rt.status,
Body: ioutil.NopCloser(body), Body: ioutil.NopCloser(body),
}, nil Header: make(http.Header),
}
for k, v := range rt.header {
res.Header.Set(k, v)
}
return res, nil
} }
func (rt *FakeRoundTripper) Reset() { func (rt *FakeRoundTripper) Reset() {

View File

@ -28,25 +28,25 @@ type ListContainersOptions struct {
} }
type APIPort struct { type APIPort struct {
PrivatePort int64 PrivatePort int64 `json:"PrivatePort,omitempty" yaml:"PrivatePort,omitempty"`
PublicPort int64 PublicPort int64 `json:"PublicPort,omitempty" yaml:"PublicPort,omitempty"`
Type string Type string `json:"Type,omitempty" yaml:"Type,omitempty"`
IP string IP string `json:"IP,omitempty" yaml:"IP,omitempty"`
} }
// APIContainers represents a container. // APIContainers represents a container.
// //
// See http://goo.gl/QeFH7U for more details. // See http://goo.gl/QeFH7U for more details.
type APIContainers struct { type APIContainers struct {
ID string `json:"Id"` ID string `json:"Id" yaml:"Id"`
Image string Image string `json:"Image,omitempty" yaml:"Image,omitempty"`
Command string Command string `json:"Command,omitempty" yaml:"Command,omitempty"`
Created int64 Created int64 `json:"Created,omitempty" yaml:"Created,omitempty"`
Status string Status string `json:"Status,omitempty" yaml:"Status,omitempty"`
Ports []APIPort Ports []APIPort `json:"Ports,omitempty" yaml:"Ports,omitempty"`
SizeRw int64 SizeRw int64 `json:"SizeRw,omitempty" yaml:"SizeRw,omitempty"`
SizeRootFs int64 SizeRootFs int64 `json:"SizeRootFs,omitempty" yaml:"SizeRootFs,omitempty"`
Names []string Names []string `json:"Names,omitempty" yaml:"Names,omitempty"`
} }
// ListContainers returns a slice of containers matching the given criteria. // ListContainers returns a slice of containers matching the given criteria.
@ -86,12 +86,12 @@ func (p Port) Proto() string {
// State represents the state of a container. // State represents the state of a container.
type State struct { type State struct {
Running bool Running bool `json:"Running,omitempty" yaml:"Running,omitempty"`
Paused bool Paused bool `json:"Paused,omitempty" yaml:"Paused,omitempty"`
Pid int Pid int `json:"Pid,omitempty" yaml:"Pid,omitempty"`
ExitCode int ExitCode int `json:"ExitCode,omitempty" yaml:"ExitCode,omitempty"`
StartedAt time.Time StartedAt time.Time `json:"StartedAt,omitempty" yaml:"StartedAt,omitempty"`
FinishedAt time.Time FinishedAt time.Time `json:"FinishedAt,omitempty" yaml:"FinishedAt,omitempty"`
} }
// String returns the string representation of a state. // String returns the string representation of a state.
@ -106,19 +106,19 @@ func (s *State) String() string {
} }
type PortBinding struct { type PortBinding struct {
HostIp string HostIp string `json:"HostIP,omitempty" yaml:"HostIP,omitempty"`
HostPort string HostPort string `json:"HostPort,omitempty" yaml:"HostPort,omitempty"`
} }
type PortMapping map[string]string type PortMapping map[string]string
type NetworkSettings struct { type NetworkSettings struct {
IPAddress string IPAddress string `json:"IPAddress,omitempty" yaml:"IPAddress,omitempty"`
IPPrefixLen int IPPrefixLen int `json:"IPPrefixLen,omitempty" yaml:"IPPrefixLen,omitempty"`
Gateway string Gateway string `json:"Gateway,omitempty" yaml:"Gateway,omitempty"`
Bridge string Bridge string `json:"Bridge,omitempty" yaml:"Bridge,omitempty"`
PortMapping map[string]PortMapping PortMapping map[string]PortMapping `json:"PortMapping,omitempty" yaml:"PortMapping,omitempty"`
Ports map[Port][]PortBinding Ports map[Port][]PortBinding `json:"Ports,omitempty" yaml:"Ports,omitempty"`
} }
func (settings *NetworkSettings) PortMappingAPI() []APIPort { func (settings *NetworkSettings) PortMappingAPI() []APIPort {
@ -155,55 +155,55 @@ func parsePort(rawPort string) (int, error) {
} }
type Config struct { type Config struct {
Hostname string Hostname string `json:"Hostname,omitempty" yaml:"Hostname,omitempty"`
Domainname string Domainname string `json:"Domainname,omitempty" yaml:"Domainname,omitempty"`
User string User string `json:"User,omitempty" yaml:"User,omitempty"`
Memory int64 Memory int64 `json:"Memory,omitempty" yaml:"Memory,omitempty"`
MemorySwap int64 MemorySwap int64 `json:"MemorySwap,omitempty" yaml:"MemorySwap,omitempty"`
CpuShares int64 CpuShares int64 `json:"CpuShares,omitempty" yaml:"CpuShares,omitempty"`
AttachStdin bool AttachStdin bool `json:"AttachStdin,omitempty" yaml:"AttachStdin,omitempty"`
AttachStdout bool AttachStdout bool `json:"AttachStdout,omitempty" yaml:"AttachStdout,omitempty"`
AttachStderr bool AttachStderr bool `json:"AttachStderr,omitempty" yaml:"AttachStderr,omitempty"`
PortSpecs []string PortSpecs []string `json:"PortSpecs,omitempty" yaml:"PortSpecs,omitempty"`
ExposedPorts map[Port]struct{} ExposedPorts map[Port]struct{} `json:"ExposedPorts,omitempty" yaml:"ExposedPorts,omitempty"`
Tty bool Tty bool `json:"Tty,omitempty" yaml:"Tty,omitempty"`
OpenStdin bool OpenStdin bool `json:"OpenStdin,omitempty" yaml:"OpenStdin,omitempty"`
StdinOnce bool StdinOnce bool `json:"StdinOnce,omitempty" yaml:"StdinOnce,omitempty"`
Env []string Env []string `json:"Env,omitempty" yaml:"Env,omitempty"`
Cmd []string Cmd []string `json:"Cmd,omitempty" yaml:"Cmd,omitempty"`
Dns []string // For Docker API v1.9 and below only Dns []string `json:"Dns,omitempty" yaml:"Dns,omitempty"` // For Docker API v1.9 and below only
Image string Image string `json:"Image,omitempty" yaml:"Image,omitempty"`
Volumes map[string]struct{} Volumes map[string]struct{} `json:"Volumes,omitempty" yaml:"Volumes,omitempty"`
VolumesFrom string VolumesFrom string `json:"VolumesFrom,omitempty" yaml:"VolumesFrom,omitempty"`
WorkingDir string WorkingDir string `json:"WorkingDir,omitempty" yaml:"WorkingDir,omitempty"`
Entrypoint []string Entrypoint []string `json:"Entrypoint,omitempty" yaml:"Entrypoint,omitempty"`
NetworkDisabled bool NetworkDisabled bool `json:"NetworkDisabled,omitempty" yaml:"NetworkDisabled,omitempty"`
} }
type Container struct { type Container struct {
ID string ID string `json:"Id" yaml:"Id"`
Created time.Time Created time.Time `json:"Created,omitempty" yaml:"Created,omitempty"`
Path string Path string `json:"Path,omitempty" yaml:"Path,omitempty"`
Args []string Args []string `json:"Args,omitempty" yaml:"Args,omitempty"`
Config *Config Config *Config `json:"Config,omitempty" yaml:"Config,omitempty"`
State State State State `json:"State,omitempty" yaml:"State,omitempty"`
Image string Image string `json:"Image,omitempty" yaml:"Image,omitempty"`
NetworkSettings *NetworkSettings NetworkSettings *NetworkSettings `json:"NetworkSettings,omitempty" yaml:"NetworkSettings,omitempty"`
SysInitPath string SysInitPath string `json:"SysInitPath,omitempty" yaml:"SysInitPath,omitempty"`
ResolvConfPath string ResolvConfPath string `json:"ResolvConfPath,omitempty" yaml:"ResolvConfPath,omitempty"`
HostnamePath string HostnamePath string `json:"HostnamePath,omitempty" yaml:"HostnamePath,omitempty"`
HostsPath string HostsPath string `json:"HostsPath,omitempty" yaml:"HostsPath,omitempty"`
Name string Name string `json:"Name,omitempty" yaml:"Name,omitempty"`
Driver string Driver string `json:"Driver,omitempty" yaml:"Driver,omitempty"`
Volumes map[string]string Volumes map[string]string `json:"Volumes,omitempty" yaml:"Volumes,omitempty"`
VolumesRW map[string]bool VolumesRW map[string]bool `json:"VolumesRW,omitempty" yaml:"VolumesRW,omitempty"`
HostConfig *HostConfig HostConfig *HostConfig `json:"HostConfig,omitempty" yaml:"HostConfig,omitempty"`
} }
// InspectContainer returns information about a container by its ID. // InspectContainer returns information about a container by its ID.
@ -279,22 +279,56 @@ func (c *Client) CreateContainer(opts CreateContainerOptions) (*Container, error
} }
type KeyValuePair struct { type KeyValuePair struct {
Key string Key string `json:"Key,omitempty" yaml:"Key,omitempty"`
Value string Value string `json:"Value,omitempty" yaml:"Value,omitempty"`
}
// RestartPolicy represents the policy for automatically restarting a container.
//
// Possible values are:
//
// - always: the docker daemon will always restart the container
// - on-failure: the docker daemon will restart the container on failures, at
// most MaximumRetryCount times
// - no: the docker daemon will not restart the container automatically
type RestartPolicy struct {
Name string `json:"Name,omitempty" yaml:"Name,omitempty"`
MaximumRetryCount int `json:"MaximumRetryCount,omitempty" yaml:"MaximumRetryCount,omitempty"`
}
// AlwaysRestart returns a restart policy that tells the Docker daemon to
// always restart the container.
func AlwaysRestart() RestartPolicy {
return RestartPolicy{Name: "always"}
}
// RestartOnFailure returns a restart policy that tells the Docker daemon to
// restart the container on failures, trying at most maxRetry times.
func RestartOnFailure(maxRetry int) RestartPolicy {
return RestartPolicy{Name: "on-failure", MaximumRetryCount: maxRetry}
}
// NeverRestart returns a restart policy that tells the Docker daemon to never
// restart the container on failures.
func NeverRestart() RestartPolicy {
return RestartPolicy{Name: "no"}
} }
type HostConfig struct { type HostConfig struct {
Binds []string Binds []string `json:"Binds,omitempty" yaml:"Binds,omitempty"`
ContainerIDFile string CapAdd []string `json:"CapAdd,omitempty" yaml:"CapAdd,omitempty"`
LxcConf []KeyValuePair CapDrop []string `json:"CapDrop,omitempty" yaml:"CapDrop,omitempty"`
Privileged bool ContainerIDFile string `json:"ContainerIDFile,omitempty" yaml:"ContainerIDFile,omitempty"`
PortBindings map[Port][]PortBinding LxcConf []KeyValuePair `json:"LxcConf,omitempty" yaml:"LxcConf,omitempty"`
Links []string Privileged bool `json:"Privileged,omitempty" yaml:"Privileged,omitempty"`
PublishAllPorts bool PortBindings map[Port][]PortBinding `json:"PortBindings,omitempty" yaml:"PortBindings,omitempty"`
Dns []string // For Docker API v1.10 and above only Links []string `json:"Links,omitempty" yaml:"Links,omitempty"`
DnsSearch []string PublishAllPorts bool `json:"PublishAllPorts,omitempty" yaml:"PublishAllPorts,omitempty"`
VolumesFrom []string Dns []string `json:"Dns,omitempty" yaml:"Dns,omitempty"` // For Docker API v1.10 and above only
NetworkMode string DnsSearch []string `json:"DnsSearch,omitempty" yaml:"DnsSearch,omitempty"`
VolumesFrom []string `json:"VolumesFrom,omitempty" yaml:"VolumesFrom,omitempty"`
NetworkMode string `json:"NetworkMode,omitempty" yaml:"NetworkMode,omitempty"`
RestartPolicy RestartPolicy `json:"RestartPolicy,omitempty" yaml:"RestartPolicy,omitempty"`
} }
// StartContainer starts a container, returning an error in case of failure. // StartContainer starts a container, returning an error in case of failure.
@ -309,6 +343,9 @@ func (c *Client) StartContainer(id string, hostConfig *HostConfig) error {
if status == http.StatusNotFound { if status == http.StatusNotFound {
return &NoSuchContainer{ID: id} return &NoSuchContainer{ID: id}
} }
if status == http.StatusNotModified {
return &ContainerAlreadyRunning{ID: id}
}
if err != nil { if err != nil {
return err return err
} }
@ -325,6 +362,9 @@ func (c *Client) StopContainer(id string, timeout uint) error {
if status == http.StatusNotFound { if status == http.StatusNotFound {
return &NoSuchContainer{ID: id} return &NoSuchContainer{ID: id}
} }
if status == http.StatusNotModified {
return &ContainerNotRunning{ID: id}
}
if err != nil { if err != nil {
return err return err
} }
@ -590,7 +630,7 @@ func (c *Client) Logs(opts LogsOptions) error {
opts.Tail = "all" opts.Tail = "all"
} }
path := "/containers/" + opts.Container + "/logs?" + queryString(opts) path := "/containers/" + opts.Container + "/logs?" + queryString(opts)
return c.stream("GET", path, opts.RawTerminal, nil, nil, opts.OutputStream, opts.ErrorStream) return c.stream("GET", path, opts.RawTerminal, false, nil, nil, opts.OutputStream, opts.ErrorStream)
} }
// ResizeContainerTTY resizes the terminal to the given height and width. // ResizeContainerTTY resizes the terminal to the given height and width.
@ -617,10 +657,10 @@ type ExportContainerOptions struct {
// See http://goo.gl/Lqk0FZ for more details. // See http://goo.gl/Lqk0FZ for more details.
func (c *Client) ExportContainer(opts ExportContainerOptions) error { func (c *Client) ExportContainer(opts ExportContainerOptions) error {
if opts.ID == "" { if opts.ID == "" {
return NoSuchContainer{ID: opts.ID} return &NoSuchContainer{ID: opts.ID}
} }
url := fmt.Sprintf("/containers/%s/export", opts.ID) url := fmt.Sprintf("/containers/%s/export", opts.ID)
return c.stream("GET", url, true, nil, nil, opts.OutputStream, nil) return c.stream("GET", url, true, false, nil, nil, opts.OutputStream, nil)
} }
// NoSuchContainer is the error returned when a given container does not exist. // NoSuchContainer is the error returned when a given container does not exist.
@ -628,6 +668,26 @@ type NoSuchContainer struct {
ID string ID string
} }
func (err NoSuchContainer) Error() string { func (err *NoSuchContainer) Error() string {
return "No such container: " + err.ID return "No such container: " + err.ID
} }
// ContainerAlreadyRunning is the error returned when a given container is
// already running.
type ContainerAlreadyRunning struct {
ID string
}
func (err *ContainerAlreadyRunning) Error() string {
return "Container already running: " + err.ID
}
// ContainerNotRunning is the error returned when a given container is not
// running.
type ContainerNotRunning struct {
ID string
}
func (err *ContainerNotRunning) Error() string {
return "Container not running: " + err.ID
}

View File

@ -493,6 +493,15 @@ func TestStartContainerNotFound(t *testing.T) {
} }
} }
func TestStartContainerAlreadyRunning(t *testing.T) {
client := newTestClient(&FakeRoundTripper{message: "container already running", status: http.StatusNotModified})
err := client.StartContainer("a2334", &HostConfig{})
expected := &ContainerAlreadyRunning{ID: "a2334"}
if !reflect.DeepEqual(err, expected) {
t.Errorf("StartContainer: Wrong error returned. Want %#v. Got %#v.", expected, err)
}
}
func TestStopContainer(t *testing.T) { func TestStopContainer(t *testing.T) {
fakeRT := &FakeRoundTripper{message: "", status: http.StatusNoContent} fakeRT := &FakeRoundTripper{message: "", status: http.StatusNoContent}
client := newTestClient(fakeRT) client := newTestClient(fakeRT)
@ -520,6 +529,15 @@ func TestStopContainerNotFound(t *testing.T) {
} }
} }
func TestStopContainerNotRunning(t *testing.T) {
client := newTestClient(&FakeRoundTripper{message: "container not running", status: http.StatusNotModified})
err := client.StopContainer("a2334", 10)
expected := &ContainerNotRunning{ID: "a2334"}
if !reflect.DeepEqual(err, expected) {
t.Errorf("StopContainer: Wrong error returned. Want %#v. Got %#v.", expected, err)
}
}
func TestRestartContainer(t *testing.T) { func TestRestartContainer(t *testing.T) {
fakeRT := &FakeRoundTripper{message: "", status: http.StatusNoContent} fakeRT := &FakeRoundTripper{message: "", status: http.StatusNoContent}
client := newTestClient(fakeRT) client := newTestClient(fakeRT)
@ -1313,8 +1331,12 @@ func TestExportContainerNoId(t *testing.T) {
client := Client{} client := Client{}
out := stdoutMock{bytes.NewBufferString("")} out := stdoutMock{bytes.NewBufferString("")}
err := client.ExportContainer(ExportContainerOptions{OutputStream: out}) err := client.ExportContainer(ExportContainerOptions{OutputStream: out})
if err != (NoSuchContainer{}) { e, ok := err.(*NoSuchContainer)
t.Errorf("ExportContainer: wrong error. Want %#v. Got %#v.", NoSuchContainer{}, err) if !ok {
t.Errorf("ExportContainer: wrong error. Want NoSuchContainer. Got %#v.", e)
}
if e.ID != "" {
t.Errorf("ExportContainer: wrong ID. Want %q. Got %q", "", e.ID)
} }
} }
@ -1361,3 +1383,34 @@ func TestPassingNameOptToCreateContainerReturnsItInContainer(t *testing.T) {
t.Errorf("Container name expected to be TestCreateContainer, was %s", container.Name) t.Errorf("Container name expected to be TestCreateContainer, was %s", container.Name)
} }
} }
func TestAlwaysRestart(t *testing.T) {
policy := AlwaysRestart()
if policy.Name != "always" {
t.Errorf("AlwaysRestart(): wrong policy name. Want %q. Got %q", "always", policy.Name)
}
if policy.MaximumRetryCount != 0 {
t.Errorf("AlwaysRestart(): wrong MaximumRetryCount. Want 0. Got %d", policy.MaximumRetryCount)
}
}
func TestRestartOnFailure(t *testing.T) {
const retry = 5
policy := RestartOnFailure(retry)
if policy.Name != "on-failure" {
t.Errorf("RestartOnFailure(%d): wrong policy name. Want %q. Got %q", retry, "on-failure", policy.Name)
}
if policy.MaximumRetryCount != retry {
t.Errorf("RestartOnFailure(%d): wrong MaximumRetryCount. Want %d. Got %d", retry, retry, policy.MaximumRetryCount)
}
}
func TestNeverRestart(t *testing.T) {
policy := NeverRestart()
if policy.Name != "no" {
t.Errorf("NeverRestart(): wrong policy name. Want %q. Got %q", "always", policy.Name)
}
if policy.MaximumRetryCount != 0 {
t.Errorf("NeverRestart(): wrong MaximumRetryCount. Want 0. Got %d", policy.MaximumRetryCount)
}
}

View File

@ -20,10 +20,10 @@ import (
// APIEvents represents an event returned by the API. // APIEvents represents an event returned by the API.
type APIEvents struct { type APIEvents struct {
Status string Status string `json:"Status,omitempty" yaml:"Status,omitempty"`
ID string ID string `json:"ID,omitempty" yaml:"ID,omitempty"`
From string From string `json:"From,omitempty" yaml:"From,omitempty"`
Time int64 Time int64 `json:"Time,omitempty" yaml:"Time,omitempty"`
} }
type eventMonitoringState struct { type eventMonitoringState struct {

View File

@ -8,10 +8,11 @@ import (
"archive/tar" "archive/tar"
"bytes" "bytes"
"fmt" "fmt"
"github.com/fsouza/go-dockerclient"
"io" "io"
"log" "log"
"time" "time"
"github.com/fsouza/go-dockerclient"
) )
func ExampleClient_AttachToContainer() { func ExampleClient_AttachToContainer() {

View File

@ -20,28 +20,26 @@ import (
// APIImages represent an image returned in the ListImages call. // APIImages represent an image returned in the ListImages call.
type APIImages struct { type APIImages struct {
ID string `json:"Id"` ID string `json:"Id" yaml:"Id"`
RepoTags []string `json:",omitempty"` RepoTags []string `json:"RepoTags,omitempty" yaml:"RepoTags,omitempty"`
Created int64 Created int64 `json:"Created,omitempty" yaml:"Created,omitempty"`
Size int64 Size int64 `json:"Size,omitempty" yaml:"Size,omitempty"`
VirtualSize int64 VirtualSize int64 `json:"VirtualSize,omitempty" yaml:"VirtualSize,omitempty"`
ParentId string `json:",omitempty"` ParentId string `json:"ParentId,omitempty" yaml:"ParentId,omitempty"`
Repository string `json:",omitempty"`
Tag string `json:",omitempty"`
} }
type Image struct { type Image struct {
ID string `json:"id"` ID string `json:"Id" yaml:"Id"`
Parent string `json:"parent,omitempty"` Parent string `json:"Parent,omitempty" yaml:"Parent,omitempty"`
Comment string `json:"comment,omitempty"` Comment string `json:"Comment,omitempty" yaml:"Comment,omitempty"`
Created time.Time `json:"created"` Created time.Time `json:"Created,omitempty" yaml:"Created,omitempty"`
Container string `json:"container,omitempty"` Container string `json:"Container,omitempty" yaml:"Container,omitempty"`
ContainerConfig Config `json:"containerconfig,omitempty"` ContainerConfig Config `json:"ContainerConfig,omitempty" yaml:"ContainerConfig,omitempty"`
DockerVersion string `json:"dockerversion,omitempty"` DockerVersion string `json:"DockerVersion,omitempty" yaml:"DockerVersion,omitempty"`
Author string `json:"author,omitempty"` Author string `json:"Author,omitempty" yaml:"Author,omitempty"`
Config *Config `json:"config,omitempty"` Config *Config `json:"Config,omitempty" yaml:"Config,omitempty"`
Architecture string `json:"architecture,omitempty"` Architecture string `json:"Architecture,omitempty" yaml:"Architecture,omitempty"`
Size int64 Size int64 `json:"Size,omitempty" yaml:"Size,omitempty"`
} }
type ImagePre012 struct { type ImagePre012 struct {
@ -55,7 +53,7 @@ type ImagePre012 struct {
Author string `json:"author,omitempty"` Author string `json:"author,omitempty"`
Config *Config `json:"config,omitempty"` Config *Config `json:"config,omitempty"`
Architecture string `json:"architecture,omitempty"` Architecture string `json:"architecture,omitempty"`
Size int64 Size int64 `json:"size,omitempty"`
} }
var ( var (
@ -164,7 +162,7 @@ type PushImageOptions struct {
} }
// AuthConfiguration represents authentication options to use in the PushImage // AuthConfiguration represents authentication options to use in the PushImage
// method. It represents the authencation in the Docker index server. // method. It represents the authentication in the Docker index server.
type AuthConfiguration struct { type AuthConfiguration struct {
Username string `json:"username,omitempty"` Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"` Password string `json:"password,omitempty"`
@ -190,7 +188,7 @@ func (c *Client) PushImage(opts PushImageOptions, auth AuthConfiguration) error
headers["X-Registry-Auth"] = base64.URLEncoding.EncodeToString(buf.Bytes()) headers["X-Registry-Auth"] = base64.URLEncoding.EncodeToString(buf.Bytes())
return c.stream("POST", path, true, headers, nil, opts.OutputStream, nil) return c.stream("POST", path, true, false, headers, nil, opts.OutputStream, nil)
} }
// PullImageOptions present the set of options available for pulling an image // PullImageOptions present the set of options available for pulling an image
@ -198,10 +196,11 @@ func (c *Client) PushImage(opts PushImageOptions, auth AuthConfiguration) error
// //
// See http://goo.gl/PhBKnS for more details. // See http://goo.gl/PhBKnS for more details.
type PullImageOptions struct { type PullImageOptions struct {
Repository string `qs:"fromImage"` Repository string `qs:"fromImage"`
Registry string Registry string
Tag string Tag string
OutputStream io.Writer `qs:"-"` OutputStream io.Writer `qs:"-"`
RawJSONStream bool `qs:"-"`
} }
// PullImage pulls an image from a remote registry, logging progress to w. // PullImage pulls an image from a remote registry, logging progress to w.
@ -217,12 +216,41 @@ func (c *Client) PullImage(opts PullImageOptions, auth AuthConfiguration) error
json.NewEncoder(&buf).Encode(auth) json.NewEncoder(&buf).Encode(auth)
headers["X-Registry-Auth"] = base64.URLEncoding.EncodeToString(buf.Bytes()) headers["X-Registry-Auth"] = base64.URLEncoding.EncodeToString(buf.Bytes())
return c.createImage(queryString(&opts), headers, nil, opts.OutputStream) return c.createImage(queryString(&opts), headers, nil, opts.OutputStream, opts.RawJSONStream)
} }
func (c *Client) createImage(qs string, headers map[string]string, in io.Reader, w io.Writer) error { func (c *Client) createImage(qs string, headers map[string]string, in io.Reader, w io.Writer, rawJSONStream bool) error {
path := "/images/create?" + qs path := "/images/create?" + qs
return c.stream("POST", path, true, headers, in, w, nil) return c.stream("POST", path, true, rawJSONStream, headers, in, w, nil)
}
// LoadImageOptions represents the options for LoadImage Docker API Call
//
// See http://goo.gl/Y8NNCq for more details.
type LoadImageOptions struct {
InputStream io.Reader
}
// LoadImage imports a tarball docker image
//
// See http://goo.gl/Y8NNCq for more details.
func (c *Client) LoadImage(opts LoadImageOptions) error {
return c.stream("POST", "/images/load", true, false, nil, opts.InputStream, nil, nil)
}
// ExportImageOptions represent the options for ExportImage Docker API call
//
// See http://goo.gl/mi6kvk for more details.
type ExportImageOptions struct {
Name string
OutputStream io.Writer
}
// ExportImage exports an image (as a tar file) into the stream
//
// See http://goo.gl/mi6kvk for more details.
func (c *Client) ExportImage(opts ExportImageOptions) error {
return c.stream("GET", fmt.Sprintf("/images/%s/get", opts.Name), true, false, nil, nil, opts.OutputStream, nil)
} }
// ImportImageOptions present the set of informations available for importing // ImportImageOptions present the set of informations available for importing
@ -257,20 +285,21 @@ func (c *Client) ImportImage(opts ImportImageOptions) error {
opts.InputStream = bytes.NewBuffer(b) opts.InputStream = bytes.NewBuffer(b)
opts.Source = "-" opts.Source = "-"
} }
return c.createImage(queryString(&opts), nil, opts.InputStream, opts.OutputStream) return c.createImage(queryString(&opts), nil, opts.InputStream, opts.OutputStream, false)
} }
// BuildImageOptions present the set of informations available for building // BuildImageOptions present the set of informations available for building
// an image from a tarfile with a Dockerfile in it,the details about Dockerfile // an image from a tarfile with a Dockerfile in it,the details about Dockerfile
// see http://docs.docker.io/en/latest/reference/builder/ // see http://docs.docker.io/en/latest/reference/builder/
type BuildImageOptions struct { type BuildImageOptions struct {
Name string `qs:"t"` Name string `qs:"t"`
NoCache bool `qs:"nocache"` NoCache bool `qs:"nocache"`
SuppressOutput bool `qs:"q"` SuppressOutput bool `qs:"q"`
RmTmpContainer bool `qs:"rm"` RmTmpContainer bool `qs:"rm"`
InputStream io.Reader `qs:"-"` ForceRmTmpContainer bool `qs:"forcerm"`
OutputStream io.Writer `qs:"-"` InputStream io.Reader `qs:"-"`
Remote string `qs:"remote"` OutputStream io.Writer `qs:"-"`
Remote string `qs:"remote"`
} }
// BuildImage builds an image from a tarball's url or a Dockerfile in the input // BuildImage builds an image from a tarball's url or a Dockerfile in the input
@ -289,7 +318,7 @@ func (c *Client) BuildImage(opts BuildImageOptions) error {
return ErrMissingRepo return ErrMissingRepo
} }
return c.stream("POST", fmt.Sprintf("/build?%s", return c.stream("POST", fmt.Sprintf("/build?%s",
queryString(&opts)), true, headers, opts.InputStream, opts.OutputStream, nil) queryString(&opts)), true, false, headers, opts.InputStream, opts.OutputStream, nil)
} }
// TagImageOptions present the set of options to tag an image // TagImageOptions present the set of options to tag an image

View File

@ -309,6 +309,33 @@ func TestPullImage(t *testing.T) {
} }
} }
func TestPullImageWithRawJSON(t *testing.T) {
body := `
{"status":"Pulling..."}
{"status":"Pulling", "progress":"1 B/ 100 B", "progressDetail":{"current":1, "total":100}}
`
fakeRT := &FakeRoundTripper{
message: body,
status: http.StatusOK,
header: map[string]string{
"Content-Type": "application/json",
},
}
client := newTestClient(fakeRT)
var buf bytes.Buffer
err := client.PullImage(PullImageOptions{
Repository: "base",
OutputStream: &buf,
RawJSONStream: true,
}, AuthConfiguration{})
if err != nil {
t.Fatal(err)
}
if buf.String() != body {
t.Errorf("PullImage: Wrong raw output. Want %q. Got %q", body, buf.String())
}
}
func TestPullImageWithoutOutputStream(t *testing.T) { func TestPullImageWithoutOutputStream(t *testing.T) {
fakeRT := &FakeRoundTripper{message: "Pulling 1/100", status: http.StatusOK} fakeRT := &FakeRoundTripper{message: "Pulling 1/100", status: http.StatusOK}
client := newTestClient(fakeRT) client := newTestClient(fakeRT)
@ -514,19 +541,20 @@ func TestBuildImageParameters(t *testing.T) {
client := newTestClient(fakeRT) client := newTestClient(fakeRT)
var buf bytes.Buffer var buf bytes.Buffer
opts := BuildImageOptions{ opts := BuildImageOptions{
Name: "testImage", Name: "testImage",
NoCache: true, NoCache: true,
SuppressOutput: true, SuppressOutput: true,
RmTmpContainer: true, RmTmpContainer: true,
InputStream: &buf, ForceRmTmpContainer: true,
OutputStream: &buf, InputStream: &buf,
OutputStream: &buf,
} }
err := client.BuildImage(opts) err := client.BuildImage(opts)
if err != nil && strings.Index(err.Error(), "build image fail") == -1 { if err != nil && strings.Index(err.Error(), "build image fail") == -1 {
t.Fatal(err) t.Fatal(err)
} }
req := fakeRT.requests[0] req := fakeRT.requests[0]
expected := map[string][]string{"t": {opts.Name}, "nocache": {"1"}, "q": {"1"}, "rm": {"1"}} expected := map[string][]string{"t": {opts.Name}, "nocache": {"1"}, "q": {"1"}, "rm": {"1"}, "forcerm": {"1"}}
got := map[string][]string(req.URL.Query()) got := map[string][]string(req.URL.Query())
if !reflect.DeepEqual(got, expected) { if !reflect.DeepEqual(got, expected) {
t.Errorf("BuildImage: wrong query string. Want %#v. Got %#v.", expected, got) t.Errorf("BuildImage: wrong query string. Want %#v. Got %#v.", expected, got)
@ -640,3 +668,45 @@ func TestIsUrl(t *testing.T) {
t.Errorf("isURL: wrong match. Expected %#v to not be a url. Got %#v", url, result) t.Errorf("isURL: wrong match. Expected %#v to not be a url. Got %#v", url, result)
} }
} }
func TestLoadImage(t *testing.T) {
fakeRT := &FakeRoundTripper{message: "", status: http.StatusOK}
client := newTestClient(fakeRT)
tar, err := os.Open("testing/data/container.tar")
if err != nil {
t.Fatal(err)
} else {
defer tar.Close()
}
opts := LoadImageOptions{InputStream: tar}
err = client.LoadImage(opts)
if nil != err {
t.Error(err)
}
req := fakeRT.requests[0]
if req.Method != "POST" {
t.Errorf("LoadImage: wrong method. Expected %q. Got %q.", "POST", req.Method)
}
if req.URL.Path != "/images/load" {
t.Errorf("LoadImage: wrong URL. Expected %q. Got %q.", "/images/load", req.URL.Path)
}
}
func TestExportImage(t *testing.T) {
var buf bytes.Buffer
fakeRT := &FakeRoundTripper{message: "", status: http.StatusOK}
client := newTestClient(fakeRT)
opts := ExportImageOptions{Name: "testimage", OutputStream: &buf}
err := client.ExportImage(opts)
if nil != err {
t.Error(err)
}
req := fakeRT.requests[0]
if req.Method != "GET" {
t.Errorf("ExportImage: wrong method. Expected %q. Got %q.", "GET", req.Method)
}
expectedPath := "/images/testimage/get"
if req.URL.Path != expectedPath {
t.Errorf("ExportIMage: wrong path. Expected %q. Got %q.", expectedPath, req.URL.Path)
}
}

View File

@ -12,8 +12,6 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"github.com/fsouza/go-dockerclient"
"github.com/gorilla/mux"
mathrand "math/rand" mathrand "math/rand"
"net" "net"
"net/http" "net/http"
@ -22,6 +20,9 @@ import (
"strings" "strings"
"sync" "sync"
"time" "time"
"github.com/fsouza/go-dockerclient"
"github.com/gorilla/mux"
) )
// DockerServer represents a programmable, concurrent (not much), HTTP server // DockerServer represents a programmable, concurrent (not much), HTTP server
@ -102,6 +103,8 @@ func (s *DockerServer) buildMuxer() {
s.mux.Path("/images/{name:.*}/push").Methods("POST").HandlerFunc(s.handlerWrapper(s.pushImage)) s.mux.Path("/images/{name:.*}/push").Methods("POST").HandlerFunc(s.handlerWrapper(s.pushImage))
s.mux.Path("/events").Methods("GET").HandlerFunc(s.listEvents) s.mux.Path("/events").Methods("GET").HandlerFunc(s.listEvents)
s.mux.Path("/_ping").Methods("GET").HandlerFunc(s.handlerWrapper(s.pingDocker)) s.mux.Path("/_ping").Methods("GET").HandlerFunc(s.handlerWrapper(s.pingDocker))
s.mux.Path("/images/load").Methods("POST").HandlerFunc(s.handlerWrapper(s.loadImage))
s.mux.Path("/images/{id:.*}/get").Methods("GET").HandlerFunc(s.handlerWrapper(s.getImage))
} }
// PrepareFailure adds a new expected failure based on a URL regexp it receives // PrepareFailure adds a new expected failure based on a URL regexp it receives
@ -653,3 +656,13 @@ func (s *DockerServer) generateEvent() *docker.APIEvents {
Time: time.Now().Unix(), Time: time.Now().Unix(),
} }
} }
func (s *DockerServer) loadImage(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}
func (s *DockerServer) getImage(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/tar")
}

View File

@ -7,7 +7,6 @@ package testing
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/fsouza/go-dockerclient"
"math/rand" "math/rand"
"net" "net"
"net/http" "net/http"
@ -17,6 +16,8 @@ import (
"strings" "strings"
"testing" "testing"
"time" "time"
"github.com/fsouza/go-dockerclient"
) )
func TestNewServer(t *testing.T) { func TestNewServer(t *testing.T) {

View File

@ -17,10 +17,10 @@ limitations under the License.
package v1beta1 package v1beta1
import ( import (
"github.com/fsouza/go-dockerclient"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch" "github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
"github.com/GoogleCloudPlatform/kubernetes/third_party/docker-api-structs"
) )
// Common string formats // Common string formats

View File

@ -1,22 +0,0 @@
Copyright (c) 2014, go-dockerclient authors
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1 +0,0 @@
This package is a fork of part of [go-dockerclient](https://github.com/fsouza/go-dockerclient).

View File

@ -1,104 +0,0 @@
// 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 (
"time"
)
type Container struct {
ID string `yaml:"ID,omitempty" json:"ID,omitempty"`
Created time.Time `yaml:"Created,omitempty" json:"Created,omitempty"`
Path string `yaml:"Path,omitempty" json:"Path,omitempty"`
Args []string `yaml:"Args,omitempty" json:"Args,omitempty"`
Config *Config `yaml:"Config,omitempty" json:"Config,omitempty"`
State State `yaml:"State,omitempty" json:"State,omitempty"`
Image string `yaml:"Image,omitempty" json:"Image,omitempty"`
NetworkSettings *NetworkSettings `yaml:"NetworkSettings,omitempty" json:"NetworkSettings,omitempty"`
SysInitPath string `yaml:"SysInitPath,omitempty" json:"SysInitPath,omitempty"`
ResolvConfPath string `yaml:"ResolvConfPath,omitempty" json:"ResolvConfPath,omitempty"`
HostnamePath string `yaml:"HostnamePath,omitempty" json:"HostnamePath,omitempty"`
HostsPath string `yaml:"HostsPath,omitempty" json:"HostsPath,omitempty"`
Name string `yaml:"Name,omitempty" json:"Name,omitempty"`
Driver string `yaml:"Driver,omitempty" json:"Driver,omitempty"`
Volumes map[string]string `yaml:"Volumes,omitempty" json:"Volumes,omitempty"`
VolumesRW map[string]bool `yaml:"VolumesRW,omitempty" json:"VolumesRW,omitempty"`
HostConfig *HostConfig `yaml:"HostConfig,omitempty" json:"HostConfig,omitempty"`
}
type Config struct {
Hostname string `yaml:"Hostname,omitempty" json:"Hostname,omitempty"`
Domainname string `yaml:"Domainname,omitempty" json:"Domainname,omitempty"`
User string `yaml:"User,omitempty" json:"User,omitempty"`
Memory int64 `yaml:"Memory,omitempty" json:"Memory,omitempty"`
MemorySwap int64 `yaml:"MemorySwap,omitempty" json:"MemorySwap,omitempty"`
CpuShares int64 `yaml:"CpuShares,omitempty" json:"CpuShares,omitempty"`
AttachStdin bool `yaml:"AttachStdin,omitempty" json:"AttachStdin,omitempty"`
AttachStdout bool `yaml:"AttachStdout,omitempty" json:"AttachStdout,omitempty"`
AttachStderr bool `yaml:"AttachStderr,omitempty" json:"AttachStderr,omitempty"`
PortSpecs []string `yaml:"PortSpecs,omitempty" json:"PortSpecs,omitempty"`
ExposedPorts map[Port]struct{} `yaml:"ExposedPorts,omitempty" json:"ExposedPorts,omitempty"`
Tty bool `yaml:"Tty,omitempty" json:"Tty,omitempty"`
OpenStdin bool `yaml:"OpenStdin,omitempty" json:"OpenStdin,omitempty"`
StdinOnce bool `yaml:"StdinOnce,omitempty" json:"StdinOnce,omitempty"`
Env []string `yaml:"Env,omitempty" json:"Env,omitempty"`
Cmd []string `yaml:"Cmd,omitempty" json:"Cmd,omitempty"`
Dns []string `yaml:"Dns,omitempty" json:"Dns,omitempty"`
Image string `yaml:"Image,omitempty" json:"Image,omitempty"`
Volumes map[string]struct{} `yaml:"Volumes,omitempty" json:"Volumes,omitempty"`
VolumesFrom string `yaml:"VolumesFrom,omitempty" json:"VolumesFrom,omitempty"`
WorkingDir string `yaml:"WorkingDir,omitempty" json:"WorkingDir,omitempty"`
Entrypoint []string `yaml:"Entrypoint,omitempty" json:"Entrypoint,omitempty"`
NetworkDisabled bool `yaml:"NetworkDisabled,omitempty" json:"NetworkDisabled,omitempty"`
}
type State struct {
Running bool `yaml:"Running,omitempty" json:"Running,omitempty"`
Paused bool `yaml:"Paused,omitempty" json:"Paused,omitempty"`
Pid int `yaml:"Pid,omitempty" json:"Pid,omitempty"`
ExitCode int `yaml:"ExitCode,omitempty" json:"ExitCode,omitempty"`
StartedAt time.Time `yaml:"StartedAt,omitempty" json:"StartedAt,omitempty"`
FinishedAt time.Time `yaml:"FinishedAt,omitempty" json:"FinishedAt,omitempty"`
}
type PortBinding struct {
HostIp string `yaml:"HostIp,omitempty" json:"HostIp,omitempty"`
HostPort string `yaml:"HostPort,omitempty" json:"HostPort,omitempty"`
}
type PortMapping map[string]string
type NetworkSettings struct {
IPAddress string `yaml:"IPAddress,omitempty" json:"IPAddress,omitempty"`
IPPrefixLen int `yaml:"IPPrefixLen,omitempty" json:"IPPrefixLen,omitempty"`
Gateway string `yaml:"Gateway,omitempty" json:"Gateway,omitempty"`
Bridge string `yaml:"Bridge,omitempty" json:"Bridge,omitempty"`
PortMapping map[string]PortMapping `yaml:"PortMapping,omitempty" json:"PortMapping,omitempty"`
Ports map[Port][]PortBinding `yaml:"Ports,omitempty" json:"Ports,omitempty"`
}
type KeyValuePair struct {
Key string `yaml:"Key,omitempty" json:"Key,omitempty"`
Value string `yaml:"Value,omitempty" json:"Value,omitempty"`
}
type Port string
type HostConfig struct {
Binds []string `yaml:"Binds,omitempty" json:"Binds,omitempty"`
ContainerIDFile string `yaml:"ContainerIDFile,omitempty" json:"ContainerIDFile,omitempty"`
LxcConf []KeyValuePair `yaml:"LxcConf,omitempty" json:"LxcConf,omitempty"`
Privileged bool `yaml:"Privileged,omitempty" json:"Privileged,omitempty"`
PortBindings map[Port][]PortBinding `yaml:"PortBindings,omitempty" json:"PortBindings,omitempty"`
Links []string `yaml:"Links,omitempty" json:"Links,omitempty"`
PublishAllPorts bool `yaml:"PublishAllPorts,omitempty" json:"PublishAllPorts,omitempty"`
Dns []string `yaml:"Dns,omitempty" json:"Dns,omitempty"`
DnsSearch []string `yaml:"DnsSearch,omitempty" json:"DnsSearch,omitempty"`
VolumesFrom []string `yaml:"VolumesFrom,omitempty" json:"VolumesFrom,omitempty"`
NetworkMode string `yaml:"NetworkMode,omitempty" json:"NetworkMode,omitempty"`
}