mirror of https://github.com/docker/docs.git
Merge pull request #2442 from dgageot/version
Add version to machine ls
This commit is contained in:
commit
b8b5bd8a45
|
|
@ -5,6 +5,7 @@
|
||||||
"github.com/docker/machine",
|
"github.com/docker/machine",
|
||||||
"github.com/docker/machine/cmd",
|
"github.com/docker/machine/cmd",
|
||||||
"github.com/docker/machine/commands",
|
"github.com/docker/machine/commands",
|
||||||
|
"github.com/docker/machine/commands/commandstest",
|
||||||
"github.com/docker/machine/commands/mcndirs",
|
"github.com/docker/machine/commands/mcndirs",
|
||||||
"github.com/docker/machine/drivers/amazonec2",
|
"github.com/docker/machine/drivers/amazonec2",
|
||||||
"github.com/docker/machine/drivers/amazonec2/amz",
|
"github.com/docker/machine/drivers/amazonec2/amz",
|
||||||
|
|
@ -36,11 +37,13 @@
|
||||||
"github.com/docker/machine/libmachine/examples",
|
"github.com/docker/machine/libmachine/examples",
|
||||||
"github.com/docker/machine/libmachine/host",
|
"github.com/docker/machine/libmachine/host",
|
||||||
"github.com/docker/machine/libmachine/hosttest",
|
"github.com/docker/machine/libmachine/hosttest",
|
||||||
|
"github.com/docker/machine/libmachine/libmachinetest",
|
||||||
"github.com/docker/machine/libmachine/log",
|
"github.com/docker/machine/libmachine/log",
|
||||||
"github.com/docker/machine/libmachine/mcnerror",
|
"github.com/docker/machine/libmachine/mcnerror",
|
||||||
"github.com/docker/machine/libmachine/mcnflag",
|
"github.com/docker/machine/libmachine/mcnflag",
|
||||||
"github.com/docker/machine/libmachine/mcnutils",
|
"github.com/docker/machine/libmachine/mcnutils",
|
||||||
"github.com/docker/machine/libmachine/persist",
|
"github.com/docker/machine/libmachine/persist",
|
||||||
|
"github.com/docker/machine/libmachine/persist/persisttest",
|
||||||
"github.com/docker/machine/libmachine/provider",
|
"github.com/docker/machine/libmachine/provider",
|
||||||
"github.com/docker/machine/libmachine/provision",
|
"github.com/docker/machine/libmachine/provision",
|
||||||
"github.com/docker/machine/libmachine/provision/pkgaction",
|
"github.com/docker/machine/libmachine/provision/pkgaction",
|
||||||
|
|
@ -76,6 +79,11 @@
|
||||||
"Comment": "v1.5.0",
|
"Comment": "v1.5.0",
|
||||||
"Rev": "a8a31eff10544860d2188dddabdee4d727545796"
|
"Rev": "a8a31eff10544860d2188dddabdee4d727545796"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/docker/docker/pkg/units",
|
||||||
|
"Comment": "v1.5.0",
|
||||||
|
"Rev": "a8a31eff10544860d2188dddabdee4d727545796"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/go-querystring/query",
|
"ImportPath": "github.com/google/go-querystring/query",
|
||||||
"Rev": "30f7a39f4a218feb5325f3aebc60c32a572a8274"
|
"Rev": "30f7a39f4a218feb5325f3aebc60c32a572a8274"
|
||||||
|
|
@ -93,6 +101,10 @@
|
||||||
"Comment": "v1.0.0-558-gce0f487",
|
"Comment": "v1.0.0-558-gce0f487",
|
||||||
"Rev": "ce0f487f6747ab43c4e4404722df25349385bebd"
|
"Rev": "ce0f487f6747ab43c4e4404722df25349385bebd"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/samalba/dockerclient",
|
||||||
|
"Rev": "82381805d3533c97cec74e1cc79b00ef45774571"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/skarademir/naturalsort",
|
"ImportPath": "github.com/skarademir/naturalsort",
|
||||||
"Rev": "69a5d87bef620f77ee8508db30c846b3b84b111e"
|
"Rev": "69a5d87bef620f77ee8508db30c846b3b84b111e"
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errTooManyArguments = errors.New("Error: Too many arguments given")
|
|
||||||
errNoActiveHost = errors.New("No active host found")
|
errNoActiveHost = errors.New("No active host found")
|
||||||
)
|
)
|
||||||
|
|
||||||
func cmdActive(c CommandLine, api libmachine.API) error {
|
func cmdActive(c CommandLine, api libmachine.API) error {
|
||||||
if len(c.Args()) > 0 {
|
if len(c.Args()) > 0 {
|
||||||
return errTooManyArguments
|
return ErrTooManyArguments
|
||||||
}
|
}
|
||||||
|
|
||||||
hosts, hostsInError, err := persist.LoadAllHosts(api)
|
hosts, hostsInError, err := persist.LoadAllHosts(api)
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ var (
|
||||||
ErrUnknownShell = errors.New("Error: Unknown shell")
|
ErrUnknownShell = errors.New("Error: Unknown shell")
|
||||||
ErrNoMachineSpecified = errors.New("Error: Expected to get one or more machine names as arguments")
|
ErrNoMachineSpecified = errors.New("Error: Expected to get one or more machine names as arguments")
|
||||||
ErrExpectedOneMachine = errors.New("Error: Expected one machine name as an argument")
|
ErrExpectedOneMachine = errors.New("Error: Expected one machine name as an argument")
|
||||||
|
ErrTooManyArguments = errors.New("Error: Too many arguments given")
|
||||||
)
|
)
|
||||||
|
|
||||||
// CommandLine contains all the information passed to the commands on the command line.
|
// CommandLine contains all the information passed to the commands on the command line.
|
||||||
|
|
@ -305,7 +306,7 @@ var Commands = []cli.Command{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "version",
|
Name: "version",
|
||||||
Usage: "Show the Docker Machine version information",
|
Usage: "Show the Docker Machine version or a machine docker version",
|
||||||
Action: fatalOnError(cmdVersion),
|
Action: fatalOnError(cmdVersion),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -316,7 +317,9 @@ func printIP(h *host.Host) func() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Error getting IP address: %s", err)
|
return fmt.Errorf("Error getting IP address: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(ip)
|
fmt.Println(ip)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ type FakeFlagger struct {
|
||||||
|
|
||||||
type FakeCommandLine struct {
|
type FakeCommandLine struct {
|
||||||
LocalFlags, GlobalFlags *FakeFlagger
|
LocalFlags, GlobalFlags *FakeFlagger
|
||||||
HelpShown bool
|
HelpShown, VersionShown bool
|
||||||
CliArgs []string
|
CliArgs []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,5 +91,5 @@ func (fcli *FakeCommandLine) Args() cli.Args {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fcli *FakeCommandLine) ShowVersion() {
|
func (fcli *FakeCommandLine) ShowVersion() {
|
||||||
return
|
fcli.VersionShown = true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ type HostListItem struct {
|
||||||
URL string
|
URL string
|
||||||
SwarmOptions *swarm.Options
|
SwarmOptions *swarm.Options
|
||||||
Error string
|
Error string
|
||||||
|
DockerVersion string
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdLs(c CommandLine, api libmachine.API) error {
|
func cmdLs(c CommandLine, api libmachine.API) error {
|
||||||
|
|
@ -68,7 +69,7 @@ func cmdLs(c CommandLine, api libmachine.API) error {
|
||||||
swarmInfo := make(map[string]string)
|
swarmInfo := make(map[string]string)
|
||||||
|
|
||||||
w := tabwriter.NewWriter(os.Stdout, 5, 1, 3, ' ', 0)
|
w := tabwriter.NewWriter(os.Stdout, 5, 1, 3, ' ', 0)
|
||||||
fmt.Fprintln(w, "NAME\tACTIVE\tDRIVER\tSTATE\tURL\tSWARM\tERRORS")
|
fmt.Fprintln(w, "NAME\tACTIVE\tDRIVER\tSTATE\tURL\tSWARM\tDOCKER\tERRORS")
|
||||||
|
|
||||||
for _, host := range hostList {
|
for _, host := range hostList {
|
||||||
swarmOptions := host.HostOptions.SwarmOptions
|
swarmOptions := host.HostOptions.SwarmOptions
|
||||||
|
|
@ -97,8 +98,8 @@ func cmdLs(c CommandLine, api libmachine.API) error {
|
||||||
swarmInfo = fmt.Sprintf("%s (master)", swarmInfo)
|
swarmInfo = fmt.Sprintf("%s (master)", swarmInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
|
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
|
||||||
item.Name, activeString, item.DriverName, item.State, item.URL, swarmInfo, item.Error)
|
item.Name, activeString, item.DriverName, item.State, item.URL, swarmInfo, item.DockerVersion, item.Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Flush()
|
w.Flush()
|
||||||
|
|
@ -232,11 +233,21 @@ func matchesName(host *host.Host, names []string) bool {
|
||||||
func attemptGetHostState(h *host.Host, stateQueryChan chan<- HostListItem) {
|
func attemptGetHostState(h *host.Host, stateQueryChan chan<- HostListItem) {
|
||||||
url := ""
|
url := ""
|
||||||
hostError := ""
|
hostError := ""
|
||||||
|
dockerVersion := "Unknown"
|
||||||
|
|
||||||
currentState, err := h.Driver.GetState()
|
currentState, err := h.Driver.GetState()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
url, err = h.GetURL()
|
url, err = h.URL()
|
||||||
}
|
}
|
||||||
|
if err == nil {
|
||||||
|
dockerVersion, err = h.DockerVersion()
|
||||||
|
if err != nil {
|
||||||
|
dockerVersion = "Unknown"
|
||||||
|
} else {
|
||||||
|
dockerVersion = fmt.Sprintf("v%s", dockerVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
hostError = err.Error()
|
hostError = err.Error()
|
||||||
}
|
}
|
||||||
|
|
@ -256,6 +267,7 @@ func attemptGetHostState(h *host.Host, stateQueryChan chan<- HostListItem) {
|
||||||
State: currentState,
|
State: currentState,
|
||||||
URL: url,
|
URL: url,
|
||||||
SwarmOptions: swarmOptions,
|
SwarmOptions: swarmOptions,
|
||||||
|
DockerVersion: dockerVersion,
|
||||||
Error: hostError,
|
Error: hostError,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import (
|
||||||
|
|
||||||
"github.com/docker/machine/drivers/fakedriver"
|
"github.com/docker/machine/drivers/fakedriver"
|
||||||
"github.com/docker/machine/libmachine/host"
|
"github.com/docker/machine/libmachine/host"
|
||||||
|
"github.com/docker/machine/libmachine/mcndockerclient"
|
||||||
"github.com/docker/machine/libmachine/state"
|
"github.com/docker/machine/libmachine/state"
|
||||||
"github.com/docker/machine/libmachine/swarm"
|
"github.com/docker/machine/libmachine/swarm"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
@ -296,6 +297,9 @@ func TestFilterHostsDifferentFlagsProduceAND(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetHostListItems(t *testing.T) {
|
func TestGetHostListItems(t *testing.T) {
|
||||||
|
mcndockerclient.CurrentDockerVersioner = &mcndockerclient.FakeDockerVersioner{Version: "1.9"}
|
||||||
|
defer mcndockerclient.CleanupDockerVersioner()
|
||||||
|
|
||||||
// TODO: Ideally this would mockable via interface instead.
|
// TODO: Ideally this would mockable via interface instead.
|
||||||
os.Setenv("DOCKER_HOST", "tcp://active.host.com:2376")
|
os.Setenv("DOCKER_HOST", "tcp://active.host.com:2376")
|
||||||
|
|
||||||
|
|
@ -334,11 +338,12 @@ func TestGetHostListItems(t *testing.T) {
|
||||||
name string
|
name string
|
||||||
state state.State
|
state state.State
|
||||||
active bool
|
active bool
|
||||||
|
version string
|
||||||
error string
|
error string
|
||||||
}{
|
}{
|
||||||
{"bar10", state.Error, false, "Unable to get ip"},
|
{"bar10", state.Error, false, "Unknown", "Unable to get ip"},
|
||||||
{"bar100", state.Stopped, false, ""},
|
{"bar100", state.Stopped, false, "Unknown", ""},
|
||||||
{"foo", state.Running, true, ""},
|
{"foo", state.Running, true, "v1.9", ""},
|
||||||
}
|
}
|
||||||
|
|
||||||
items := getHostListItems(hosts, map[string]error{})
|
items := getHostListItems(hosts, map[string]error{})
|
||||||
|
|
@ -347,6 +352,7 @@ func TestGetHostListItems(t *testing.T) {
|
||||||
assert.Equal(t, expected[i].name, items[i].Name)
|
assert.Equal(t, expected[i].name, items[i].Name)
|
||||||
assert.Equal(t, expected[i].state, items[i].State)
|
assert.Equal(t, expected[i].state, items[i].State)
|
||||||
assert.Equal(t, expected[i].active, items[i].Active)
|
assert.Equal(t, expected[i].active, items[i].Active)
|
||||||
|
assert.Equal(t, expected[i].version, items[i].DockerVersion)
|
||||||
assert.Equal(t, expected[i].error, items[i].Error)
|
assert.Equal(t, expected[i].error, items[i].Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -355,6 +361,9 @@ func TestGetHostListItems(t *testing.T) {
|
||||||
|
|
||||||
// issue #1908
|
// issue #1908
|
||||||
func TestGetHostListItemsEnvDockerHostUnset(t *testing.T) {
|
func TestGetHostListItemsEnvDockerHostUnset(t *testing.T) {
|
||||||
|
mcndockerclient.CurrentDockerVersioner = &mcndockerclient.FakeDockerVersioner{Version: "1.9"}
|
||||||
|
defer mcndockerclient.CleanupDockerVersioner()
|
||||||
|
|
||||||
orgDockerHost := os.Getenv("DOCKER_HOST")
|
orgDockerHost := os.Getenv("DOCKER_HOST")
|
||||||
defer func() {
|
defer func() {
|
||||||
// revert DOCKER_HOST
|
// revert DOCKER_HOST
|
||||||
|
|
@ -410,10 +419,11 @@ func TestGetHostListItemsEnvDockerHostUnset(t *testing.T) {
|
||||||
expected := map[string]struct {
|
expected := map[string]struct {
|
||||||
state state.State
|
state state.State
|
||||||
active bool
|
active bool
|
||||||
|
version string
|
||||||
}{
|
}{
|
||||||
"foo": {state.Running, false},
|
"foo": {state.Running, false, "v1.9"},
|
||||||
"bar": {state.Stopped, false},
|
"bar": {state.Stopped, false, "Unknown"},
|
||||||
"baz": {state.Saved, false},
|
"baz": {state.Saved, false, "Unknown"},
|
||||||
}
|
}
|
||||||
|
|
||||||
items := getHostListItems(hosts, map[string]error{})
|
items := getHostListItems(hosts, map[string]error{})
|
||||||
|
|
@ -423,6 +433,7 @@ func TestGetHostListItemsEnvDockerHostUnset(t *testing.T) {
|
||||||
|
|
||||||
assert.Equal(t, expected.state, item.State)
|
assert.Equal(t, expected.state, item.State)
|
||||||
assert.Equal(t, expected.active, item.Active)
|
assert.Equal(t, expected.active, item.Active)
|
||||||
|
assert.Equal(t, expected.version, item.DockerVersion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -463,7 +474,7 @@ func TestGetHostStateTimeout(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
stateTimeoutDuration = 1 * time.Second
|
stateTimeoutDuration = 1 * time.Millisecond
|
||||||
hostItems := getHostListItems(hosts, map[string]error{})
|
hostItems := getHostListItems(hosts, map[string]error{})
|
||||||
hostItem := hostItems[0]
|
hostItem := hostItems[0]
|
||||||
|
|
||||||
|
|
@ -496,6 +507,9 @@ func TestGetHostStateError(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetSomeHostInEror(t *testing.T) {
|
func TestGetSomeHostInEror(t *testing.T) {
|
||||||
|
mcndockerclient.CurrentDockerVersioner = &mcndockerclient.FakeDockerVersioner{Version: "1.9"}
|
||||||
|
defer mcndockerclient.CleanupDockerVersioner()
|
||||||
|
|
||||||
hosts := []*host.Host{
|
hosts := []*host.Host{
|
||||||
{
|
{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ func cmdURL(c CommandLine, api libmachine.API) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
url, err := host.GetURL()
|
url, err := host.URL()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,39 @@
|
||||||
package commands
|
package commands
|
||||||
|
|
||||||
import "github.com/docker/machine/libmachine"
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/docker/machine/libmachine"
|
||||||
|
)
|
||||||
|
|
||||||
func cmdVersion(c CommandLine, api libmachine.API) error {
|
func cmdVersion(c CommandLine, api libmachine.API) error {
|
||||||
|
return printVersion(c, api, os.Stdout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func printVersion(c CommandLine, api libmachine.API, out io.Writer) error {
|
||||||
|
if len(c.Args()) == 0 {
|
||||||
c.ShowVersion()
|
c.ShowVersion()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(c.Args()) != 1 {
|
||||||
|
return ErrExpectedOneMachine
|
||||||
|
}
|
||||||
|
|
||||||
|
host, err := api.Load(c.Args().First())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
version, err := host.DockerVersion()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintln(out, version)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"bytes"
|
||||||
|
|
||||||
|
"github.com/docker/machine/commands/commandstest"
|
||||||
|
"github.com/docker/machine/drivers/vmwarevsphere/errors"
|
||||||
|
"github.com/docker/machine/libmachine/host"
|
||||||
|
"github.com/docker/machine/libmachine/libmachinetest"
|
||||||
|
"github.com/docker/machine/libmachine/mcndockerclient"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCmdVersion(t *testing.T) {
|
||||||
|
commandLine := &commandstest.FakeCommandLine{}
|
||||||
|
api := &libmachinetest.FakeAPI{}
|
||||||
|
|
||||||
|
err := cmdVersion(commandLine, api)
|
||||||
|
|
||||||
|
assert.True(t, commandLine.VersionShown)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCmdVersionTooManyNames(t *testing.T) {
|
||||||
|
commandLine := &commandstest.FakeCommandLine{
|
||||||
|
CliArgs: []string{"machine1", "machine2"},
|
||||||
|
}
|
||||||
|
api := &libmachinetest.FakeAPI{}
|
||||||
|
|
||||||
|
err := cmdVersion(commandLine, api)
|
||||||
|
|
||||||
|
assert.EqualError(t, err, "Error: Expected one machine name as an argument")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCmdVersionNotFound(t *testing.T) {
|
||||||
|
commandLine := &commandstest.FakeCommandLine{
|
||||||
|
CliArgs: []string{"unknown"},
|
||||||
|
}
|
||||||
|
api := &libmachinetest.FakeAPI{}
|
||||||
|
|
||||||
|
err := cmdVersion(commandLine, api)
|
||||||
|
|
||||||
|
assert.EqualError(t, err, `Host does not exist: "unknown"`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCmdVersionOnHost(t *testing.T) {
|
||||||
|
mcndockerclient.CurrentDockerVersioner = &mcndockerclient.FakeDockerVersioner{Version: "1.9.1"}
|
||||||
|
defer mcndockerclient.CleanupDockerVersioner()
|
||||||
|
|
||||||
|
commandLine := &commandstest.FakeCommandLine{
|
||||||
|
CliArgs: []string{"machine"},
|
||||||
|
}
|
||||||
|
api := &libmachinetest.FakeAPI{
|
||||||
|
Hosts: []*host.Host{
|
||||||
|
{
|
||||||
|
Name: "machine",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
out := &bytes.Buffer{}
|
||||||
|
err := printVersion(commandLine, api, out)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "1.9.1\n", out.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCmdVersionFailure(t *testing.T) {
|
||||||
|
mcndockerclient.CurrentDockerVersioner = &mcndockerclient.FakeDockerVersioner{Err: errors.New("connection failure")}
|
||||||
|
defer mcndockerclient.CleanupDockerVersioner()
|
||||||
|
|
||||||
|
commandLine := &commandstest.FakeCommandLine{
|
||||||
|
CliArgs: []string{"machine"},
|
||||||
|
}
|
||||||
|
api := &libmachinetest.FakeAPI{
|
||||||
|
Hosts: []*host.Host{
|
||||||
|
{
|
||||||
|
Name: "machine",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
out := &bytes.Buffer{}
|
||||||
|
err := printVersion(commandLine, api, out)
|
||||||
|
|
||||||
|
assert.EqualError(t, err, "connection failure")
|
||||||
|
}
|
||||||
|
|
@ -185,6 +185,14 @@ _docker_machine_url() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_docker_machine_version() {
|
||||||
|
if [[ "${cur}" == -* ]]; then
|
||||||
|
COMPREPLY=($(compgen -W "--help" -- "${cur}"))
|
||||||
|
else
|
||||||
|
COMPREPLY=($(compgen -W "$(docker-machine ls -q)" -- "${cur}"))
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
_docker_machine_help() {
|
_docker_machine_help() {
|
||||||
if [[ "${cur}" == -* ]]; then
|
if [[ "${cur}" == -* ]]; then
|
||||||
COMPREPLY=($(compgen -W "--help" -- "${cur}"))
|
COMPREPLY=($(compgen -W "--help" -- "${cur}"))
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,8 @@ instructions in the next section.
|
||||||
|
|
||||||
3. Check the installation by displaying the Machine version:
|
3. Check the installation by displaying the Machine version:
|
||||||
|
|
||||||
$ docker-machine -v
|
$ docker-machine version
|
||||||
machine version 0.5.0 (3e06852)
|
docker-machine version 0.5.2 (0456b9f)
|
||||||
|
|
||||||
## Installing bash completion scripts
|
## Installing bash completion scripts
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ var defaultGenerator = NewX509CertGenerator()
|
||||||
type Generator interface {
|
type Generator interface {
|
||||||
GenerateCACertificate(certFile, keyFile, org string, bits int) error
|
GenerateCACertificate(certFile, keyFile, org string, bits int) error
|
||||||
GenerateCert(hosts []string, certFile, keyFile, caFile, caKeyFile, org string, bits int) error
|
GenerateCert(hosts []string, certFile, keyFile, caFile, caKeyFile, org string, bits int) error
|
||||||
|
ReadTLSConfig(addr string, authOptions *auth.Options) (*tls.Config, error)
|
||||||
ValidateCertificate(addr string, authOptions *auth.Options) (bool, error)
|
ValidateCertificate(addr string, authOptions *auth.Options) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,6 +46,10 @@ func ValidateCertificate(addr string, authOptions *auth.Options) (bool, error) {
|
||||||
return defaultGenerator.ValidateCertificate(addr, authOptions)
|
return defaultGenerator.ValidateCertificate(addr, authOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReadTLSConfig(addr string, authOptions *auth.Options) (*tls.Config, error) {
|
||||||
|
return defaultGenerator.ReadTLSConfig(addr, authOptions)
|
||||||
|
}
|
||||||
|
|
||||||
func SetCertGenerator(cg Generator) {
|
func SetCertGenerator(cg Generator) {
|
||||||
defaultGenerator = cg
|
defaultGenerator = cg
|
||||||
}
|
}
|
||||||
|
|
@ -204,8 +209,8 @@ func (xcg *X509CertGenerator) GenerateCert(hosts []string, certFile, keyFile, ca
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateCertificate validate the certificate installed on the vm.
|
// ReadTLSConfig reads the tls config for a machine.
|
||||||
func (xcg *X509CertGenerator) ValidateCertificate(addr string, authOptions *auth.Options) (bool, error) {
|
func (xcg *X509CertGenerator) ReadTLSConfig(addr string, authOptions *auth.Options) (*tls.Config, error) {
|
||||||
caCertPath := authOptions.CaCertPath
|
caCertPath := authOptions.CaCertPath
|
||||||
serverCertPath := authOptions.ServerCertPath
|
serverCertPath := authOptions.ServerCertPath
|
||||||
serverKeyPath := authOptions.ServerKeyPath
|
serverKeyPath := authOptions.ServerKeyPath
|
||||||
|
|
@ -213,22 +218,27 @@ func (xcg *X509CertGenerator) ValidateCertificate(addr string, authOptions *auth
|
||||||
log.Debugf("Reading CA certificate from %s", caCertPath)
|
log.Debugf("Reading CA certificate from %s", caCertPath)
|
||||||
caCert, err := ioutil.ReadFile(caCertPath)
|
caCert, err := ioutil.ReadFile(caCertPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Reading server certificate from %s", serverCertPath)
|
log.Debugf("Reading server certificate from %s", serverCertPath)
|
||||||
serverCert, err := ioutil.ReadFile(serverCertPath)
|
serverCert, err := ioutil.ReadFile(serverCertPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Reading server key from %s", serverKeyPath)
|
log.Debugf("Reading server key from %s", serverKeyPath)
|
||||||
serverKey, err := ioutil.ReadFile(serverKeyPath)
|
serverKey, err := ioutil.ReadFile(serverKeyPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsConfig, err := xcg.getTLSConfig(caCert, serverCert, serverKey, false)
|
return xcg.getTLSConfig(caCert, serverCert, serverKey, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateCertificate validate the certificate installed on the vm.
|
||||||
|
func (xcg *X509CertGenerator) ValidateCertificate(addr string, authOptions *auth.Options) (bool, error) {
|
||||||
|
tlsConfig, err := xcg.ReadTLSConfig(addr, authOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"crypto/tls"
|
||||||
|
|
||||||
"github.com/docker/machine/libmachine/auth"
|
"github.com/docker/machine/libmachine/auth"
|
||||||
"github.com/docker/machine/libmachine/cert"
|
"github.com/docker/machine/libmachine/cert"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
@ -30,6 +32,10 @@ func (fcg FakeCertGenerator) ValidateCertificate(addr string, authOptions *auth.
|
||||||
return fcg.fakeValidateCertificate.IsValid, fcg.fakeValidateCertificate.Err
|
return fcg.fakeValidateCertificate.IsValid, fcg.fakeValidateCertificate.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fcg FakeCertGenerator) ReadTLSConfig(addr string, authOptions *auth.Options) (*tls.Config, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func TestCheckCert(t *testing.T) {
|
func TestCheckCert(t *testing.T) {
|
||||||
errCertsExpired := errors.New("Certs have expired")
|
errCertsExpired := errors.New("Certs have expired")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/docker/machine/libmachine/drivers"
|
"github.com/docker/machine/libmachine/drivers"
|
||||||
"github.com/docker/machine/libmachine/engine"
|
"github.com/docker/machine/libmachine/engine"
|
||||||
"github.com/docker/machine/libmachine/log"
|
"github.com/docker/machine/libmachine/log"
|
||||||
|
"github.com/docker/machine/libmachine/mcndockerclient"
|
||||||
"github.com/docker/machine/libmachine/mcnutils"
|
"github.com/docker/machine/libmachine/mcnutils"
|
||||||
"github.com/docker/machine/libmachine/provision"
|
"github.com/docker/machine/libmachine/provision"
|
||||||
"github.com/docker/machine/libmachine/provision/pkgaction"
|
"github.com/docker/machine/libmachine/provision/pkgaction"
|
||||||
|
|
@ -145,10 +146,18 @@ func (h *Host) Upgrade() error {
|
||||||
return provisioner.Service("docker", serviceaction.Restart)
|
return provisioner.Service("docker", serviceaction.Restart)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Host) GetURL() (string, error) {
|
func (h *Host) URL() (string, error) {
|
||||||
return h.Driver.GetURL()
|
return h.Driver.GetURL()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Host) AuthOptions() *auth.Options {
|
||||||
|
return h.HostOptions.AuthOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Host) DockerVersion() (string, error) {
|
||||||
|
return mcndockerclient.DockerVersion(h)
|
||||||
|
}
|
||||||
|
|
||||||
func (h *Host) ConfigureAuth() error {
|
func (h *Host) ConfigureAuth() error {
|
||||||
provisioner, err := provision.DetectProvisioner(h.Driver)
|
provisioner, err := provision.DetectProvisioner(h.Driver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package mcndockerclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/docker/machine/libmachine/cert"
|
||||||
|
"github.com/samalba/dockerclient"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DockerClient(host DockerHost) (*dockerclient.DockerClient, error) {
|
||||||
|
url, err := host.URL()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsConfig, err := cert.ReadTLSConfig(url, host.AuthOptions())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to read TLS config: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dockerclient.NewDockerClient(url, tlsConfig)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package mcndockerclient
|
||||||
|
|
||||||
|
import "github.com/docker/machine/libmachine/auth"
|
||||||
|
|
||||||
|
type URLer interface {
|
||||||
|
URL() (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type AuthOptionser interface {
|
||||||
|
AuthOptions() *auth.Options
|
||||||
|
}
|
||||||
|
|
||||||
|
type DockerHost interface {
|
||||||
|
URLer
|
||||||
|
AuthOptionser
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
package mcndockerclient
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
var CurrentDockerVersioner DockerVersioner = &defaultDockerVersioner{}
|
||||||
|
|
||||||
|
type DockerVersioner interface {
|
||||||
|
DockerVersion(host DockerHost) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DockerVersion(host DockerHost) (string, error) {
|
||||||
|
return CurrentDockerVersioner.DockerVersion(host)
|
||||||
|
}
|
||||||
|
|
||||||
|
type defaultDockerVersioner struct{}
|
||||||
|
|
||||||
|
func (dv *defaultDockerVersioner) DockerVersion(host DockerHost) (string, error) {
|
||||||
|
client, err := DockerClient(host)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("Unable to query docker version: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
version, err := client.Version()
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("Unable to query docker version: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return version.Version, nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
package mcndockerclient
|
||||||
|
|
||||||
|
var originalDockerVersioner = CurrentDockerVersioner
|
||||||
|
|
||||||
|
func CleanupDockerVersioner() {
|
||||||
|
CurrentDockerVersioner = originalDockerVersioner
|
||||||
|
}
|
||||||
|
|
||||||
|
type FakeDockerVersioner struct {
|
||||||
|
Version string
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dv *FakeDockerVersioner) DockerVersion(host DockerHost) (string, error) {
|
||||||
|
if dv.Err != nil {
|
||||||
|
return "", dv.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
return dv.Version, nil
|
||||||
|
}
|
||||||
|
|
@ -238,7 +238,7 @@ func TestStoreLoad(t *testing.T) {
|
||||||
|
|
||||||
h.Driver = realDriver
|
h.Driver = realDriver
|
||||||
|
|
||||||
actualURL, err := h.GetURL()
|
actualURL, err := h.URL()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,12 @@ load ${BASE_TEST_DIR}/helpers.bash
|
||||||
[[ ${lines[0]} =~ "total" ]]
|
[[ ${lines[0]} =~ "total" ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "$DRIVER: version" {
|
||||||
|
run machine version $NAME
|
||||||
|
echo ${output}
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
@test "$DRIVER: docker commands with the socket should work" {
|
@test "$DRIVER: docker commands with the socket should work" {
|
||||||
run machine ssh $NAME -- sudo docker version
|
run machine ssh $NAME -- sudo docker version
|
||||||
echo ${output}
|
echo ${output}
|
||||||
|
|
@ -93,6 +99,14 @@ load ${BASE_TEST_DIR}/helpers.bash
|
||||||
[[ ${output} == *"not running. Please start"* ]]
|
[[ ${output} == *"not running. Please start"* ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "$DRIVER: version should show an error when machine is stopped" {
|
||||||
|
run machine version $NAME
|
||||||
|
echo ${output}
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ ${output} == *"not running"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@test "$DRIVER: machine should not allow upgrade when stopped" {
|
@test "$DRIVER: machine should not allow upgrade when stopped" {
|
||||||
run machine upgrade $NAME
|
run machine upgrade $NAME
|
||||||
echo ${output}
|
echo ${output}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
Victor Vieux <vieux@docker.com> (@vieux)
|
||||||
|
Jessie Frazelle <jess@docker.com> (@jfrazelle)
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
package units
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HumanDuration returns a human-readable approximation of a duration
|
||||||
|
// (eg. "About a minute", "4 hours ago", etc.)
|
||||||
|
func HumanDuration(d time.Duration) string {
|
||||||
|
if seconds := int(d.Seconds()); seconds < 1 {
|
||||||
|
return "Less than a second"
|
||||||
|
} else if seconds < 60 {
|
||||||
|
return fmt.Sprintf("%d seconds", seconds)
|
||||||
|
} else if minutes := int(d.Minutes()); minutes == 1 {
|
||||||
|
return "About a minute"
|
||||||
|
} else if minutes < 60 {
|
||||||
|
return fmt.Sprintf("%d minutes", minutes)
|
||||||
|
} else if hours := int(d.Hours()); hours == 1 {
|
||||||
|
return "About an hour"
|
||||||
|
} else if hours < 48 {
|
||||||
|
return fmt.Sprintf("%d hours", hours)
|
||||||
|
} else if hours < 24*7*2 {
|
||||||
|
return fmt.Sprintf("%d days", hours/24)
|
||||||
|
} else if hours < 24*30*3 {
|
||||||
|
return fmt.Sprintf("%d weeks", hours/24/7)
|
||||||
|
} else if hours < 24*365*2 {
|
||||||
|
return fmt.Sprintf("%d months", hours/24/30)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%f years", d.Hours()/24/365)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
package units
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// See: http://en.wikipedia.org/wiki/Binary_prefix
|
||||||
|
const (
|
||||||
|
// Decimal
|
||||||
|
|
||||||
|
KB = 1000
|
||||||
|
MB = 1000 * KB
|
||||||
|
GB = 1000 * MB
|
||||||
|
TB = 1000 * GB
|
||||||
|
PB = 1000 * TB
|
||||||
|
|
||||||
|
// Binary
|
||||||
|
|
||||||
|
KiB = 1024
|
||||||
|
MiB = 1024 * KiB
|
||||||
|
GiB = 1024 * MiB
|
||||||
|
TiB = 1024 * GiB
|
||||||
|
PiB = 1024 * TiB
|
||||||
|
)
|
||||||
|
|
||||||
|
type unitMap map[string]int64
|
||||||
|
|
||||||
|
var (
|
||||||
|
decimalMap = unitMap{"k": KB, "m": MB, "g": GB, "t": TB, "p": PB}
|
||||||
|
binaryMap = unitMap{"k": KiB, "m": MiB, "g": GiB, "t": TiB, "p": PiB}
|
||||||
|
sizeRegex = regexp.MustCompile(`^(\d+)([kKmMgGtTpP])?[bB]?$`)
|
||||||
|
)
|
||||||
|
|
||||||
|
var decimapAbbrs = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
|
||||||
|
var binaryAbbrs = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}
|
||||||
|
|
||||||
|
// HumanSize returns a human-readable approximation of a size
|
||||||
|
// using SI standard (eg. "44kB", "17MB")
|
||||||
|
func HumanSize(size float64) string {
|
||||||
|
return intToString(float64(size), 1000.0, decimapAbbrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BytesSize(size float64) string {
|
||||||
|
return intToString(size, 1024.0, binaryAbbrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func intToString(size, unit float64, _map []string) string {
|
||||||
|
i := 0
|
||||||
|
for size >= unit {
|
||||||
|
size = size / unit
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%.4g %s", size, _map[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromHumanSize returns an integer from a human-readable specification of a
|
||||||
|
// size using SI standard (eg. "44kB", "17MB")
|
||||||
|
func FromHumanSize(size string) (int64, error) {
|
||||||
|
return parseSize(size, decimalMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RAMInBytes parses a human-readable string representing an amount of RAM
|
||||||
|
// in bytes, kibibytes, mebibytes, gibibytes, or tebibytes and
|
||||||
|
// returns the number of bytes, or -1 if the string is unparseable.
|
||||||
|
// Units are case-insensitive, and the 'b' suffix is optional.
|
||||||
|
func RAMInBytes(size string) (int64, error) {
|
||||||
|
return parseSize(size, binaryMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parses the human-readable size string into the amount it represents
|
||||||
|
func parseSize(sizeStr string, uMap unitMap) (int64, error) {
|
||||||
|
matches := sizeRegex.FindStringSubmatch(sizeStr)
|
||||||
|
if len(matches) != 3 {
|
||||||
|
return -1, fmt.Errorf("invalid size: '%s'", sizeStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
size, err := strconv.ParseInt(matches[1], 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
|
||||||
|
unitPrefix := strings.ToLower(matches[2])
|
||||||
|
if mul, ok := uMap[unitPrefix]; ok {
|
||||||
|
size *= mul
|
||||||
|
}
|
||||||
|
|
||||||
|
return size, nil
|
||||||
|
}
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
Copyright (c) 2009 The Go 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.
|
|
||||||
* Neither the name of Google Inc. nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
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
|
|
||||||
OWNER 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.
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
Additional IP Rights Grant (Patents)
|
|
||||||
|
|
||||||
"This implementation" means the copyrightable works distributed by
|
|
||||||
Google as part of the Go project.
|
|
||||||
|
|
||||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
|
||||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
|
||||||
patent license to make, have made, use, offer to sell, sell, import,
|
|
||||||
transfer and otherwise run, modify and propagate the contents of this
|
|
||||||
implementation of Go, where such license applies only to those patent
|
|
||||||
claims, both currently owned or controlled by Google and acquired in
|
|
||||||
the future, licensable by Google that are necessarily infringed by this
|
|
||||||
implementation of Go. This grant does not include claims that would be
|
|
||||||
infringed only as a consequence of further modification of this
|
|
||||||
implementation. If you or your agent or exclusive licensee institute or
|
|
||||||
order or agree to the institution of patent litigation against any
|
|
||||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
|
||||||
that this implementation of Go or any code incorporated within this
|
|
||||||
implementation of Go constitutes direct or contributory patent
|
|
||||||
infringement, or inducement of patent infringement, then any patent
|
|
||||||
rights granted to you under this License for this implementation of Go
|
|
||||||
shall terminate as of the date such litigation is filed.
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2014 Simon Eskildsen
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
191
vendor/github.com/docker/docker/vendor/src/github.com/coreos/go-systemd/LICENSE
generated
vendored
191
vendor/github.com/docker/docker/vendor/src/github.com/coreos/go-systemd/LICENSE
generated
vendored
|
|
@ -1,191 +0,0 @@
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction, and
|
|
||||||
distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright
|
|
||||||
owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all other entities
|
|
||||||
that control, are controlled by, or are under common control with that entity.
|
|
||||||
For the purposes of this definition, "control" means (i) the power, direct or
|
|
||||||
indirect, to cause the direction or management of such entity, whether by
|
|
||||||
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity exercising
|
|
||||||
permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications, including
|
|
||||||
but not limited to software source code, documentation source, and configuration
|
|
||||||
files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical transformation or
|
|
||||||
translation of a Source form, including but not limited to compiled object code,
|
|
||||||
generated documentation, and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or Object form, made
|
|
||||||
available under the License, as indicated by a copyright notice that is included
|
|
||||||
in or attached to the work (an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object form, that
|
|
||||||
is based on (or derived from) the Work and for which the editorial revisions,
|
|
||||||
annotations, elaborations, or other modifications represent, as a whole, an
|
|
||||||
original work of authorship. For the purposes of this License, Derivative Works
|
|
||||||
shall not include works that remain separable from, or merely link (or bind by
|
|
||||||
name) to the interfaces of, the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including the original version
|
|
||||||
of the Work and any modifications or additions to that Work or Derivative Works
|
|
||||||
thereof, that is intentionally submitted to Licensor for inclusion in the Work
|
|
||||||
by the copyright owner or by an individual or Legal Entity authorized to submit
|
|
||||||
on behalf of the copyright owner. For the purposes of this definition,
|
|
||||||
"submitted" means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems, and
|
|
||||||
issue tracking systems that are managed by, or on behalf of, the Licensor for
|
|
||||||
the purpose of discussing and improving the Work, but excluding communication
|
|
||||||
that is conspicuously marked or otherwise designated in writing by the copyright
|
|
||||||
owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
|
|
||||||
of whom a Contribution has been received by Licensor and subsequently
|
|
||||||
incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License.
|
|
||||||
|
|
||||||
Subject to the terms and conditions of this License, each Contributor hereby
|
|
||||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
|
||||||
irrevocable copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the Work and such
|
|
||||||
Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License.
|
|
||||||
|
|
||||||
Subject to the terms and conditions of this License, each Contributor hereby
|
|
||||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
|
||||||
irrevocable (except as stated in this section) patent license to make, have
|
|
||||||
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
|
|
||||||
such license applies only to those patent claims licensable by such Contributor
|
|
||||||
that are necessarily infringed by their Contribution(s) alone or by combination
|
|
||||||
of their Contribution(s) with the Work to which such Contribution(s) was
|
|
||||||
submitted. If You institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
|
|
||||||
Contribution incorporated within the Work constitutes direct or contributory
|
|
||||||
patent infringement, then any patent licenses granted to You under this License
|
|
||||||
for that Work shall terminate as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution.
|
|
||||||
|
|
||||||
You may reproduce and distribute copies of the Work or Derivative Works thereof
|
|
||||||
in any medium, with or without modifications, and in Source or Object form,
|
|
||||||
provided that You meet the following conditions:
|
|
||||||
|
|
||||||
You must give any other recipients of the Work or Derivative Works a copy of
|
|
||||||
this License; and
|
|
||||||
You must cause any modified files to carry prominent notices stating that You
|
|
||||||
changed the files; and
|
|
||||||
You must retain, in the Source form of any Derivative Works that You distribute,
|
|
||||||
all copyright, patent, trademark, and attribution notices from the Source form
|
|
||||||
of the Work, excluding those notices that do not pertain to any part of the
|
|
||||||
Derivative Works; and
|
|
||||||
If the Work includes a "NOTICE" text file as part of its distribution, then any
|
|
||||||
Derivative Works that You distribute must include a readable copy of the
|
|
||||||
attribution notices contained within such NOTICE file, excluding those notices
|
|
||||||
that do not pertain to any part of the Derivative Works, in at least one of the
|
|
||||||
following places: within a NOTICE text file distributed as part of the
|
|
||||||
Derivative Works; within the Source form or documentation, if provided along
|
|
||||||
with the Derivative Works; or, within a display generated by the Derivative
|
|
||||||
Works, if and wherever such third-party notices normally appear. The contents of
|
|
||||||
the NOTICE file are for informational purposes only and do not modify the
|
|
||||||
License. You may add Your own attribution notices within Derivative Works that
|
|
||||||
You distribute, alongside or as an addendum to the NOTICE text from the Work,
|
|
||||||
provided that such additional attribution notices cannot be construed as
|
|
||||||
modifying the License.
|
|
||||||
You may add Your own copyright statement to Your modifications and may provide
|
|
||||||
additional or different license terms and conditions for use, reproduction, or
|
|
||||||
distribution of Your modifications, or for any such Derivative Works as a whole,
|
|
||||||
provided Your use, reproduction, and distribution of the Work otherwise complies
|
|
||||||
with the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions.
|
|
||||||
|
|
||||||
Unless You explicitly state otherwise, any Contribution intentionally submitted
|
|
||||||
for inclusion in the Work by You to the Licensor shall be under the terms and
|
|
||||||
conditions of this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify the terms of
|
|
||||||
any separate license agreement you may have executed with Licensor regarding
|
|
||||||
such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks.
|
|
||||||
|
|
||||||
This License does not grant permission to use the trade names, trademarks,
|
|
||||||
service marks, or product names of the Licensor, except as required for
|
|
||||||
reasonable and customary use in describing the origin of the Work and
|
|
||||||
reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty.
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, Licensor provides the
|
|
||||||
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
|
|
||||||
including, without limitation, any warranties or conditions of TITLE,
|
|
||||||
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
|
|
||||||
solely responsible for determining the appropriateness of using or
|
|
||||||
redistributing the Work and assume any risks associated with Your exercise of
|
|
||||||
permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability.
|
|
||||||
|
|
||||||
In no event and under no legal theory, whether in tort (including negligence),
|
|
||||||
contract, or otherwise, unless required by applicable law (such as deliberate
|
|
||||||
and grossly negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special, incidental,
|
|
||||||
or consequential damages of any character arising as a result of this License or
|
|
||||||
out of the use or inability to use the Work (including but not limited to
|
|
||||||
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
|
|
||||||
any and all other commercial damages or losses), even if such Contributor has
|
|
||||||
been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability.
|
|
||||||
|
|
||||||
While redistributing the Work or Derivative Works thereof, You may choose to
|
|
||||||
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
|
|
||||||
other liability obligations and/or rights consistent with this License. However,
|
|
||||||
in accepting such obligations, You may act only on Your own behalf and on Your
|
|
||||||
sole responsibility, not on behalf of any other Contributor, and only if You
|
|
||||||
agree to indemnify, defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason of your
|
|
||||||
accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following boilerplate
|
|
||||||
notice, with the fields enclosed by brackets "[]" replaced with your own
|
|
||||||
identifying information. (Don't include the brackets!) The text should be
|
|
||||||
enclosed in the appropriate comment syntax for the file format. We also
|
|
||||||
recommend that a file or class name and description of purpose be included on
|
|
||||||
the same "printed page" as the copyright notice for easier identification within
|
|
||||||
third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
191
vendor/github.com/docker/docker/vendor/src/github.com/docker/libcontainer/LICENSE
generated
vendored
191
vendor/github.com/docker/docker/vendor/src/github.com/docker/libcontainer/LICENSE
generated
vendored
|
|
@ -1,191 +0,0 @@
|
||||||
|
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
Copyright 2014 Docker, Inc.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
16
vendor/github.com/docker/docker/vendor/src/github.com/docker/libcontainer/NOTICE
generated
vendored
16
vendor/github.com/docker/docker/vendor/src/github.com/docker/libcontainer/NOTICE
generated
vendored
|
|
@ -1,16 +0,0 @@
|
||||||
libcontainer
|
|
||||||
Copyright 2012-2014 Docker, Inc.
|
|
||||||
|
|
||||||
This product includes software developed at Docker, Inc. (http://www.docker.com).
|
|
||||||
|
|
||||||
The following is courtesy of our legal counsel:
|
|
||||||
|
|
||||||
|
|
||||||
Use and transfer of Docker may be subject to certain restrictions by the
|
|
||||||
United States and other governments.
|
|
||||||
It is your responsibility to ensure that your use and/or transfer does not
|
|
||||||
violate applicable laws.
|
|
||||||
|
|
||||||
For more information, please see http://www.bis.doc.gov
|
|
||||||
|
|
||||||
See also http://www.apache.org/dev/crypto.html and/or seek legal counsel.
|
|
||||||
28
vendor/github.com/docker/docker/vendor/src/github.com/go-fsnotify/fsnotify/LICENSE
generated
vendored
28
vendor/github.com/docker/docker/vendor/src/github.com/go-fsnotify/fsnotify/LICENSE
generated
vendored
|
|
@ -1,28 +0,0 @@
|
||||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
|
||||||
Copyright (c) 2012 fsnotify 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.
|
|
||||||
* Neither the name of Google Inc. nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
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
|
|
||||||
OWNER 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.
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
Copyright (c) 2013, Georg Reinke (<guelfey at gmail dot com>)
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions
|
|
||||||
are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. 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.
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
Copyright (c) 2012 Rodrigo Moraes. 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.
|
|
||||||
* Neither the name of Google Inc. nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
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
|
|
||||||
OWNER 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.
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
Copyright (c) 2012 Rodrigo Moraes. 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.
|
|
||||||
* Neither the name of Google Inc. nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
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
|
|
||||||
OWNER 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.
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
Copyright (c) 2011 Keith Rarick
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person
|
|
||||||
obtaining a copy of this software and associated
|
|
||||||
documentation files (the "Software"), to deal in the
|
|
||||||
Software without restriction, including without limitation
|
|
||||||
the rights to use, copy, modify, merge, publish, distribute,
|
|
||||||
sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so,
|
|
||||||
subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall
|
|
||||||
be included in all copies or substantial portions of the
|
|
||||||
Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
|
||||||
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
||||||
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
|
||||||
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
||||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
||||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
24
vendor/github.com/docker/docker/vendor/src/github.com/syndtr/gocapability/LICENSE
generated
vendored
24
vendor/github.com/docker/docker/vendor/src/github.com/syndtr/gocapability/LICENSE
generated
vendored
|
|
@ -1,24 +0,0 @@
|
||||||
Copyright 2013 Suryandaru Triandana <syndtr@gmail.com>
|
|
||||||
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.
|
|
||||||
20
vendor/github.com/docker/docker/vendor/src/github.com/tchap/go-patricia/LICENSE
generated
vendored
20
vendor/github.com/docker/docker/vendor/src/github.com/tchap/go-patricia/LICENSE
generated
vendored
|
|
@ -1,20 +0,0 @@
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2014 The AUTHORS
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
||||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
||||||
subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
||||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
||||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Folders
|
||||||
|
_obj
|
||||||
|
_test
|
||||||
|
|
||||||
|
# Architecture specific extensions/prefixes
|
||||||
|
*.[568vq]
|
||||||
|
[568vq].out
|
||||||
|
|
||||||
|
*.cgo1.go
|
||||||
|
*.cgo2.c
|
||||||
|
_cgo_defun.c
|
||||||
|
_cgo_gotypes.go
|
||||||
|
_cgo_export.*
|
||||||
|
|
||||||
|
_testmain.go
|
||||||
|
|
||||||
|
*.exe
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
Apache License
|
Apache License
|
||||||
Version 2.0, January 2004
|
Version 2.0, January 2004
|
||||||
http://www.apache.org/licenses/
|
http://www.apache.org/licenses/
|
||||||
|
|
@ -176,7 +175,18 @@
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
Copyright 2014 Docker, Inc.
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright 2014 Sam Alba <sam.alba@gmail.com>
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
@ -189,3 +199,4 @@
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
Docker client library in Go
|
||||||
|
===========================
|
||||||
|
[](http://godoc.org/github.com/samalba/dockerclient)
|
||||||
|
|
||||||
|
Well maintained docker client library.
|
||||||
|
|
||||||
|
# How to use it?
|
||||||
|
|
||||||
|
Here is an example showing how to use it:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/samalba/dockerclient"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Callback used to listen to Docker's events
|
||||||
|
func eventCallback(event *dockerclient.Event, ec chan error, args ...interface{}) {
|
||||||
|
log.Printf("Received event: %#v\n", *event)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Init the client
|
||||||
|
docker, _ := dockerclient.NewDockerClient("unix:///var/run/docker.sock", nil)
|
||||||
|
|
||||||
|
// Get only running containers
|
||||||
|
containers, err := docker.ListContainers(false, false, "")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
for _, c := range containers {
|
||||||
|
log.Println(c.Id, c.Names)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inspect the first container returned
|
||||||
|
if len(containers) > 0 {
|
||||||
|
id := containers[0].Id
|
||||||
|
info, _ := docker.InspectContainer(id)
|
||||||
|
log.Println(info)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build a docker image
|
||||||
|
// some.tar contains the build context (Dockerfile any any files it needs to add/copy)
|
||||||
|
dockerBuildContext, err := os.Open("some.tar")
|
||||||
|
defer dockerBuildContext.Close()
|
||||||
|
buildImageConfig := &dockerclient.BuildImage{
|
||||||
|
Context: dockerBuildContext,
|
||||||
|
RepoName: "your_image_name",
|
||||||
|
SuppressOutput: false,
|
||||||
|
}
|
||||||
|
reader, err := docker.BuildImage(buildImageConfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a container
|
||||||
|
containerConfig := &dockerclient.ContainerConfig{
|
||||||
|
Image: "ubuntu:14.04",
|
||||||
|
Cmd: []string{"bash"},
|
||||||
|
AttachStdin: true,
|
||||||
|
Tty: true}
|
||||||
|
containerId, err := docker.CreateContainer(containerConfig, "foobar")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the container
|
||||||
|
hostConfig := &dockerclient.HostConfig{}
|
||||||
|
err = docker.StartContainer(containerId, hostConfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the container (with 5 seconds timeout)
|
||||||
|
docker.StopContainer(containerId, 5)
|
||||||
|
|
||||||
|
// Listen to events
|
||||||
|
docker.StartMonitorEvents(eventCallback, nil)
|
||||||
|
|
||||||
|
// Hold the execution to look at the events coming
|
||||||
|
time.Sleep(3600 * time.Second)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Maintainers
|
||||||
|
|
||||||
|
List of people you can ping for feedback on Pull Requests or any questions.
|
||||||
|
|
||||||
|
- [Sam Alba](https://github.com/samalba)
|
||||||
|
- [Michael Crosby](https://github.com/crosbymichael)
|
||||||
|
- [Andrea Luzzardi](https://github.com/aluzzardi)
|
||||||
|
- [Victor Vieux](https://github.com/vieux)
|
||||||
|
- [Evan Hazlett](https://github.com/ehazlett)
|
||||||
|
- [Donald Huang](https://github.com/donhcd)
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
package dockerclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AuthConfig hold parameters for authenticating with the docker registry
|
||||||
|
type AuthConfig struct {
|
||||||
|
Username string `json:"username,omitempty"`
|
||||||
|
Password string `json:"password,omitempty"`
|
||||||
|
Email string `json:"email,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode the auth configuration struct into base64 for the X-Registry-Auth header
|
||||||
|
func (c *AuthConfig) encode() (string, error) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := json.NewEncoder(&buf).Encode(c); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return base64.URLEncoding.EncodeToString(buf.Bytes()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigFile holds parameters for authenticating during a BuildImage request
|
||||||
|
type ConfigFile struct {
|
||||||
|
Configs map[string]AuthConfig `json:"configs,omitempty"`
|
||||||
|
rootPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode the configuration struct into base64 for the X-Registry-Config header
|
||||||
|
func (c *ConfigFile) encode() (string, error) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := json.NewEncoder(&buf).Encode(c); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return base64.URLEncoding.EncodeToString(buf.Bytes()), nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,930 @@
|
||||||
|
package dockerclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/tls"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
APIVersion = "v1.15"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrImageNotFound = errors.New("Image not found")
|
||||||
|
ErrNotFound = errors.New("Not found")
|
||||||
|
|
||||||
|
defaultTimeout = 30 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
|
type DockerClient struct {
|
||||||
|
URL *url.URL
|
||||||
|
HTTPClient *http.Client
|
||||||
|
TLSConfig *tls.Config
|
||||||
|
monitorStats int32
|
||||||
|
eventStopChan chan (struct{})
|
||||||
|
}
|
||||||
|
|
||||||
|
type Error struct {
|
||||||
|
StatusCode int
|
||||||
|
Status string
|
||||||
|
msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e Error) Error() string {
|
||||||
|
return fmt.Sprintf("%s: %s", e.Status, e.msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDockerClient(daemonUrl string, tlsConfig *tls.Config) (*DockerClient, error) {
|
||||||
|
return NewDockerClientTimeout(daemonUrl, tlsConfig, time.Duration(defaultTimeout))
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDockerClientTimeout(daemonUrl string, tlsConfig *tls.Config, timeout time.Duration) (*DockerClient, error) {
|
||||||
|
u, err := url.Parse(daemonUrl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if u.Scheme == "" || u.Scheme == "tcp" {
|
||||||
|
if tlsConfig == nil {
|
||||||
|
u.Scheme = "http"
|
||||||
|
} else {
|
||||||
|
u.Scheme = "https"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
httpClient := newHTTPClient(u, tlsConfig, timeout)
|
||||||
|
return &DockerClient{u, httpClient, tlsConfig, 0, nil}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) doRequest(method string, path string, body []byte, headers map[string]string) ([]byte, error) {
|
||||||
|
b := bytes.NewBuffer(body)
|
||||||
|
|
||||||
|
reader, err := client.doStreamRequest(method, path, b, headers)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer reader.Close()
|
||||||
|
data, err := ioutil.ReadAll(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) doStreamRequest(method string, path string, in io.Reader, headers map[string]string) (io.ReadCloser, error) {
|
||||||
|
if (method == "POST" || method == "PUT") && in == nil {
|
||||||
|
in = bytes.NewReader(nil)
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest(method, client.URL.String()+path, in)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.Header.Add("Content-Type", "application/json")
|
||||||
|
if headers != nil {
|
||||||
|
for header, value := range headers {
|
||||||
|
req.Header.Add(header, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resp, err := client.HTTPClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
if !strings.Contains(err.Error(), "connection refused") && client.TLSConfig == nil {
|
||||||
|
return nil, fmt.Errorf("%v. Are you trying to connect to a TLS-enabled daemon without TLS?", err)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode == 404 {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
data, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, ErrNotFound
|
||||||
|
}
|
||||||
|
if len(data) > 0 {
|
||||||
|
// check if is image not found error
|
||||||
|
if strings.Index(string(data), "No such image") != -1 {
|
||||||
|
return nil, ErrImageNotFound
|
||||||
|
}
|
||||||
|
return nil, errors.New(string(data))
|
||||||
|
}
|
||||||
|
return nil, ErrNotFound
|
||||||
|
}
|
||||||
|
if resp.StatusCode >= 400 {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
data, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, Error{StatusCode: resp.StatusCode, Status: resp.Status, msg: string(data)}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp.Body, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) Info() (*Info, error) {
|
||||||
|
uri := fmt.Sprintf("/%s/info", APIVersion)
|
||||||
|
data, err := client.doRequest("GET", uri, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ret := &Info{}
|
||||||
|
err = json.Unmarshal(data, &ret)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) ListContainers(all bool, size bool, filters string) ([]Container, error) {
|
||||||
|
argAll := 0
|
||||||
|
if all == true {
|
||||||
|
argAll = 1
|
||||||
|
}
|
||||||
|
showSize := 0
|
||||||
|
if size == true {
|
||||||
|
showSize = 1
|
||||||
|
}
|
||||||
|
uri := fmt.Sprintf("/%s/containers/json?all=%d&size=%d", APIVersion, argAll, showSize)
|
||||||
|
|
||||||
|
if filters != "" {
|
||||||
|
uri += "&filters=" + filters
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := client.doRequest("GET", uri, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ret := []Container{}
|
||||||
|
err = json.Unmarshal(data, &ret)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) InspectContainer(id string) (*ContainerInfo, error) {
|
||||||
|
uri := fmt.Sprintf("/%s/containers/%s/json", APIVersion, id)
|
||||||
|
data, err := client.doRequest("GET", uri, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
info := &ContainerInfo{}
|
||||||
|
err = json.Unmarshal(data, info)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) CreateContainer(config *ContainerConfig, name string) (string, error) {
|
||||||
|
data, err := json.Marshal(config)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
uri := fmt.Sprintf("/%s/containers/create", APIVersion)
|
||||||
|
if name != "" {
|
||||||
|
v := url.Values{}
|
||||||
|
v.Set("name", name)
|
||||||
|
uri = fmt.Sprintf("%s?%s", uri, v.Encode())
|
||||||
|
}
|
||||||
|
data, err = client.doRequest("POST", uri, data, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
result := &RespContainersCreate{}
|
||||||
|
err = json.Unmarshal(data, result)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return result.Id, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) ContainerLogs(id string, options *LogOptions) (io.ReadCloser, error) {
|
||||||
|
v := url.Values{}
|
||||||
|
v.Add("follow", strconv.FormatBool(options.Follow))
|
||||||
|
v.Add("stdout", strconv.FormatBool(options.Stdout))
|
||||||
|
v.Add("stderr", strconv.FormatBool(options.Stderr))
|
||||||
|
v.Add("timestamps", strconv.FormatBool(options.Timestamps))
|
||||||
|
if options.Tail > 0 {
|
||||||
|
v.Add("tail", strconv.FormatInt(options.Tail, 10))
|
||||||
|
}
|
||||||
|
|
||||||
|
uri := fmt.Sprintf("/%s/containers/%s/logs?%s", APIVersion, id, v.Encode())
|
||||||
|
req, err := http.NewRequest("GET", client.URL.String()+uri, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.Header.Add("Content-Type", "application/json")
|
||||||
|
resp, err := client.HTTPClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp.Body, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) ContainerChanges(id string) ([]*ContainerChanges, error) {
|
||||||
|
uri := fmt.Sprintf("/%s/containers/%s/changes", APIVersion, id)
|
||||||
|
data, err := client.doRequest("GET", uri, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
changes := []*ContainerChanges{}
|
||||||
|
err = json.Unmarshal(data, &changes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return changes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) readJSONStream(stream io.ReadCloser, decode func(*json.Decoder) decodingResult, stopChan <-chan struct{}) <-chan decodingResult {
|
||||||
|
resultChan := make(chan decodingResult)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
decodeChan := make(chan decodingResult)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
decoder := json.NewDecoder(stream)
|
||||||
|
for {
|
||||||
|
decodeResult := decode(decoder)
|
||||||
|
decodeChan <- decodeResult
|
||||||
|
if decodeResult.err != nil {
|
||||||
|
close(decodeChan)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer close(resultChan)
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-stopChan:
|
||||||
|
stream.Close()
|
||||||
|
for range decodeChan {
|
||||||
|
}
|
||||||
|
return
|
||||||
|
case decodeResult := <-decodeChan:
|
||||||
|
resultChan <- decodeResult
|
||||||
|
if decodeResult.err != nil {
|
||||||
|
stream.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}()
|
||||||
|
|
||||||
|
return resultChan
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) ExecCreate(config *ExecConfig) (string, error) {
|
||||||
|
data, err := json.Marshal(config)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
uri := fmt.Sprintf("/%s/containers/%s/exec", APIVersion, config.Container)
|
||||||
|
resp, err := client.doRequest("POST", uri, data, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
var createExecResp struct {
|
||||||
|
Id string
|
||||||
|
}
|
||||||
|
if err = json.Unmarshal(resp, &createExecResp); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return createExecResp.Id, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) ExecStart(id string, config *ExecConfig) error {
|
||||||
|
data, err := json.Marshal(config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
uri := fmt.Sprintf("/%s/exec/%s/start", APIVersion, id)
|
||||||
|
if _, err := client.doRequest("POST", uri, data, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) ExecResize(id string, width, height int) error {
|
||||||
|
v := url.Values{}
|
||||||
|
|
||||||
|
w := strconv.Itoa(width)
|
||||||
|
h := strconv.Itoa(height)
|
||||||
|
|
||||||
|
v.Set("w", w)
|
||||||
|
v.Set("h", h)
|
||||||
|
|
||||||
|
uri := fmt.Sprintf("/%s/exec/%s/resize?%s", APIVersion, id, v.Encode())
|
||||||
|
if _, err := client.doRequest("POST", client.URL.String()+uri, nil, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) AttachContainer(id string, options *AttachOptions) (io.ReadCloser, error) {
|
||||||
|
v := url.Values{}
|
||||||
|
if options != nil {
|
||||||
|
if options.Logs {
|
||||||
|
v.Set("logs", "1")
|
||||||
|
}
|
||||||
|
if options.Stream {
|
||||||
|
v.Set("stream", "1")
|
||||||
|
}
|
||||||
|
if options.Stdin {
|
||||||
|
v.Set("stdin", "1")
|
||||||
|
}
|
||||||
|
if options.Stdout {
|
||||||
|
v.Set("stdout", "1")
|
||||||
|
}
|
||||||
|
if options.Stderr {
|
||||||
|
v.Set("stderr", "1")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uri := fmt.Sprintf("/%s/containers/%s/attach?%s", APIVersion, id, v.Encode())
|
||||||
|
return client.doStreamRequest("POST", uri, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) StartContainer(id string, config *HostConfig) error {
|
||||||
|
data, err := json.Marshal(config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
uri := fmt.Sprintf("/%s/containers/%s/start", APIVersion, id)
|
||||||
|
_, err = client.doRequest("POST", uri, data, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) StopContainer(id string, timeout int) error {
|
||||||
|
uri := fmt.Sprintf("/%s/containers/%s/stop?t=%d", APIVersion, id, timeout)
|
||||||
|
_, err := client.doRequest("POST", uri, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) RestartContainer(id string, timeout int) error {
|
||||||
|
uri := fmt.Sprintf("/%s/containers/%s/restart?t=%d", APIVersion, id, timeout)
|
||||||
|
_, err := client.doRequest("POST", uri, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) KillContainer(id, signal string) error {
|
||||||
|
uri := fmt.Sprintf("/%s/containers/%s/kill?signal=%s", APIVersion, id, signal)
|
||||||
|
_, err := client.doRequest("POST", uri, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) Wait(id string) <-chan WaitResult {
|
||||||
|
ch := make(chan WaitResult)
|
||||||
|
uri := fmt.Sprintf("/%s/containers/%s/wait", APIVersion, id)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
data, err := client.doRequest("POST", uri, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
ch <- WaitResult{ExitCode: -1, Error: err}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var result struct {
|
||||||
|
StatusCode int `json:"StatusCode"`
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(data, &result)
|
||||||
|
ch <- WaitResult{ExitCode: result.StatusCode, Error: err}
|
||||||
|
}()
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) MonitorEvents(options *MonitorEventsOptions, stopChan <-chan struct{}) (<-chan EventOrError, error) {
|
||||||
|
v := url.Values{}
|
||||||
|
if options != nil {
|
||||||
|
if options.Since != 0 {
|
||||||
|
v.Add("since", strconv.Itoa(options.Since))
|
||||||
|
}
|
||||||
|
if options.Until != 0 {
|
||||||
|
v.Add("until", strconv.Itoa(options.Until))
|
||||||
|
}
|
||||||
|
if options.Filters != nil {
|
||||||
|
filterMap := make(map[string][]string)
|
||||||
|
if len(options.Filters.Event) > 0 {
|
||||||
|
filterMap["event"] = []string{options.Filters.Event}
|
||||||
|
}
|
||||||
|
if len(options.Filters.Image) > 0 {
|
||||||
|
filterMap["image"] = []string{options.Filters.Image}
|
||||||
|
}
|
||||||
|
if len(options.Filters.Container) > 0 {
|
||||||
|
filterMap["container"] = []string{options.Filters.Container}
|
||||||
|
}
|
||||||
|
if len(filterMap) > 0 {
|
||||||
|
filterJSONBytes, err := json.Marshal(filterMap)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
v.Add("filters", string(filterJSONBytes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uri := fmt.Sprintf("%s/%s/events?%s", client.URL.String(), APIVersion, v.Encode())
|
||||||
|
resp, err := client.HTTPClient.Get(uri)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
decode := func(decoder *json.Decoder) decodingResult {
|
||||||
|
var event Event
|
||||||
|
if err := decoder.Decode(&event); err != nil {
|
||||||
|
return decodingResult{err: err}
|
||||||
|
} else {
|
||||||
|
return decodingResult{result: event}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
decodingResultChan := client.readJSONStream(resp.Body, decode, stopChan)
|
||||||
|
eventOrErrorChan := make(chan EventOrError)
|
||||||
|
go func() {
|
||||||
|
for decodingResult := range decodingResultChan {
|
||||||
|
event, _ := decodingResult.result.(Event)
|
||||||
|
eventOrErrorChan <- EventOrError{
|
||||||
|
Event: event,
|
||||||
|
Error: decodingResult.err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(eventOrErrorChan)
|
||||||
|
}()
|
||||||
|
return eventOrErrorChan, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) StartMonitorEvents(cb Callback, ec chan error, args ...interface{}) {
|
||||||
|
client.eventStopChan = make(chan struct{})
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
eventErrChan, err := client.MonitorEvents(nil, client.eventStopChan)
|
||||||
|
if err != nil {
|
||||||
|
if ec != nil {
|
||||||
|
ec <- err
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for e := range eventErrChan {
|
||||||
|
if e.Error != nil {
|
||||||
|
if ec != nil {
|
||||||
|
ec <- err
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cb(&e.Event, ec, args...)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) StopAllMonitorEvents() {
|
||||||
|
close(client.eventStopChan)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) StartMonitorStats(id string, cb StatCallback, ec chan error, args ...interface{}) {
|
||||||
|
atomic.StoreInt32(&client.monitorStats, 1)
|
||||||
|
go client.getStats(id, cb, ec, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) getStats(id string, cb StatCallback, ec chan error, args ...interface{}) {
|
||||||
|
uri := fmt.Sprintf("%s/%s/containers/%s/stats", client.URL.String(), APIVersion, id)
|
||||||
|
resp, err := client.HTTPClient.Get(uri)
|
||||||
|
if err != nil {
|
||||||
|
ec <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
dec := json.NewDecoder(resp.Body)
|
||||||
|
for atomic.LoadInt32(&client.monitorStats) > 0 {
|
||||||
|
var stats *Stats
|
||||||
|
if err := dec.Decode(&stats); err != nil {
|
||||||
|
ec <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cb(id, stats, ec, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) StopAllMonitorStats() {
|
||||||
|
atomic.StoreInt32(&client.monitorStats, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) TagImage(nameOrID string, repo string, tag string, force bool) error {
|
||||||
|
v := url.Values{}
|
||||||
|
v.Set("repo", repo)
|
||||||
|
v.Set("tag", tag)
|
||||||
|
if force {
|
||||||
|
v.Set("force", "1")
|
||||||
|
}
|
||||||
|
uri := fmt.Sprintf("/%s/images/%s/tag?%s", APIVersion, nameOrID, v.Encode())
|
||||||
|
if _, err := client.doRequest("POST", uri, nil, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) Version() (*Version, error) {
|
||||||
|
uri := fmt.Sprintf("/%s/version", APIVersion)
|
||||||
|
data, err := client.doRequest("GET", uri, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
version := &Version{}
|
||||||
|
err = json.Unmarshal(data, version)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return version, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) PushImage(name string, tag string, auth *AuthConfig) error {
|
||||||
|
v := url.Values{}
|
||||||
|
if tag != "" {
|
||||||
|
v.Set("tag", tag)
|
||||||
|
}
|
||||||
|
uri := fmt.Sprintf("/%s/images/%s/push?%s", APIVersion, url.QueryEscape(name), v.Encode())
|
||||||
|
req, err := http.NewRequest("POST", client.URL.String()+uri, nil)
|
||||||
|
if auth != nil {
|
||||||
|
if encodedAuth, err := auth.encode(); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
req.Header.Add("X-Registry-Auth", encodedAuth)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resp, err := client.HTTPClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
var finalObj map[string]interface{}
|
||||||
|
for decoder := json.NewDecoder(resp.Body); err == nil; err = decoder.Decode(&finalObj) {
|
||||||
|
}
|
||||||
|
if err != io.EOF {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err, ok := finalObj["error"]; ok {
|
||||||
|
return fmt.Errorf("%v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) PullImage(name string, auth *AuthConfig) error {
|
||||||
|
v := url.Values{}
|
||||||
|
v.Set("fromImage", name)
|
||||||
|
uri := fmt.Sprintf("/%s/images/create?%s", APIVersion, v.Encode())
|
||||||
|
req, err := http.NewRequest("POST", client.URL.String()+uri, nil)
|
||||||
|
if auth != nil {
|
||||||
|
encoded_auth, err := auth.encode()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.Header.Add("X-Registry-Auth", encoded_auth)
|
||||||
|
}
|
||||||
|
resp, err := client.HTTPClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if resp.StatusCode == 404 {
|
||||||
|
return ErrNotFound
|
||||||
|
}
|
||||||
|
if resp.StatusCode >= 400 {
|
||||||
|
data, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return fmt.Errorf("%s", string(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
var finalObj map[string]interface{}
|
||||||
|
for decoder := json.NewDecoder(resp.Body); err == nil; err = decoder.Decode(&finalObj) {
|
||||||
|
}
|
||||||
|
if err != io.EOF {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err, ok := finalObj["error"]; ok {
|
||||||
|
return fmt.Errorf("%v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) InspectImage(id string) (*ImageInfo, error) {
|
||||||
|
uri := fmt.Sprintf("/%s/images/%s/json", APIVersion, id)
|
||||||
|
data, err := client.doRequest("GET", uri, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
info := &ImageInfo{}
|
||||||
|
err = json.Unmarshal(data, info)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) LoadImage(reader io.Reader) error {
|
||||||
|
data, err := ioutil.ReadAll(reader)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
uri := fmt.Sprintf("/%s/images/load", APIVersion)
|
||||||
|
_, err = client.doRequest("POST", uri, data, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) RemoveContainer(id string, force, volumes bool) error {
|
||||||
|
argForce := 0
|
||||||
|
argVolumes := 0
|
||||||
|
if force == true {
|
||||||
|
argForce = 1
|
||||||
|
}
|
||||||
|
if volumes == true {
|
||||||
|
argVolumes = 1
|
||||||
|
}
|
||||||
|
args := fmt.Sprintf("force=%d&v=%d", argForce, argVolumes)
|
||||||
|
uri := fmt.Sprintf("/%s/containers/%s?%s", APIVersion, id, args)
|
||||||
|
_, err := client.doRequest("DELETE", uri, nil, nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) ListImages(all bool) ([]*Image, error) {
|
||||||
|
argAll := 0
|
||||||
|
if all {
|
||||||
|
argAll = 1
|
||||||
|
}
|
||||||
|
uri := fmt.Sprintf("/%s/images/json?all=%d", APIVersion, argAll)
|
||||||
|
data, err := client.doRequest("GET", uri, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var images []*Image
|
||||||
|
if err := json.Unmarshal(data, &images); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return images, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) RemoveImage(name string, force bool) ([]*ImageDelete, error) {
|
||||||
|
argForce := 0
|
||||||
|
if force {
|
||||||
|
argForce = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
args := fmt.Sprintf("force=%d", argForce)
|
||||||
|
uri := fmt.Sprintf("/%s/images/%s?%s", APIVersion, name, args)
|
||||||
|
data, err := client.doRequest("DELETE", uri, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var imageDelete []*ImageDelete
|
||||||
|
if err := json.Unmarshal(data, &imageDelete); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return imageDelete, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) PauseContainer(id string) error {
|
||||||
|
uri := fmt.Sprintf("/%s/containers/%s/pause", APIVersion, id)
|
||||||
|
_, err := client.doRequest("POST", uri, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (client *DockerClient) UnpauseContainer(id string) error {
|
||||||
|
uri := fmt.Sprintf("/%s/containers/%s/unpause", APIVersion, id)
|
||||||
|
_, err := client.doRequest("POST", uri, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) RenameContainer(oldName string, newName string) error {
|
||||||
|
uri := fmt.Sprintf("/containers/%s/rename?name=%s", oldName, newName)
|
||||||
|
_, err := client.doRequest("POST", uri, nil, nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) ImportImage(source string, repository string, tag string, tar io.Reader) (io.ReadCloser, error) {
|
||||||
|
var fromSrc string
|
||||||
|
v := &url.Values{}
|
||||||
|
if source == "" {
|
||||||
|
fromSrc = "-"
|
||||||
|
} else {
|
||||||
|
fromSrc = source
|
||||||
|
}
|
||||||
|
|
||||||
|
v.Set("fromSrc", fromSrc)
|
||||||
|
v.Set("repo", repository)
|
||||||
|
if tag != "" {
|
||||||
|
v.Set("tag", tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
var in io.Reader
|
||||||
|
if fromSrc == "-" {
|
||||||
|
in = tar
|
||||||
|
}
|
||||||
|
return client.doStreamRequest("POST", "/images/create?"+v.Encode(), in, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) BuildImage(image *BuildImage) (io.ReadCloser, error) {
|
||||||
|
v := url.Values{}
|
||||||
|
|
||||||
|
if image.DockerfileName != "" {
|
||||||
|
v.Set("dockerfile", image.DockerfileName)
|
||||||
|
}
|
||||||
|
if image.RepoName != "" {
|
||||||
|
v.Set("t", image.RepoName)
|
||||||
|
}
|
||||||
|
if image.RemoteURL != "" {
|
||||||
|
v.Set("remote", image.RemoteURL)
|
||||||
|
}
|
||||||
|
if image.NoCache {
|
||||||
|
v.Set("nocache", "1")
|
||||||
|
}
|
||||||
|
if image.Pull {
|
||||||
|
v.Set("pull", "1")
|
||||||
|
}
|
||||||
|
if image.Remove {
|
||||||
|
v.Set("rm", "1")
|
||||||
|
} else {
|
||||||
|
v.Set("rm", "0")
|
||||||
|
}
|
||||||
|
if image.ForceRemove {
|
||||||
|
v.Set("forcerm", "1")
|
||||||
|
}
|
||||||
|
if image.SuppressOutput {
|
||||||
|
v.Set("q", "1")
|
||||||
|
}
|
||||||
|
|
||||||
|
v.Set("memory", strconv.FormatInt(image.Memory, 10))
|
||||||
|
v.Set("memswap", strconv.FormatInt(image.MemorySwap, 10))
|
||||||
|
v.Set("cpushares", strconv.FormatInt(image.CpuShares, 10))
|
||||||
|
v.Set("cpuperiod", strconv.FormatInt(image.CpuPeriod, 10))
|
||||||
|
v.Set("cpuquota", strconv.FormatInt(image.CpuQuota, 10))
|
||||||
|
v.Set("cpusetcpus", image.CpuSetCpus)
|
||||||
|
v.Set("cpusetmems", image.CpuSetMems)
|
||||||
|
v.Set("cgroupparent", image.CgroupParent)
|
||||||
|
if image.BuildArgs != nil {
|
||||||
|
buildArgsJSON, err := json.Marshal(image.BuildArgs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
v.Set("buildargs", string(buildArgsJSON))
|
||||||
|
}
|
||||||
|
|
||||||
|
headers := make(map[string]string)
|
||||||
|
if image.Config != nil {
|
||||||
|
encoded_config, err := image.Config.encode()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
headers["X-Registry-Config"] = encoded_config
|
||||||
|
}
|
||||||
|
if image.Context != nil {
|
||||||
|
headers["Content-Type"] = "application/tar"
|
||||||
|
}
|
||||||
|
|
||||||
|
uri := fmt.Sprintf("/%s/build?%s", APIVersion, v.Encode())
|
||||||
|
return client.doStreamRequest("POST", uri, image.Context, headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) ListVolumes() ([]*Volume, error) {
|
||||||
|
uri := fmt.Sprintf("/%s/volumes", APIVersion)
|
||||||
|
data, err := client.doRequest("GET", uri, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var volumesList VolumesListResponse
|
||||||
|
if err := json.Unmarshal(data, &volumesList); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return volumesList.Volumes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) RemoveVolume(name string) error {
|
||||||
|
uri := fmt.Sprintf("/%s/volumes/%s", APIVersion, name)
|
||||||
|
_, err := client.doRequest("DELETE", uri, nil, nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) CreateVolume(request *VolumeCreateRequest) (*Volume, error) {
|
||||||
|
data, err := json.Marshal(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
uri := fmt.Sprintf("/%s/volumes/create", APIVersion)
|
||||||
|
data, err = client.doRequest("POST", uri, data, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
volume := &Volume{}
|
||||||
|
err = json.Unmarshal(data, volume)
|
||||||
|
return volume, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) ListNetworks(filters string) ([]*NetworkResource, error) {
|
||||||
|
uri := fmt.Sprintf("/%s/networks", APIVersion)
|
||||||
|
|
||||||
|
if filters != "" {
|
||||||
|
uri += "&filters=" + filters
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := client.doRequest("GET", uri, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ret := []*NetworkResource{}
|
||||||
|
err = json.Unmarshal(data, &ret)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) InspectNetwork(id string) (*NetworkResource, error) {
|
||||||
|
uri := fmt.Sprintf("/%s/networks/%s", APIVersion, id)
|
||||||
|
|
||||||
|
data, err := client.doRequest("GET", uri, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ret := &NetworkResource{}
|
||||||
|
err = json.Unmarshal(data, ret)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) CreateNetwork(config *NetworkCreate) (*NetworkCreateResponse, error) {
|
||||||
|
data, err := json.Marshal(config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
uri := fmt.Sprintf("/%s/networks/create", APIVersion)
|
||||||
|
data, err = client.doRequest("POST", uri, data, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ret := &NetworkCreateResponse{}
|
||||||
|
err = json.Unmarshal(data, ret)
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) ConnectNetwork(id, container string) error {
|
||||||
|
data, err := json.Marshal(NetworkConnect{Container: container})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
uri := fmt.Sprintf("/%s/networks/%s/connect", APIVersion, id)
|
||||||
|
_, err = client.doRequest("POST", uri, data, nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) DisconnectNetwork(id, container string) error {
|
||||||
|
data, err := json.Marshal(NetworkDisconnect{Container: container})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
uri := fmt.Sprintf("/%s/networks/%s/disconnect", APIVersion, id)
|
||||||
|
_, err = client.doRequest("POST", uri, data, nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *DockerClient) RemoveNetwork(id string) error {
|
||||||
|
uri := fmt.Sprintf("/%s/networks/%s", APIVersion, id)
|
||||||
|
_, err := client.doRequest("DELETE", uri, nil, nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package dockerclient
|
||||||
|
|
||||||
|
var haproxyPullOutput = `{"status":"The image you are pulling has been verified","id":"haproxy:1"}
|
||||||
|
{"status":"Already exists","progressDetail":{},"id":"511136ea3c5a"}{"status":"Already exists","progressDetail":{},"id":"1aeada447715"}{"status":"Already exists","progressDetail":{},"id":"479215127fa7"}{"status":"Already exists","progressDetail":{},"id":"66301eb54a7d"}{"status":"Already exists","progressDetail":{},"id":"e3990b07573f"}{"status":"Already exists","progressDetail":{},"id":"ecb4b23ca7ce"}{"status":"Already exists","progressDetail":{},"id":"f453e940c177"}{"status":"Already exists","progressDetail":{},"id":"fc5ea1bc05ab"}{"status":"Already exists","progressDetail":{},"id":"380557f8f7b3"}{"status":"The image you are pulling has been verified","id":"haproxy:1.4"}
|
||||||
|
{"status":"Already exists","progressDetail":{},"id":"511136ea3c5a"}{"status":"Already exists","progressDetail":{},"id":"1aeada447715"}{"status":"Already exists","progressDetail":{},"id":"479215127fa7"}{"status":"Already exists","progressDetail":{},"id":"63a1b9929e14"}{"status":"Already exists","progressDetail":{},"id":"af43bf7d176e"}{"status":"Already exists","progressDetail":{},"id":"851aac2d69aa"}{"status":"Already exists","progressDetail":{},"id":"345053a92c95"}{"status":"Already exists","progressDetail":{},"id":"b41231d429c9"}{"status":"The image you are pulling has been verified","id":"haproxy:1.4.25"}
|
||||||
|
{"status":"Already exists","progressDetail":{},"id":"511136ea3c5a"}{"status":"Already exists","progressDetail":{},"id":"1aeada447715"}{"status":"Already exists","progressDetail":{},"id":"479215127fa7"}{"status":"Already exists","progressDetail":{},"id":"63a1b9929e14"}{"status":"Already exists","progressDetail":{},"id":"af43bf7d176e"}{"status":"Already exists","progressDetail":{},"id":"851aac2d69aa"}{"status":"Already exists","progressDetail":{},"id":"345053a92c95"}{"status":"Already exists","progressDetail":{},"id":"b41231d429c9"}{"status":"The image you are pulling has been verified","id":"haproxy:1.5"}
|
||||||
|
{"status":"Already exists","progressDetail":{},"id":"511136ea3c5a"}{"status":"Already exists","progressDetail":{},"id":"1aeada447715"}{"status":"Already exists","progressDetail":{},"id":"479215127fa7"}{"status":"Already exists","progressDetail":{},"id":"66301eb54a7d"}{"status":"Already exists","progressDetail":{},"id":"e3990b07573f"}{"status":"Already exists","progressDetail":{},"id":"ecb4b23ca7ce"}{"status":"Already exists","progressDetail":{},"id":"f453e940c177"}{"status":"Already exists","progressDetail":{},"id":"fc5ea1bc05ab"}{"status":"Already exists","progressDetail":{},"id":"380557f8f7b3"}{"status":"The image you are pulling has been verified","id":"haproxy:1.5.10"}
|
||||||
|
{"status":"Already exists","progressDetail":{},"id":"511136ea3c5a"}{"status":"Already exists","progressDetail":{},"id":"1aeada447715"}{"status":"Already exists","progressDetail":{},"id":"479215127fa7"}{"status":"Already exists","progressDetail":{},"id":"66301eb54a7d"}{"status":"Already exists","progressDetail":{},"id":"e3990b07573f"}{"status":"Already exists","progressDetail":{},"id":"ecb4b23ca7ce"}{"status":"Already exists","progressDetail":{},"id":"f453e940c177"}{"status":"Already exists","progressDetail":{},"id":"fc5ea1bc05ab"}{"status":"Already exists","progressDetail":{},"id":"380557f8f7b3"}{"status":"The image you are pulling has been verified","id":"haproxy:1.5.9"}
|
||||||
|
{"status":"Already exists","progressDetail":{},"id":"511136ea3c5a"}{"status":"Already exists","progressDetail":{},"id":"1aeada447715"}{"status":"Already exists","progressDetail":{},"id":"479215127fa7"}{"status":"Already exists","progressDetail":{},"id":"66301eb54a7d"}{"status":"Already exists","progressDetail":{},"id":"e3990b07573f"}{"status":"Already exists","progressDetail":{},"id":"3d894e6f7e63"}{"status":"Already exists","progressDetail":{},"id":"4d949c40bc77"}{"status":"Already exists","progressDetail":{},"id":"55e031889365"}{"status":"Already exists","progressDetail":{},"id":"c7aa675e1876"}{"status":"The image you are pulling has been verified","id":"haproxy:latest"}
|
||||||
|
{"status":"Already exists","progressDetail":{},"id":"511136ea3c5a"}{"status":"Already exists","progressDetail":{},"id":"1aeada447715"}{"status":"Already exists","progressDetail":{},"id":"479215127fa7"}{"status":"Already exists","progressDetail":{},"id":"66301eb54a7d"}{"status":"Already exists","progressDetail":{},"id":"e3990b07573f"}{"status":"Already exists","progressDetail":{},"id":"ecb4b23ca7ce"}{"status":"Already exists","progressDetail":{},"id":"f453e940c177"}{"status":"Already exists","progressDetail":{},"id":"fc5ea1bc05ab"}{"status":"Already exists","progressDetail":{},"id":"380557f8f7b3"}{"status":"Status: Image is up to date for haproxy"}
|
||||||
|
`
|
||||||
|
|
||||||
|
var eventsResp = `{"status":"pull","id":"nginx:latest","time":1428620433}{"status":"create","id":"9b818c3b8291708fdcecd7c4086b75c222cb503be10a93d9c11040886032a48b","from":"nginx:latest","time":1428620433}{"status":"start","id":"9b818c3b8291708fdcecd7c4086b75c222cb503be10a93d9c11040886032a48b","from":"nginx:latest","time":1428620433}{"status":"die","id":"9b818c3b8291708fdcecd7c4086b75c222cb503be10a93d9c11040886032a48b","from":"nginx:latest","time":1428620442}{"status":"create","id":"352d0b412aae5a5d2b14ae9d88be59dc276602d9edb9dcc33e138e475b3e4720","from":"52.11.96.81/foobar/ubuntu:latest","time":1428620444}{"status":"start","id":"352d0b412aae5a5d2b14ae9d88be59dc276602d9edb9dcc33e138e475b3e4720","from":"52.11.96.81/foobar/ubuntu:latest","time":1428620444}{"status":"die","id":"352d0b412aae5a5d2b14ae9d88be59dc276602d9edb9dcc33e138e475b3e4720","from":"52.11.96.81/foobar/ubuntu:latest","time":1428620444}{"status":"pull","id":"debian:latest","time":1428620453}{"status":"create","id":"668887b5729946546b3072655dc6da08f0e3210111b68b704eb842adfce53f6c","from":"debian:latest","time":1428620453}{"status":"start","id":"668887b5729946546b3072655dc6da08f0e3210111b68b704eb842adfce53f6c","from":"debian:latest","time":1428620453}{"status":"die","id":"668887b5729946546b3072655dc6da08f0e3210111b68b704eb842adfce53f6c","from":"debian:latest","time":1428620453}{"status":"create","id":"eb4a19ec21ab29bbbffbf3ee2e2df9d99cb749780e1eff06a591cee5ba505180","from":"nginx:latest","time":1428620458}{"status":"start","id":"eb4a19ec21ab29bbbffbf3ee2e2df9d99cb749780e1eff06a591cee5ba505180","from":"nginx:latest","time":1428620458}{"status":"pause","id":"eb4a19ec21ab29bbbffbf3ee2e2df9d99cb749780e1eff06a591cee5ba505180","from":"nginx:latest","time":1428620462}{"status":"unpause","id":"eb4a19ec21ab29bbbffbf3ee2e2df9d99cb749780e1eff06a591cee5ba505180","from":"nginx:latest","time":1428620466}{"status":"die","id":"eb4a19ec21ab29bbbffbf3ee2e2df9d99cb749780e1eff06a591cee5ba505180","from":"nginx:latest","time":1428620469}`
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/samalba/dockerclient"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func eventCallback(e *dockerclient.Event, ec chan error, args ...interface{}) {
|
||||||
|
log.Println(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
client *dockerclient.DockerClient
|
||||||
|
)
|
||||||
|
|
||||||
|
func waitForInterrupt() {
|
||||||
|
sigChan := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT)
|
||||||
|
for _ = range sigChan {
|
||||||
|
client.StopAllMonitorEvents()
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
docker, err := dockerclient.NewDockerClient(os.Getenv("DOCKER_HOST"), nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
client = docker
|
||||||
|
|
||||||
|
client.StartMonitorEvents(eventCallback, nil)
|
||||||
|
|
||||||
|
waitForInterrupt()
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/samalba/dockerclient"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func statCallback(id string, stat *dockerclient.Stats, ec chan error, args ...interface{}) {
|
||||||
|
log.Println(stat)
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitForInterrupt() {
|
||||||
|
sigChan := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT)
|
||||||
|
for _ = range sigChan {
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
docker, err := dockerclient.NewDockerClient(os.Getenv("DOCKER_HOST"), nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
containerConfig := &dockerclient.ContainerConfig{Image: "busybox", Cmd: []string{"sh"}}
|
||||||
|
containerId, err := docker.CreateContainer(containerConfig, "")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the container
|
||||||
|
err = docker.StartContainer(containerId, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
docker.StartMonitorStats(containerId, statCallback, nil)
|
||||||
|
|
||||||
|
waitForInterrupt()
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
package dockerclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Callback func(*Event, chan error, ...interface{})
|
||||||
|
|
||||||
|
type StatCallback func(string, *Stats, chan error, ...interface{})
|
||||||
|
|
||||||
|
type Client interface {
|
||||||
|
Info() (*Info, error)
|
||||||
|
ListContainers(all, size bool, filters string) ([]Container, error)
|
||||||
|
InspectContainer(id string) (*ContainerInfo, error)
|
||||||
|
InspectImage(id string) (*ImageInfo, error)
|
||||||
|
CreateContainer(config *ContainerConfig, name string) (string, error)
|
||||||
|
ContainerLogs(id string, options *LogOptions) (io.ReadCloser, error)
|
||||||
|
ContainerChanges(id string) ([]*ContainerChanges, error)
|
||||||
|
ExecCreate(config *ExecConfig) (string, error)
|
||||||
|
ExecStart(id string, config *ExecConfig) error
|
||||||
|
ExecResize(id string, width, height int) error
|
||||||
|
StartContainer(id string, config *HostConfig) error
|
||||||
|
AttachContainer(id string, options *AttachOptions) (io.ReadCloser, error)
|
||||||
|
StopContainer(id string, timeout int) error
|
||||||
|
RestartContainer(id string, timeout int) error
|
||||||
|
KillContainer(id, signal string) error
|
||||||
|
Wait(id string) <-chan WaitResult
|
||||||
|
// MonitorEvents takes options and an optional stop channel, and returns
|
||||||
|
// an EventOrError channel. If an error is ever sent, then no more
|
||||||
|
// events will be sent. If a stop channel is provided, events will stop
|
||||||
|
// being monitored after the stop channel is closed.
|
||||||
|
MonitorEvents(options *MonitorEventsOptions, stopChan <-chan struct{}) (<-chan EventOrError, error)
|
||||||
|
StartMonitorEvents(cb Callback, ec chan error, args ...interface{})
|
||||||
|
StopAllMonitorEvents()
|
||||||
|
StartMonitorStats(id string, cb StatCallback, ec chan error, args ...interface{})
|
||||||
|
StopAllMonitorStats()
|
||||||
|
TagImage(nameOrID string, repo string, tag string, force bool) error
|
||||||
|
Version() (*Version, error)
|
||||||
|
PullImage(name string, auth *AuthConfig) error
|
||||||
|
PushImage(name string, tag string, auth *AuthConfig) error
|
||||||
|
LoadImage(reader io.Reader) error
|
||||||
|
RemoveContainer(id string, force, volumes bool) error
|
||||||
|
ListImages(all bool) ([]*Image, error)
|
||||||
|
RemoveImage(name string, force bool) ([]*ImageDelete, error)
|
||||||
|
PauseContainer(name string) error
|
||||||
|
UnpauseContainer(name string) error
|
||||||
|
RenameContainer(oldName string, newName string) error
|
||||||
|
ImportImage(source string, repository string, tag string, tar io.Reader) (io.ReadCloser, error)
|
||||||
|
BuildImage(image *BuildImage) (io.ReadCloser, error)
|
||||||
|
ListVolumes() ([]*Volume, error)
|
||||||
|
RemoveVolume(name string) error
|
||||||
|
CreateVolume(request *VolumeCreateRequest) (*Volume, error)
|
||||||
|
ListNetworks(filters string) ([]*NetworkResource, error)
|
||||||
|
InspectNetwork(id string) (*NetworkResource, error)
|
||||||
|
CreateNetwork(config *NetworkCreate) (*NetworkCreateResponse, error)
|
||||||
|
ConnectNetwork(id, container string) error
|
||||||
|
DisconnectNetwork(id, container string) error
|
||||||
|
RemoveNetwork(id string) error
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,227 @@
|
||||||
|
package mockclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/samalba/dockerclient"
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MockClient struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMockClient() *MockClient {
|
||||||
|
return &MockClient{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) Info() (*dockerclient.Info, error) {
|
||||||
|
args := client.Mock.Called()
|
||||||
|
return args.Get(0).(*dockerclient.Info), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) ListContainers(all bool, size bool, filters string) ([]dockerclient.Container, error) {
|
||||||
|
args := client.Mock.Called(all, size, filters)
|
||||||
|
return args.Get(0).([]dockerclient.Container), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) InspectContainer(id string) (*dockerclient.ContainerInfo, error) {
|
||||||
|
args := client.Mock.Called(id)
|
||||||
|
return args.Get(0).(*dockerclient.ContainerInfo), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) InspectImage(id string) (*dockerclient.ImageInfo, error) {
|
||||||
|
args := client.Mock.Called(id)
|
||||||
|
return args.Get(0).(*dockerclient.ImageInfo), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) CreateContainer(config *dockerclient.ContainerConfig, name string) (string, error) {
|
||||||
|
args := client.Mock.Called(config, name)
|
||||||
|
return args.String(0), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) ContainerLogs(id string, options *dockerclient.LogOptions) (io.ReadCloser, error) {
|
||||||
|
args := client.Mock.Called(id, options)
|
||||||
|
return args.Get(0).(io.ReadCloser), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) ContainerChanges(id string) ([]*dockerclient.ContainerChanges, error) {
|
||||||
|
args := client.Mock.Called(id)
|
||||||
|
return args.Get(0).([]*dockerclient.ContainerChanges), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) AttachContainer(id string, options *dockerclient.AttachOptions) (io.ReadCloser, error) {
|
||||||
|
args := client.Mock.Called(id, options)
|
||||||
|
return args.Get(0).(io.ReadCloser), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) StartContainer(id string, config *dockerclient.HostConfig) error {
|
||||||
|
args := client.Mock.Called(id, config)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) StopContainer(id string, timeout int) error {
|
||||||
|
args := client.Mock.Called(id, timeout)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) RestartContainer(id string, timeout int) error {
|
||||||
|
args := client.Mock.Called(id, timeout)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) KillContainer(id, signal string) error {
|
||||||
|
args := client.Mock.Called(id, signal)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) Wait(id string) <-chan dockerclient.WaitResult {
|
||||||
|
args := client.Mock.Called(id)
|
||||||
|
return args.Get(0).(<-chan dockerclient.WaitResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) MonitorEvents(options *dockerclient.MonitorEventsOptions, stopChan <-chan struct{}) (<-chan dockerclient.EventOrError, error) {
|
||||||
|
args := client.Mock.Called(options, stopChan)
|
||||||
|
return args.Get(0).(<-chan dockerclient.EventOrError), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) StartMonitorEvents(cb dockerclient.Callback, ec chan error, args ...interface{}) {
|
||||||
|
client.Mock.Called(cb, ec, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) StopAllMonitorEvents() {
|
||||||
|
client.Mock.Called()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) TagImage(nameOrID string, repo string, tag string, force bool) error {
|
||||||
|
args := client.Mock.Called(nameOrID, repo, tag, force)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) StartMonitorStats(id string, cb dockerclient.StatCallback, ec chan error, args ...interface{}) {
|
||||||
|
client.Mock.Called(id, cb, ec, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) StopAllMonitorStats() {
|
||||||
|
client.Mock.Called()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) Version() (*dockerclient.Version, error) {
|
||||||
|
args := client.Mock.Called()
|
||||||
|
return args.Get(0).(*dockerclient.Version), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) PullImage(name string, auth *dockerclient.AuthConfig) error {
|
||||||
|
args := client.Mock.Called(name, auth)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) PushImage(name string, tag string, auth *dockerclient.AuthConfig) error {
|
||||||
|
args := client.Mock.Called(name, tag, auth)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) LoadImage(reader io.Reader) error {
|
||||||
|
args := client.Mock.Called(reader)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) RemoveContainer(id string, force, volumes bool) error {
|
||||||
|
args := client.Mock.Called(id, force, volumes)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) ListImages(all bool) ([]*dockerclient.Image, error) {
|
||||||
|
args := client.Mock.Called(all)
|
||||||
|
return args.Get(0).([]*dockerclient.Image), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) RemoveImage(name string, force bool) ([]*dockerclient.ImageDelete, error) {
|
||||||
|
args := client.Mock.Called(name, force)
|
||||||
|
return args.Get(0).([]*dockerclient.ImageDelete), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) PauseContainer(name string) error {
|
||||||
|
args := client.Mock.Called(name)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) UnpauseContainer(name string) error {
|
||||||
|
args := client.Mock.Called(name)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) ExecCreate(config *dockerclient.ExecConfig) (string, error) {
|
||||||
|
args := client.Mock.Called(config)
|
||||||
|
return args.String(0), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) ExecStart(id string, config *dockerclient.ExecConfig) error {
|
||||||
|
args := client.Mock.Called(id, config)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) ExecResize(id string, width, height int) error {
|
||||||
|
args := client.Mock.Called(id, width, height)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) RenameContainer(oldName string, newName string) error {
|
||||||
|
args := client.Mock.Called(oldName, newName)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) ImportImage(source string, repository string, tag string, tar io.Reader) (io.ReadCloser, error) {
|
||||||
|
args := client.Mock.Called(source, repository, tag, tar)
|
||||||
|
return args.Get(0).(io.ReadCloser), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) BuildImage(image *dockerclient.BuildImage) (io.ReadCloser, error) {
|
||||||
|
args := client.Mock.Called(image)
|
||||||
|
return args.Get(0).(io.ReadCloser), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) ListVolumes() ([]*dockerclient.Volume, error) {
|
||||||
|
args := client.Mock.Called()
|
||||||
|
return args.Get(0).([]*dockerclient.Volume), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) RemoveVolume(name string) error {
|
||||||
|
args := client.Mock.Called(name)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) CreateVolume(request *dockerclient.VolumeCreateRequest) (*dockerclient.Volume, error) {
|
||||||
|
args := client.Mock.Called(request)
|
||||||
|
return args.Get(0).(*dockerclient.Volume), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) ListNetworks(filters string) ([]*dockerclient.NetworkResource, error) {
|
||||||
|
args := client.Mock.Called(filters)
|
||||||
|
return args.Get(0).([]*dockerclient.NetworkResource), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) InspectNetwork(id string) (*dockerclient.NetworkResource, error) {
|
||||||
|
args := client.Mock.Called(id)
|
||||||
|
return args.Get(0).(*dockerclient.NetworkResource), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) CreateNetwork(config *dockerclient.NetworkCreate) (*dockerclient.NetworkCreateResponse, error) {
|
||||||
|
args := client.Mock.Called(config)
|
||||||
|
return args.Get(0).(*dockerclient.NetworkCreateResponse), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) ConnectNetwork(id, container string) error {
|
||||||
|
args := client.Mock.Called(id, container)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) DisconnectNetwork(id, container string) error {
|
||||||
|
args := client.Mock.Called(id, container)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *MockClient) RemoveNetwork(id string) error {
|
||||||
|
args := client.Mock.Called(id)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,191 @@
|
||||||
|
package nopclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/samalba/dockerclient"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrNoEngine = errors.New("Engine no longer exists")
|
||||||
|
)
|
||||||
|
|
||||||
|
type NopClient struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNopClient() *NopClient {
|
||||||
|
return &NopClient{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) Info() (*dockerclient.Info, error) {
|
||||||
|
return nil, ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) ListContainers(all bool, size bool, filters string) ([]dockerclient.Container, error) {
|
||||||
|
return nil, ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) InspectContainer(id string) (*dockerclient.ContainerInfo, error) {
|
||||||
|
return nil, ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) InspectImage(id string) (*dockerclient.ImageInfo, error) {
|
||||||
|
return nil, ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) CreateContainer(config *dockerclient.ContainerConfig, name string) (string, error) {
|
||||||
|
return "", ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) ContainerLogs(id string, options *dockerclient.LogOptions) (io.ReadCloser, error) {
|
||||||
|
return nil, ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) ContainerChanges(id string) ([]*dockerclient.ContainerChanges, error) {
|
||||||
|
return nil, ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) AttachContainer(id string, options *dockerclient.AttachOptions) (io.ReadCloser, error) {
|
||||||
|
return nil, ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) StartContainer(id string, config *dockerclient.HostConfig) error {
|
||||||
|
return ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) StopContainer(id string, timeout int) error {
|
||||||
|
return ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) RestartContainer(id string, timeout int) error {
|
||||||
|
return ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) KillContainer(id, signal string) error {
|
||||||
|
return ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) Wait(id string) <-chan dockerclient.WaitResult {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) MonitorEvents(options *dockerclient.MonitorEventsOptions, stopChan <-chan struct{}) (<-chan dockerclient.EventOrError, error) {
|
||||||
|
return nil, ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) StartMonitorEvents(cb dockerclient.Callback, ec chan error, args ...interface{}) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) StopAllMonitorEvents() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) TagImage(nameOrID string, repo string, tag string, force bool) error {
|
||||||
|
return ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) StartMonitorStats(id string, cb dockerclient.StatCallback, ec chan error, args ...interface{}) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) StopAllMonitorStats() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) Version() (*dockerclient.Version, error) {
|
||||||
|
return nil, ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) PullImage(name string, auth *dockerclient.AuthConfig) error {
|
||||||
|
return ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) PushImage(name, tag string, auth *dockerclient.AuthConfig) error {
|
||||||
|
return ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) LoadImage(reader io.Reader) error {
|
||||||
|
return ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) RemoveContainer(id string, force, volumes bool) error {
|
||||||
|
return ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) ListImages(all bool) ([]*dockerclient.Image, error) {
|
||||||
|
return nil, ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) RemoveImage(name string, force bool) ([]*dockerclient.ImageDelete, error) {
|
||||||
|
return nil, ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) PauseContainer(name string) error {
|
||||||
|
return ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) UnpauseContainer(name string) error {
|
||||||
|
return ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) ExecCreate(config *dockerclient.ExecConfig) (string, error) {
|
||||||
|
return "", ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) ExecStart(id string, config *dockerclient.ExecConfig) error {
|
||||||
|
return ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) ExecResize(id string, width, height int) error {
|
||||||
|
return ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) RenameContainer(oldName string, newName string) error {
|
||||||
|
return ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) ImportImage(source string, repository string, tag string, tar io.Reader) (io.ReadCloser, error) {
|
||||||
|
return nil, ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) BuildImage(image *dockerclient.BuildImage) (io.ReadCloser, error) {
|
||||||
|
return nil, ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) ListVolumes() ([]*dockerclient.Volume, error) {
|
||||||
|
return nil, ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) RemoveVolume(name string) error {
|
||||||
|
return ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) CreateVolume(request *dockerclient.VolumeCreateRequest) (*dockerclient.Volume, error) {
|
||||||
|
return nil, ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) ListNetworks(filters string) ([]*dockerclient.NetworkResource, error) {
|
||||||
|
return nil, ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) InspectNetwork(id string) (*dockerclient.NetworkResource, error) {
|
||||||
|
return nil, ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) CreateNetwork(config *dockerclient.NetworkCreate) (*dockerclient.NetworkCreateResponse, error) {
|
||||||
|
return nil, ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) ConnectNetwork(id, container string) error {
|
||||||
|
return ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) DisconnectNetwork(id, container string) error {
|
||||||
|
return ErrNoEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *NopClient) RemoveNetwork(id string) error {
|
||||||
|
return ErrNoEngine
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,538 @@
|
||||||
|
package dockerclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/docker/docker/pkg/units"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ContainerConfig struct {
|
||||||
|
Hostname string
|
||||||
|
Domainname string
|
||||||
|
User string
|
||||||
|
AttachStdin bool
|
||||||
|
AttachStdout bool
|
||||||
|
AttachStderr bool
|
||||||
|
ExposedPorts map[string]struct{}
|
||||||
|
Tty bool
|
||||||
|
OpenStdin bool
|
||||||
|
StdinOnce bool
|
||||||
|
Env []string
|
||||||
|
Cmd []string
|
||||||
|
Image string
|
||||||
|
Volumes map[string]struct{}
|
||||||
|
WorkingDir string
|
||||||
|
Entrypoint []string
|
||||||
|
NetworkDisabled bool
|
||||||
|
MacAddress string
|
||||||
|
OnBuild []string
|
||||||
|
Labels map[string]string
|
||||||
|
StopSignal string
|
||||||
|
|
||||||
|
// FIXME: VolumeDriver have been removed since docker 1.9
|
||||||
|
VolumeDriver string
|
||||||
|
|
||||||
|
// FIXME: The following fields have been removed since API v1.18
|
||||||
|
Memory int64
|
||||||
|
MemorySwap int64
|
||||||
|
CpuShares int64
|
||||||
|
Cpuset string
|
||||||
|
PortSpecs []string
|
||||||
|
|
||||||
|
// This is used only by the create command
|
||||||
|
HostConfig HostConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
type HostConfig struct {
|
||||||
|
Binds []string
|
||||||
|
ContainerIDFile string
|
||||||
|
LxcConf []map[string]string
|
||||||
|
Memory int64
|
||||||
|
MemoryReservation int64
|
||||||
|
MemorySwap int64
|
||||||
|
KernelMemory int64
|
||||||
|
CpuShares int64
|
||||||
|
CpuPeriod int64
|
||||||
|
CpusetCpus string
|
||||||
|
CpusetMems string
|
||||||
|
CpuQuota int64
|
||||||
|
BlkioWeight int64
|
||||||
|
OomKillDisable bool
|
||||||
|
MemorySwappiness int64
|
||||||
|
Privileged bool
|
||||||
|
PortBindings map[string][]PortBinding
|
||||||
|
Links []string
|
||||||
|
PublishAllPorts bool
|
||||||
|
Dns []string
|
||||||
|
DNSOptions []string
|
||||||
|
DnsSearch []string
|
||||||
|
ExtraHosts []string
|
||||||
|
VolumesFrom []string
|
||||||
|
Devices []DeviceMapping
|
||||||
|
NetworkMode string
|
||||||
|
IpcMode string
|
||||||
|
PidMode string
|
||||||
|
UTSMode string
|
||||||
|
CapAdd []string
|
||||||
|
CapDrop []string
|
||||||
|
GroupAdd []string
|
||||||
|
RestartPolicy RestartPolicy
|
||||||
|
SecurityOpt []string
|
||||||
|
ReadonlyRootfs bool
|
||||||
|
Ulimits []Ulimit
|
||||||
|
LogConfig LogConfig
|
||||||
|
CgroupParent string
|
||||||
|
ConsoleSize [2]int
|
||||||
|
VolumeDriver string
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeviceMapping struct {
|
||||||
|
PathOnHost string `json:"PathOnHost"`
|
||||||
|
PathInContainer string `json:"PathInContainer"`
|
||||||
|
CgroupPermissions string `json:"CgroupPermissions"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExecConfig struct {
|
||||||
|
AttachStdin bool
|
||||||
|
AttachStdout bool
|
||||||
|
AttachStderr bool
|
||||||
|
Tty bool
|
||||||
|
Cmd []string
|
||||||
|
Container string
|
||||||
|
Detach bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type LogOptions struct {
|
||||||
|
Follow bool
|
||||||
|
Stdout bool
|
||||||
|
Stderr bool
|
||||||
|
Timestamps bool
|
||||||
|
Tail int64
|
||||||
|
}
|
||||||
|
|
||||||
|
type AttachOptions struct {
|
||||||
|
Logs bool
|
||||||
|
Stream bool
|
||||||
|
Stdin bool
|
||||||
|
Stdout bool
|
||||||
|
Stderr bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type MonitorEventsFilters struct {
|
||||||
|
Event string `json:",omitempty"`
|
||||||
|
Image string `json:",omitempty"`
|
||||||
|
Container string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MonitorEventsOptions struct {
|
||||||
|
Since int
|
||||||
|
Until int
|
||||||
|
Filters *MonitorEventsFilters `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RestartPolicy struct {
|
||||||
|
Name string
|
||||||
|
MaximumRetryCount int64
|
||||||
|
}
|
||||||
|
|
||||||
|
type PortBinding struct {
|
||||||
|
HostIp string
|
||||||
|
HostPort string
|
||||||
|
}
|
||||||
|
|
||||||
|
type State struct {
|
||||||
|
Running bool
|
||||||
|
Paused bool
|
||||||
|
Restarting bool
|
||||||
|
OOMKilled bool
|
||||||
|
Dead bool
|
||||||
|
Pid int
|
||||||
|
ExitCode int
|
||||||
|
Error string // contains last known error when starting the container
|
||||||
|
StartedAt time.Time
|
||||||
|
FinishedAt time.Time
|
||||||
|
Ghost bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a human-readable description of the state
|
||||||
|
// Stoken from docker/docker/daemon/state.go
|
||||||
|
func (s *State) String() string {
|
||||||
|
if s.Running {
|
||||||
|
if s.Paused {
|
||||||
|
return fmt.Sprintf("Up %s (Paused)", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt)))
|
||||||
|
}
|
||||||
|
if s.Restarting {
|
||||||
|
return fmt.Sprintf("Restarting (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("Up %s", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Dead {
|
||||||
|
return "Dead"
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.FinishedAt.IsZero() {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("Exited (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// StateString returns a single string to describe state
|
||||||
|
// Stoken from docker/docker/daemon/state.go
|
||||||
|
func (s *State) StateString() string {
|
||||||
|
if s.Running {
|
||||||
|
if s.Paused {
|
||||||
|
return "paused"
|
||||||
|
}
|
||||||
|
if s.Restarting {
|
||||||
|
return "restarting"
|
||||||
|
}
|
||||||
|
return "running"
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Dead {
|
||||||
|
return "dead"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "exited"
|
||||||
|
}
|
||||||
|
|
||||||
|
type ImageInfo struct {
|
||||||
|
Architecture string
|
||||||
|
Author string
|
||||||
|
Comment string
|
||||||
|
Config *ContainerConfig
|
||||||
|
Container string
|
||||||
|
ContainerConfig *ContainerConfig
|
||||||
|
Created time.Time
|
||||||
|
DockerVersion string
|
||||||
|
Id string
|
||||||
|
Os string
|
||||||
|
Parent string
|
||||||
|
Size int64
|
||||||
|
VirtualSize int64
|
||||||
|
}
|
||||||
|
|
||||||
|
type ContainerInfo struct {
|
||||||
|
Id string
|
||||||
|
Created string
|
||||||
|
Path string
|
||||||
|
Name string
|
||||||
|
Args []string
|
||||||
|
ExecIDs []string
|
||||||
|
Config *ContainerConfig
|
||||||
|
State *State
|
||||||
|
Image string
|
||||||
|
NetworkSettings struct {
|
||||||
|
IPAddress string `json:"IpAddress"`
|
||||||
|
IPPrefixLen int `json:"IpPrefixLen"`
|
||||||
|
Gateway string
|
||||||
|
Bridge string
|
||||||
|
Ports map[string][]PortBinding
|
||||||
|
}
|
||||||
|
SysInitPath string
|
||||||
|
ResolvConfPath string
|
||||||
|
Volumes map[string]string
|
||||||
|
HostConfig *HostConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
type ContainerChanges struct {
|
||||||
|
Path string
|
||||||
|
Kind int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Port struct {
|
||||||
|
IP string
|
||||||
|
PrivatePort int
|
||||||
|
PublicPort int
|
||||||
|
Type string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Container struct {
|
||||||
|
Id string
|
||||||
|
Names []string
|
||||||
|
Image string
|
||||||
|
Command string
|
||||||
|
Created int64
|
||||||
|
Status string
|
||||||
|
Ports []Port
|
||||||
|
SizeRw int64
|
||||||
|
SizeRootFs int64
|
||||||
|
Labels map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Event struct {
|
||||||
|
Id string
|
||||||
|
Status string
|
||||||
|
From string
|
||||||
|
Time int64
|
||||||
|
}
|
||||||
|
|
||||||
|
type Version struct {
|
||||||
|
ApiVersion string
|
||||||
|
Arch string
|
||||||
|
GitCommit string
|
||||||
|
GoVersion string
|
||||||
|
KernelVersion string
|
||||||
|
Os string
|
||||||
|
Version string
|
||||||
|
}
|
||||||
|
|
||||||
|
type RespContainersCreate struct {
|
||||||
|
Id string
|
||||||
|
Warnings []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Image struct {
|
||||||
|
Created int64
|
||||||
|
Id string
|
||||||
|
Labels map[string]string
|
||||||
|
ParentId string
|
||||||
|
RepoDigests []string
|
||||||
|
RepoTags []string
|
||||||
|
Size int64
|
||||||
|
VirtualSize int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info is the struct returned by /info
|
||||||
|
// The API is currently in flux, so Debug, MemoryLimit, SwapLimit, and
|
||||||
|
// IPv4Forwarding are interfaces because in docker 1.6.1 they are 0 or 1 but in
|
||||||
|
// master they are bools.
|
||||||
|
type Info struct {
|
||||||
|
ID string
|
||||||
|
Containers int64
|
||||||
|
Driver string
|
||||||
|
DriverStatus [][]string
|
||||||
|
ExecutionDriver string
|
||||||
|
Images int64
|
||||||
|
KernelVersion string
|
||||||
|
OperatingSystem string
|
||||||
|
NCPU int64
|
||||||
|
MemTotal int64
|
||||||
|
Name string
|
||||||
|
Labels []string
|
||||||
|
Debug interface{}
|
||||||
|
NFd int64
|
||||||
|
NGoroutines int64
|
||||||
|
SystemTime string
|
||||||
|
NEventsListener int64
|
||||||
|
InitPath string
|
||||||
|
InitSha1 string
|
||||||
|
IndexServerAddress string
|
||||||
|
MemoryLimit interface{}
|
||||||
|
SwapLimit interface{}
|
||||||
|
IPv4Forwarding interface{}
|
||||||
|
BridgeNfIptables bool
|
||||||
|
BridgeNfIp6tables bool
|
||||||
|
DockerRootDir string
|
||||||
|
HttpProxy string
|
||||||
|
HttpsProxy string
|
||||||
|
NoProxy string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ImageDelete struct {
|
||||||
|
Deleted string
|
||||||
|
Untagged string
|
||||||
|
}
|
||||||
|
|
||||||
|
type EventOrError struct {
|
||||||
|
Event
|
||||||
|
Error error
|
||||||
|
}
|
||||||
|
|
||||||
|
type WaitResult struct {
|
||||||
|
ExitCode int
|
||||||
|
Error error
|
||||||
|
}
|
||||||
|
|
||||||
|
type decodingResult struct {
|
||||||
|
result interface{}
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following are types for the API stats endpoint
|
||||||
|
type ThrottlingData struct {
|
||||||
|
// Number of periods with throttling active
|
||||||
|
Periods uint64 `json:"periods"`
|
||||||
|
// Number of periods when the container hit its throttling limit.
|
||||||
|
ThrottledPeriods uint64 `json:"throttled_periods"`
|
||||||
|
// Aggregate time the container was throttled for in nanoseconds.
|
||||||
|
ThrottledTime uint64 `json:"throttled_time"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CpuUsage struct {
|
||||||
|
// Total CPU time consumed.
|
||||||
|
// Units: nanoseconds.
|
||||||
|
TotalUsage uint64 `json:"total_usage"`
|
||||||
|
// Total CPU time consumed per core.
|
||||||
|
// Units: nanoseconds.
|
||||||
|
PercpuUsage []uint64 `json:"percpu_usage"`
|
||||||
|
// Time spent by tasks of the cgroup in kernel mode.
|
||||||
|
// Units: nanoseconds.
|
||||||
|
UsageInKernelmode uint64 `json:"usage_in_kernelmode"`
|
||||||
|
// Time spent by tasks of the cgroup in user mode.
|
||||||
|
// Units: nanoseconds.
|
||||||
|
UsageInUsermode uint64 `json:"usage_in_usermode"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CpuStats struct {
|
||||||
|
CpuUsage CpuUsage `json:"cpu_usage"`
|
||||||
|
SystemUsage uint64 `json:"system_cpu_usage"`
|
||||||
|
ThrottlingData ThrottlingData `json:"throttling_data,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type NetworkStats struct {
|
||||||
|
RxBytes uint64 `json:"rx_bytes"`
|
||||||
|
RxPackets uint64 `json:"rx_packets"`
|
||||||
|
RxErrors uint64 `json:"rx_errors"`
|
||||||
|
RxDropped uint64 `json:"rx_dropped"`
|
||||||
|
TxBytes uint64 `json:"tx_bytes"`
|
||||||
|
TxPackets uint64 `json:"tx_packets"`
|
||||||
|
TxErrors uint64 `json:"tx_errors"`
|
||||||
|
TxDropped uint64 `json:"tx_dropped"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MemoryStats struct {
|
||||||
|
Usage uint64 `json:"usage"`
|
||||||
|
MaxUsage uint64 `json:"max_usage"`
|
||||||
|
Stats map[string]uint64 `json:"stats"`
|
||||||
|
Failcnt uint64 `json:"failcnt"`
|
||||||
|
Limit uint64 `json:"limit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BlkioStatEntry struct {
|
||||||
|
Major uint64 `json:"major"`
|
||||||
|
Minor uint64 `json:"minor"`
|
||||||
|
Op string `json:"op"`
|
||||||
|
Value uint64 `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BlkioStats struct {
|
||||||
|
// number of bytes tranferred to and from the block device
|
||||||
|
IoServiceBytesRecursive []BlkioStatEntry `json:"io_service_bytes_recursive"`
|
||||||
|
IoServicedRecursive []BlkioStatEntry `json:"io_serviced_recursive"`
|
||||||
|
IoQueuedRecursive []BlkioStatEntry `json:"io_queue_recursive"`
|
||||||
|
IoServiceTimeRecursive []BlkioStatEntry `json:"io_service_time_recursive"`
|
||||||
|
IoWaitTimeRecursive []BlkioStatEntry `json:"io_wait_time_recursive"`
|
||||||
|
IoMergedRecursive []BlkioStatEntry `json:"io_merged_recursive"`
|
||||||
|
IoTimeRecursive []BlkioStatEntry `json:"io_time_recursive"`
|
||||||
|
SectorsRecursive []BlkioStatEntry `json:"sectors_recursive"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Stats struct {
|
||||||
|
Read time.Time `json:"read"`
|
||||||
|
NetworkStats NetworkStats `json:"network,omitempty"`
|
||||||
|
CpuStats CpuStats `json:"cpu_stats,omitempty"`
|
||||||
|
MemoryStats MemoryStats `json:"memory_stats,omitempty"`
|
||||||
|
BlkioStats BlkioStats `json:"blkio_stats,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Ulimit struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Soft uint64 `json:"soft"`
|
||||||
|
Hard uint64 `json:"hard"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LogConfig struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Config map[string]string `json:"config"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BuildImage struct {
|
||||||
|
Config *ConfigFile
|
||||||
|
DockerfileName string
|
||||||
|
Context io.Reader
|
||||||
|
RemoteURL string
|
||||||
|
RepoName string
|
||||||
|
SuppressOutput bool
|
||||||
|
NoCache bool
|
||||||
|
Remove bool
|
||||||
|
ForceRemove bool
|
||||||
|
Pull bool
|
||||||
|
Memory int64
|
||||||
|
MemorySwap int64
|
||||||
|
CpuShares int64
|
||||||
|
CpuPeriod int64
|
||||||
|
CpuQuota int64
|
||||||
|
CpuSetCpus string
|
||||||
|
CpuSetMems string
|
||||||
|
CgroupParent string
|
||||||
|
BuildArgs map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Volume struct {
|
||||||
|
Name string // Name is the name of the volume
|
||||||
|
Driver string // Driver is the Driver name used to create the volume
|
||||||
|
Mountpoint string // Mountpoint is the location on disk of the volume
|
||||||
|
}
|
||||||
|
|
||||||
|
type VolumesListResponse struct {
|
||||||
|
Volumes []*Volume // Volumes is the list of volumes being returned
|
||||||
|
}
|
||||||
|
|
||||||
|
type VolumeCreateRequest struct {
|
||||||
|
Name string // Name is the requested name of the volume
|
||||||
|
Driver string // Driver is the name of the driver that should be used to create the volume
|
||||||
|
DriverOpts map[string]string // DriverOpts holds the driver specific options to use for when creating the volume.
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPAM represents IP Address Management
|
||||||
|
type IPAM struct {
|
||||||
|
Driver string
|
||||||
|
Config []IPAMConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPAMConfig represents IPAM configurations
|
||||||
|
type IPAMConfig struct {
|
||||||
|
Subnet string `json:",omitempty"`
|
||||||
|
IPRange string `json:",omitempty"`
|
||||||
|
Gateway string `json:",omitempty"`
|
||||||
|
AuxAddress map[string]string `json:"AuxiliaryAddresses,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetworkResource is the body of the "get network" http response message
|
||||||
|
type NetworkResource struct {
|
||||||
|
Name string
|
||||||
|
ID string `json:"Id"`
|
||||||
|
Scope string
|
||||||
|
Driver string
|
||||||
|
IPAM IPAM
|
||||||
|
Containers map[string]EndpointResource
|
||||||
|
}
|
||||||
|
|
||||||
|
//EndpointResource contains network resources allocated and usd for a container in a network
|
||||||
|
type EndpointResource struct {
|
||||||
|
EndpointID string
|
||||||
|
MacAddress string
|
||||||
|
IPv4Address string
|
||||||
|
IPv6Address string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetworkCreate is the expected body of the "create network" http request message
|
||||||
|
type NetworkCreate struct {
|
||||||
|
Name string
|
||||||
|
CheckDuplicate bool
|
||||||
|
Driver string
|
||||||
|
IPAM IPAM
|
||||||
|
Options map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetworkCreateResponse is the response message sent by the server for network create call
|
||||||
|
type NetworkCreateResponse struct {
|
||||||
|
ID string `json:"Id"`
|
||||||
|
Warning string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetworkConnect represents the data to be used to connect a container to the network
|
||||||
|
type NetworkConnect struct {
|
||||||
|
Container string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetworkDisconnect represents the data to be used to disconnect a container from the network
|
||||||
|
type NetworkDisconnect struct {
|
||||||
|
Container string
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
package dockerclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newHTTPClient(u *url.URL, tlsConfig *tls.Config, timeout time.Duration) *http.Client {
|
||||||
|
httpTransport := &http.Transport{
|
||||||
|
TLSClientConfig: tlsConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
switch u.Scheme {
|
||||||
|
default:
|
||||||
|
httpTransport.Dial = func(proto, addr string) (net.Conn, error) {
|
||||||
|
return net.DialTimeout(proto, addr, timeout)
|
||||||
|
}
|
||||||
|
case "unix":
|
||||||
|
socketPath := u.Path
|
||||||
|
unixDial := func(proto, addr string) (net.Conn, error) {
|
||||||
|
return net.DialTimeout("unix", socketPath, timeout)
|
||||||
|
}
|
||||||
|
httpTransport.Dial = unixDial
|
||||||
|
// Override the main URL object so the HTTP lib won't complain
|
||||||
|
u.Scheme = "http"
|
||||||
|
u.Host = "unix.sock"
|
||||||
|
u.Path = ""
|
||||||
|
}
|
||||||
|
return &http.Client{Transport: httpTransport}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue