1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #21657 from vdemeester/update-engine-api

Update engine api with required arguments
This commit is contained in:
David Calavera 2016-04-18 19:47:22 -07:00
commit 7fd53f7c71
55 changed files with 505 additions and 384 deletions

View file

@ -48,13 +48,14 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
cli.configFile.DetachKeys = *detachKeys cli.configFile.DetachKeys = *detachKeys
} }
container := cmd.Arg(0)
options := types.ContainerAttachOptions{ options := types.ContainerAttachOptions{
ContainerID: cmd.Arg(0), Stream: true,
Stream: true, Stdin: !*noStdin && c.Config.OpenStdin,
Stdin: !*noStdin && c.Config.OpenStdin, Stdout: true,
Stdout: true, Stderr: true,
Stderr: true, DetachKeys: cli.configFile.DetachKeys,
DetachKeys: cli.configFile.DetachKeys,
} }
var in io.ReadCloser var in io.ReadCloser
@ -63,11 +64,11 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
} }
if *proxy && !c.Config.Tty { if *proxy && !c.Config.Tty {
sigc := cli.forwardAllSignals(options.ContainerID) sigc := cli.forwardAllSignals(container)
defer signal.StopCatch(sigc) defer signal.StopCatch(sigc)
} }
resp, errAttach := cli.client.ContainerAttach(context.Background(), options) resp, errAttach := cli.client.ContainerAttach(context.Background(), container, options)
if errAttach != nil && errAttach != httputil.ErrPersistEOF { if errAttach != nil && errAttach != httputil.ErrPersistEOF {
// ContainerAttach returns an ErrPersistEOF (connection closed) // ContainerAttach returns an ErrPersistEOF (connection closed)
// means server met an error and put it in Hijacked connection // means server met an error and put it in Hijacked connection
@ -98,7 +99,7 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
return errAttach return errAttach
} }
_, status, err := getExitCode(cli, options.ContainerID) _, status, err := getExitCode(cli, container)
if err != nil { if err != nil {
return err return err
} }

View file

@ -212,7 +212,6 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
} }
options := types.ImageBuildOptions{ options := types.ImageBuildOptions{
Context: body,
Memory: memory, Memory: memory,
MemorySwap: memorySwap, MemorySwap: memorySwap,
Tags: flTags.GetAll(), Tags: flTags.GetAll(),
@ -236,7 +235,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
Labels: runconfigopts.ConvertKVStringsToMap(flLabels.GetAll()), Labels: runconfigopts.ConvertKVStringsToMap(flLabels.GetAll()),
} }
response, err := cli.client.ImageBuild(context.Background(), options) response, err := cli.client.ImageBuild(context.Background(), body, options)
if err != nil { if err != nil {
return err return err
} }

View file

@ -2,7 +2,6 @@ package client
import ( import (
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"golang.org/x/net/context" "golang.org/x/net/context"
@ -10,7 +9,6 @@ import (
Cli "github.com/docker/docker/cli" Cli "github.com/docker/docker/cli"
"github.com/docker/docker/opts" "github.com/docker/docker/opts"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/reference"
"github.com/docker/engine-api/types" "github.com/docker/engine-api/types"
"github.com/docker/engine-api/types/container" "github.com/docker/engine-api/types/container"
) )
@ -33,29 +31,10 @@ func (cli *DockerCli) CmdCommit(args ...string) error {
cmd.ParseFlags(args, true) cmd.ParseFlags(args, true)
var ( var (
name = cmd.Arg(0) name = cmd.Arg(0)
repositoryAndTag = cmd.Arg(1) reference = cmd.Arg(1)
repositoryName string
tag string
) )
//Check if the given image name can be resolved
if repositoryAndTag != "" {
ref, err := reference.ParseNamed(repositoryAndTag)
if err != nil {
return err
}
repositoryName = ref.Name()
switch x := ref.(type) {
case reference.Canonical:
return errors.New("cannot commit to digest reference")
case reference.NamedTagged:
tag = x.Tag()
}
}
var config *container.Config var config *container.Config
if *flConfig != "" { if *flConfig != "" {
config = &container.Config{} config = &container.Config{}
@ -65,17 +44,15 @@ func (cli *DockerCli) CmdCommit(args ...string) error {
} }
options := types.ContainerCommitOptions{ options := types.ContainerCommitOptions{
ContainerID: name, Reference: reference,
RepositoryName: repositoryName, Comment: *flComment,
Tag: tag, Author: *flAuthor,
Comment: *flComment, Changes: flChanges.GetAll(),
Author: *flAuthor, Pause: *flPause,
Changes: flChanges.GetAll(), Config: config,
Pause: *flPause,
Config: config,
} }
response, err := cli.client.ContainerCommit(context.Background(), options) response, err := cli.client.ContainerCommit(context.Background(), name, options)
if err != nil { if err != nil {
return err return err
} }

View file

@ -9,6 +9,7 @@ import (
Cli "github.com/docker/docker/cli" Cli "github.com/docker/docker/cli"
"github.com/docker/docker/pkg/jsonmessage" "github.com/docker/docker/pkg/jsonmessage"
// FIXME migrate to docker/distribution/reference
"github.com/docker/docker/reference" "github.com/docker/docker/reference"
"github.com/docker/docker/registry" "github.com/docker/docker/registry"
runconfigopts "github.com/docker/docker/runconfig/opts" runconfigopts "github.com/docker/docker/runconfig/opts"
@ -24,14 +25,6 @@ func (cli *DockerCli) pullImage(image string, out io.Writer) error {
return err return err
} }
var tag string
switch x := reference.WithDefaultTag(ref).(type) {
case reference.Canonical:
tag = x.Digest().String()
case reference.NamedTagged:
tag = x.Tag()
}
// Resolve the Repository name from fqn to RepositoryInfo // Resolve the Repository name from fqn to RepositoryInfo
repoInfo, err := registry.ParseRepositoryInfo(ref) repoInfo, err := registry.ParseRepositoryInfo(ref)
if err != nil { if err != nil {
@ -45,12 +38,10 @@ func (cli *DockerCli) pullImage(image string, out io.Writer) error {
} }
options := types.ImageCreateOptions{ options := types.ImageCreateOptions{
Parent: ref.Name(),
Tag: tag,
RegistryAuth: encodedAuth, RegistryAuth: encodedAuth,
} }
responseBody, err := cli.client.ImageCreate(context.Background(), options) responseBody, err := cli.client.ImageCreate(context.Background(), image, options)
if err != nil { if err != nil {
return err return err
} }

View file

@ -21,8 +21,9 @@ func (cli *DockerCli) CmdExec(args ...string) error {
detachKeys := cmd.String([]string{"-detach-keys"}, "", "Override the key sequence for detaching a container") detachKeys := cmd.String([]string{"-detach-keys"}, "", "Override the key sequence for detaching a container")
execConfig, err := ParseExec(cmd, args) execConfig, err := ParseExec(cmd, args)
container := cmd.Arg(0)
// just in case the ParseExec does not exit // just in case the ParseExec does not exit
if execConfig.Container == "" || err != nil { if container == "" || err != nil {
return Cli.StatusError{StatusCode: 1} return Cli.StatusError{StatusCode: 1}
} }
@ -33,7 +34,7 @@ func (cli *DockerCli) CmdExec(args ...string) error {
// Send client escape keys // Send client escape keys
execConfig.DetachKeys = cli.configFile.DetachKeys execConfig.DetachKeys = cli.configFile.DetachKeys
response, err := cli.client.ContainerExecCreate(context.Background(), *execConfig) response, err := cli.client.ContainerExecCreate(context.Background(), container, *execConfig)
if err != nil { if err != nil {
return err return err
} }
@ -128,13 +129,11 @@ func ParseExec(cmd *flag.FlagSet, args []string) (*types.ExecConfig, error) {
flUser = cmd.String([]string{"u", "-user"}, "", "Username or UID (format: <name|uid>[:<group|gid>])") flUser = cmd.String([]string{"u", "-user"}, "", "Username or UID (format: <name|uid>[:<group|gid>])")
flPrivileged = cmd.Bool([]string{"-privileged"}, false, "Give extended privileges to the command") flPrivileged = cmd.Bool([]string{"-privileged"}, false, "Give extended privileges to the command")
execCmd []string execCmd []string
container string
) )
cmd.Require(flag.Min, 2) cmd.Require(flag.Min, 2)
if err := cmd.ParseFlags(args, true); err != nil { if err := cmd.ParseFlags(args, true); err != nil {
return nil, err return nil, err
} }
container = cmd.Arg(0)
parsedArgs := cmd.Args() parsedArgs := cmd.Args()
execCmd = parsedArgs[1:] execCmd = parsedArgs[1:]
@ -143,7 +142,6 @@ func ParseExec(cmd *flag.FlagSet, args []string) (*types.ExecConfig, error) {
Privileged: *flPrivileged, Privileged: *flPrivileged,
Tty: *flTty, Tty: *flTty,
Cmd: execCmd, Cmd: execCmd,
Container: container,
Detach: *flDetach, Detach: *flDetach,
} }

View file

@ -23,7 +23,6 @@ func TestParseExec(t *testing.T) {
&arguments{ &arguments{
[]string{"container", "command"}, []string{"container", "command"},
}: { }: {
Container: "container",
Cmd: []string{"command"}, Cmd: []string{"command"},
AttachStdout: true, AttachStdout: true,
AttachStderr: true, AttachStderr: true,
@ -31,7 +30,6 @@ func TestParseExec(t *testing.T) {
&arguments{ &arguments{
[]string{"container", "command1", "command2"}, []string{"container", "command1", "command2"},
}: { }: {
Container: "container",
Cmd: []string{"command1", "command2"}, Cmd: []string{"command1", "command2"},
AttachStdout: true, AttachStdout: true,
AttachStderr: true, AttachStderr: true,
@ -44,7 +42,6 @@ func TestParseExec(t *testing.T) {
AttachStdout: true, AttachStdout: true,
AttachStderr: true, AttachStderr: true,
Tty: true, Tty: true,
Container: "container",
Cmd: []string{"command"}, Cmd: []string{"command"},
}, },
&arguments{ &arguments{
@ -54,7 +51,6 @@ func TestParseExec(t *testing.T) {
AttachStdout: false, AttachStdout: false,
AttachStderr: false, AttachStderr: false,
Detach: true, Detach: true,
Container: "container",
Cmd: []string{"command"}, Cmd: []string{"command"},
}, },
&arguments{ &arguments{
@ -65,7 +61,6 @@ func TestParseExec(t *testing.T) {
AttachStderr: false, AttachStderr: false,
Detach: true, Detach: true,
Tty: true, Tty: true,
Container: "container",
Cmd: []string{"command"}, Cmd: []string{"command"},
}, },
} }
@ -103,9 +98,6 @@ func compareExecConfig(config1 *types.ExecConfig, config2 *types.ExecConfig) boo
if config1.AttachStdout != config2.AttachStdout { if config1.AttachStdout != config2.AttachStdout {
return false return false
} }
if config1.Container != config2.Container {
return false
}
if config1.Detach != config2.Detach { if config1.Detach != config2.Detach {
return false return false
} }

View file

@ -12,7 +12,6 @@ import (
"github.com/docker/docker/pkg/jsonmessage" "github.com/docker/docker/pkg/jsonmessage"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/urlutil" "github.com/docker/docker/pkg/urlutil"
"github.com/docker/docker/reference"
"github.com/docker/engine-api/types" "github.com/docker/engine-api/types"
) )
@ -31,26 +30,20 @@ func (cli *DockerCli) CmdImport(args ...string) error {
cmd.ParseFlags(args, true) cmd.ParseFlags(args, true)
var ( var (
in io.Reader in io.Reader
tag string tag string
src = cmd.Arg(0) src = cmd.Arg(0)
srcName = src srcName = src
repository = cmd.Arg(1) ref = cmd.Arg(1)
changes = flChanges.GetAll() changes = flChanges.GetAll()
) )
if cmd.NArg() == 3 { if cmd.NArg() == 3 {
// FIXME(vdemeester) Which version has this been deprecated ? should we remove it ?
fmt.Fprintf(cli.err, "[DEPRECATED] The format 'file|URL|- [REPOSITORY [TAG]]' has been deprecated. Please use file|URL|- [REPOSITORY[:TAG]]\n") fmt.Fprintf(cli.err, "[DEPRECATED] The format 'file|URL|- [REPOSITORY [TAG]]' has been deprecated. Please use file|URL|- [REPOSITORY[:TAG]]\n")
tag = cmd.Arg(2) tag = cmd.Arg(2)
} }
if repository != "" {
//Check if the given image name can be resolved
if _, err := reference.ParseNamed(repository); err != nil {
return err
}
}
if src == "-" { if src == "-" {
in = cli.in in = cli.in
} else if !urlutil.IsURL(src) { } else if !urlutil.IsURL(src) {
@ -63,16 +56,18 @@ func (cli *DockerCli) CmdImport(args ...string) error {
in = file in = file
} }
options := types.ImageImportOptions{ source := types.ImageImportSource{
Source: in, Source: in,
SourceName: srcName, SourceName: srcName,
RepositoryName: repository,
Message: *message,
Tag: tag,
Changes: changes,
} }
responseBody, err := cli.client.ImageImport(context.Background(), options) options := types.ImageImportOptions{
Message: *message,
Tag: tag,
Changes: changes,
}
responseBody, err := cli.client.ImageImport(context.Background(), source, ref, options)
if err != nil { if err != nil {
return err return err
} }

View file

@ -42,15 +42,14 @@ func (cli *DockerCli) CmdLogs(args ...string) error {
} }
options := types.ContainerLogsOptions{ options := types.ContainerLogsOptions{
ContainerID: name, ShowStdout: true,
ShowStdout: true, ShowStderr: true,
ShowStderr: true, Since: *since,
Since: *since, Timestamps: *times,
Timestamps: *times, Follow: *follow,
Follow: *follow, Tail: *tail,
Tail: *tail,
} }
responseBody, err := cli.client.ContainerLogs(context.Background(), options) responseBody, err := cli.client.ContainerLogs(context.Background(), name, options)
if err != nil { if err != nil {
return err return err
} }

View file

@ -77,7 +77,6 @@ func (cli *DockerCli) CmdNetworkCreate(args ...string) error {
// Construct network create request body // Construct network create request body
nc := types.NetworkCreate{ nc := types.NetworkCreate{
Name: cmd.Arg(0),
Driver: driver, Driver: driver,
IPAM: network.IPAM{Driver: *flIpamDriver, Config: ipamCfg, Options: flIpamOpt.GetAll()}, IPAM: network.IPAM{Driver: *flIpamDriver, Config: ipamCfg, Options: flIpamOpt.GetAll()},
Options: flOpts.GetAll(), Options: flOpts.GetAll(),
@ -87,7 +86,7 @@ func (cli *DockerCli) CmdNetworkCreate(args ...string) error {
Labels: runconfigopts.ConvertKVStringsToMap(flLabels.GetAll()), Labels: runconfigopts.ConvertKVStringsToMap(flLabels.GetAll()),
} }
resp, err := cli.client.NetworkCreate(context.Background(), nc) resp, err := cli.client.NetworkCreate(context.Background(), cmd.Arg(0), nc)
if err != nil { if err != nil {
return err return err
} }

View file

@ -11,7 +11,6 @@ import (
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/reference" "github.com/docker/docker/reference"
"github.com/docker/docker/registry" "github.com/docker/docker/registry"
"github.com/docker/engine-api/client"
"github.com/docker/engine-api/types" "github.com/docker/engine-api/types"
) )
@ -48,7 +47,7 @@ func (cli *DockerCli) CmdPull(args ...string) error {
tag = x.Tag() tag = x.Tag()
} }
ref := registry.ParseReference(tag) registryRef := registry.ParseReference(tag)
// Resolve the Repository name from fqn to RepositoryInfo // Resolve the Repository name from fqn to RepositoryInfo
repoInfo, err := registry.ParseRepositoryInfo(distributionRef) repoInfo, err := registry.ParseRepositoryInfo(distributionRef)
@ -59,27 +58,26 @@ func (cli *DockerCli) CmdPull(args ...string) error {
authConfig := cli.resolveAuthConfig(repoInfo.Index) authConfig := cli.resolveAuthConfig(repoInfo.Index)
requestPrivilege := cli.registryAuthenticationPrivilegedFunc(repoInfo.Index, "pull") requestPrivilege := cli.registryAuthenticationPrivilegedFunc(repoInfo.Index, "pull")
if isTrusted() && !ref.HasDigest() { if isTrusted() && !registryRef.HasDigest() {
// Check if tag is digest // Check if tag is digest
return cli.trustedPull(repoInfo, ref, authConfig, requestPrivilege) return cli.trustedPull(repoInfo, registryRef, authConfig, requestPrivilege)
} }
return cli.imagePullPrivileged(authConfig, distributionRef.String(), "", requestPrivilege) return cli.imagePullPrivileged(authConfig, distributionRef.String(), requestPrivilege)
} }
func (cli *DockerCli) imagePullPrivileged(authConfig types.AuthConfig, imageID, tag string, requestPrivilege client.RequestPrivilegeFunc) error { func (cli *DockerCli) imagePullPrivileged(authConfig types.AuthConfig, ref string, requestPrivilege types.RequestPrivilegeFunc) error {
encodedAuth, err := encodeAuthToBase64(authConfig) encodedAuth, err := encodeAuthToBase64(authConfig)
if err != nil { if err != nil {
return err return err
} }
options := types.ImagePullOptions{ options := types.ImagePullOptions{
ImageID: imageID, RegistryAuth: encodedAuth,
Tag: tag, PrivilegeFunc: requestPrivilege,
RegistryAuth: encodedAuth,
} }
responseBody, err := cli.client.ImagePull(context.Background(), options, requestPrivilege) responseBody, err := cli.client.ImagePull(context.Background(), ref, options)
if err != nil { if err != nil {
return err return err
} }

View file

@ -1,7 +1,6 @@
package client package client
import ( import (
"errors"
"io" "io"
"golang.org/x/net/context" "golang.org/x/net/context"
@ -11,7 +10,6 @@ import (
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/reference" "github.com/docker/docker/reference"
"github.com/docker/docker/registry" "github.com/docker/docker/registry"
"github.com/docker/engine-api/client"
"github.com/docker/engine-api/types" "github.com/docker/engine-api/types"
) )
@ -30,14 +28,6 @@ func (cli *DockerCli) CmdPush(args ...string) error {
return err return err
} }
var tag string
switch x := ref.(type) {
case reference.Canonical:
return errors.New("cannot push a digest reference")
case reference.NamedTagged:
tag = x.Tag()
}
// Resolve the Repository name from fqn to RepositoryInfo // Resolve the Repository name from fqn to RepositoryInfo
repoInfo, err := registry.ParseRepositoryInfo(ref) repoInfo, err := registry.ParseRepositoryInfo(ref)
if err != nil { if err != nil {
@ -48,10 +38,10 @@ func (cli *DockerCli) CmdPush(args ...string) error {
requestPrivilege := cli.registryAuthenticationPrivilegedFunc(repoInfo.Index, "push") requestPrivilege := cli.registryAuthenticationPrivilegedFunc(repoInfo.Index, "push")
if isTrusted() { if isTrusted() {
return cli.trustedPush(repoInfo, tag, authConfig, requestPrivilege) return cli.trustedPush(repoInfo, ref, authConfig, requestPrivilege)
} }
responseBody, err := cli.imagePushPrivileged(authConfig, ref.Name(), tag, requestPrivilege) responseBody, err := cli.imagePushPrivileged(authConfig, ref.String(), requestPrivilege)
if err != nil { if err != nil {
return err return err
} }
@ -61,16 +51,15 @@ func (cli *DockerCli) CmdPush(args ...string) error {
return jsonmessage.DisplayJSONMessagesStream(responseBody, cli.out, cli.outFd, cli.isTerminalOut, nil) return jsonmessage.DisplayJSONMessagesStream(responseBody, cli.out, cli.outFd, cli.isTerminalOut, nil)
} }
func (cli *DockerCli) imagePushPrivileged(authConfig types.AuthConfig, imageID, tag string, requestPrivilege client.RequestPrivilegeFunc) (io.ReadCloser, error) { func (cli *DockerCli) imagePushPrivileged(authConfig types.AuthConfig, ref string, requestPrivilege types.RequestPrivilegeFunc) (io.ReadCloser, error) {
encodedAuth, err := encodeAuthToBase64(authConfig) encodedAuth, err := encodeAuthToBase64(authConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
options := types.ImagePushOptions{ options := types.ImagePushOptions{
ImageID: imageID, RegistryAuth: encodedAuth,
Tag: tag, PrivilegeFunc: requestPrivilege,
RegistryAuth: encodedAuth,
} }
return cli.client.ImagePush(context.Background(), options, requestPrivilege) return cli.client.ImagePush(context.Background(), ref, options)
} }

View file

@ -42,14 +42,13 @@ func (cli *DockerCli) CmdRm(args ...string) error {
return nil return nil
} }
func (cli *DockerCli) removeContainer(containerID string, removeVolumes, removeLinks, force bool) error { func (cli *DockerCli) removeContainer(container string, removeVolumes, removeLinks, force bool) error {
options := types.ContainerRemoveOptions{ options := types.ContainerRemoveOptions{
ContainerID: containerID,
RemoveVolumes: removeVolumes, RemoveVolumes: removeVolumes,
RemoveLinks: removeLinks, RemoveLinks: removeLinks,
Force: force, Force: force,
} }
if err := cli.client.ContainerRemove(context.Background(), options); err != nil { if err := cli.client.ContainerRemove(context.Background(), container, options); err != nil {
return err return err
} }
return nil return nil

View file

@ -32,14 +32,13 @@ func (cli *DockerCli) CmdRmi(args ...string) error {
} }
var errs []string var errs []string
for _, name := range cmd.Args() { for _, image := range cmd.Args() {
options := types.ImageRemoveOptions{ options := types.ImageRemoveOptions{
ImageID: name,
Force: *force, Force: *force,
PruneChildren: !*noprune, PruneChildren: !*noprune,
} }
dels, err := cli.client.ImageRemove(context.Background(), options) dels, err := cli.client.ImageRemove(context.Background(), image, options)
if err != nil { if err != nil {
errs = append(errs, err.Error()) errs = append(errs, err.Error())
} else { } else {

View file

@ -198,15 +198,14 @@ func (cli *DockerCli) CmdRun(args ...string) error {
} }
options := types.ContainerAttachOptions{ options := types.ContainerAttachOptions{
ContainerID: createResponse.ID, Stream: true,
Stream: true, Stdin: config.AttachStdin,
Stdin: config.AttachStdin, Stdout: config.AttachStdout,
Stdout: config.AttachStdout, Stderr: config.AttachStderr,
Stderr: config.AttachStderr, DetachKeys: cli.configFile.DetachKeys,
DetachKeys: cli.configFile.DetachKeys,
} }
resp, errAttach := cli.client.ContainerAttach(context.Background(), options) resp, errAttach := cli.client.ContainerAttach(context.Background(), createResponse.ID, options)
if errAttach != nil && errAttach != httputil.ErrPersistEOF { if errAttach != nil && errAttach != httputil.ErrPersistEOF {
// ContainerAttach returns an ErrPersistEOF (connection closed) // ContainerAttach returns an ErrPersistEOF (connection closed)
// means server met an error and put it in Hijacked connection // means server met an error and put it in Hijacked connection

View file

@ -47,11 +47,11 @@ func (cli *DockerCli) CmdSearch(args ...string) error {
} }
options := types.ImageSearchOptions{ options := types.ImageSearchOptions{
Term: name, RegistryAuth: encodedAuth,
RegistryAuth: encodedAuth, PrivilegeFunc: requestPrivilege,
} }
unorderedResults, err := cli.client.ImageSearch(context.Background(), options, requestPrivilege) unorderedResults, err := cli.client.ImageSearch(context.Background(), name, options)
if err != nil { if err != nil {
return err return err
} }

View file

@ -65,14 +65,14 @@ func (cli *DockerCli) CmdStart(args ...string) error {
} }
// 2. Attach to the container. // 2. Attach to the container.
containerID := cmd.Arg(0) container := cmd.Arg(0)
c, err := cli.client.ContainerInspect(context.Background(), containerID) c, err := cli.client.ContainerInspect(context.Background(), container)
if err != nil { if err != nil {
return err return err
} }
if !c.Config.Tty { if !c.Config.Tty {
sigc := cli.forwardAllSignals(containerID) sigc := cli.forwardAllSignals(container)
defer signal.StopCatch(sigc) defer signal.StopCatch(sigc)
} }
@ -81,12 +81,11 @@ func (cli *DockerCli) CmdStart(args ...string) error {
} }
options := types.ContainerAttachOptions{ options := types.ContainerAttachOptions{
ContainerID: containerID, Stream: true,
Stream: true, Stdin: *openStdin && c.Config.OpenStdin,
Stdin: *openStdin && c.Config.OpenStdin, Stdout: true,
Stdout: true, Stderr: true,
Stderr: true, DetachKeys: cli.configFile.DetachKeys,
DetachKeys: cli.configFile.DetachKeys,
} }
var in io.ReadCloser var in io.ReadCloser
@ -95,7 +94,7 @@ func (cli *DockerCli) CmdStart(args ...string) error {
in = cli.in in = cli.in
} }
resp, errAttach := cli.client.ContainerAttach(context.Background(), options) resp, errAttach := cli.client.ContainerAttach(context.Background(), container, options)
if errAttach != nil && errAttach != httputil.ErrPersistEOF { if errAttach != nil && errAttach != httputil.ErrPersistEOF {
// ContainerAttach return an ErrPersistEOF (connection closed) // ContainerAttach return an ErrPersistEOF (connection closed)
// means server met an error and put it in Hijacked connection // means server met an error and put it in Hijacked connection
@ -113,7 +112,7 @@ func (cli *DockerCli) CmdStart(args ...string) error {
}) })
// 3. Start the container. // 3. Start the container.
if err := cli.client.ContainerStart(context.Background(), containerID); err != nil { if err := cli.client.ContainerStart(context.Background(), container); err != nil {
cancelFun() cancelFun()
<-cErr <-cErr
return err return err
@ -121,14 +120,14 @@ func (cli *DockerCli) CmdStart(args ...string) error {
// 4. Wait for attachment to break. // 4. Wait for attachment to break.
if c.Config.Tty && cli.isTerminalOut { if c.Config.Tty && cli.isTerminalOut {
if err := cli.monitorTtySize(containerID, false); err != nil { if err := cli.monitorTtySize(container, false); err != nil {
fmt.Fprintf(cli.err, "Error monitoring TTY size: %s\n", err) fmt.Fprintf(cli.err, "Error monitoring TTY size: %s\n", err)
} }
} }
if attchErr := <-cErr; attchErr != nil { if attchErr := <-cErr; attchErr != nil {
return attchErr return attchErr
} }
_, status, err := getExitCode(cli, containerID) _, status, err := getExitCode(cli, container)
if err != nil { if err != nil {
return err return err
} }
@ -144,14 +143,14 @@ func (cli *DockerCli) CmdStart(args ...string) error {
return nil return nil
} }
func (cli *DockerCli) startContainersWithoutAttachments(containerIDs []string) error { func (cli *DockerCli) startContainersWithoutAttachments(containers []string) error {
var failedContainers []string var failedContainers []string
for _, containerID := range containerIDs { for _, container := range containers {
if err := cli.client.ContainerStart(context.Background(), containerID); err != nil { if err := cli.client.ContainerStart(context.Background(), container); err != nil {
fmt.Fprintf(cli.err, "%s\n", err) fmt.Fprintf(cli.err, "%s\n", err)
failedContainers = append(failedContainers, containerID) failedContainers = append(failedContainers, container)
} else { } else {
fmt.Fprintf(cli.out, "%s\n", containerID) fmt.Fprintf(cli.out, "%s\n", container)
} }
} }

View file

@ -1,13 +1,10 @@
package client package client
import ( import (
"errors"
"golang.org/x/net/context" "golang.org/x/net/context"
Cli "github.com/docker/docker/cli" Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/reference"
"github.com/docker/engine-api/types" "github.com/docker/engine-api/types"
) )
@ -21,26 +18,9 @@ func (cli *DockerCli) CmdTag(args ...string) error {
cmd.ParseFlags(args, true) cmd.ParseFlags(args, true)
ref, err := reference.ParseNamed(cmd.Arg(1))
if err != nil {
return err
}
if _, isCanonical := ref.(reference.Canonical); isCanonical {
return errors.New("refusing to create a tag with a digest reference")
}
var tag string
if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
tag = tagged.Tag()
}
options := types.ImageTagOptions{ options := types.ImageTagOptions{
ImageID: cmd.Arg(0), Force: *force,
RepositoryName: ref.Name(),
Tag: tag,
Force: *force,
} }
return cli.client.ImageTag(context.Background(), options) return cli.client.ImageTag(context.Background(), cmd.Arg(0), cmd.Arg(1), options)
} }

View file

@ -27,7 +27,6 @@ import (
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/reference" "github.com/docker/docker/reference"
"github.com/docker/docker/registry" "github.com/docker/docker/registry"
apiclient "github.com/docker/engine-api/client"
"github.com/docker/engine-api/types" "github.com/docker/engine-api/types"
registrytypes "github.com/docker/engine-api/types/registry" registrytypes "github.com/docker/engine-api/types/registry"
"github.com/docker/go-connections/tlsconfig" "github.com/docker/go-connections/tlsconfig"
@ -280,13 +279,10 @@ func (cli *DockerCli) tagTrusted(trustedRef reference.Canonical, ref reference.N
fmt.Fprintf(cli.out, "Tagging %s as %s\n", trustedRef.String(), ref.String()) fmt.Fprintf(cli.out, "Tagging %s as %s\n", trustedRef.String(), ref.String())
options := types.ImageTagOptions{ options := types.ImageTagOptions{
ImageID: trustedRef.String(), Force: true,
RepositoryName: trustedRef.Name(),
Tag: ref.Tag(),
Force: true,
} }
return cli.client.ImageTag(context.Background(), options) return cli.client.ImageTag(context.Background(), trustedRef.String(), ref.String(), options)
} }
func notaryError(repoName string, err error) error { func notaryError(repoName string, err error) error {
@ -319,7 +315,7 @@ func notaryError(repoName string, err error) error {
return err return err
} }
func (cli *DockerCli) trustedPull(repoInfo *registry.RepositoryInfo, ref registry.Reference, authConfig types.AuthConfig, requestPrivilege apiclient.RequestPrivilegeFunc) error { func (cli *DockerCli) trustedPull(repoInfo *registry.RepositoryInfo, ref registry.Reference, authConfig types.AuthConfig, requestPrivilege types.RequestPrivilegeFunc) error {
var refs []target var refs []target
notaryRepo, err := cli.getNotaryRepository(repoInfo, authConfig, "pull") notaryRepo, err := cli.getNotaryRepository(repoInfo, authConfig, "pull")
@ -377,7 +373,11 @@ func (cli *DockerCli) trustedPull(repoInfo *registry.RepositoryInfo, ref registr
} }
fmt.Fprintf(cli.out, "Pull (%d of %d): %s%s@%s\n", i+1, len(refs), repoInfo.Name(), displayTag, r.digest) fmt.Fprintf(cli.out, "Pull (%d of %d): %s%s@%s\n", i+1, len(refs), repoInfo.Name(), displayTag, r.digest)
if err := cli.imagePullPrivileged(authConfig, repoInfo.Name(), r.digest.String(), requestPrivilege); err != nil { ref, err := reference.WithDigest(repoInfo, r.digest)
if err != nil {
return err
}
if err := cli.imagePullPrivileged(authConfig, ref.String(), requestPrivilege); err != nil {
return err return err
} }
@ -399,8 +399,8 @@ func (cli *DockerCli) trustedPull(repoInfo *registry.RepositoryInfo, ref registr
return nil return nil
} }
func (cli *DockerCli) trustedPush(repoInfo *registry.RepositoryInfo, tag string, authConfig types.AuthConfig, requestPrivilege apiclient.RequestPrivilegeFunc) error { func (cli *DockerCli) trustedPush(repoInfo *registry.RepositoryInfo, ref reference.Named, authConfig types.AuthConfig, requestPrivilege types.RequestPrivilegeFunc) error {
responseBody, err := cli.imagePushPrivileged(authConfig, repoInfo.Name(), tag, requestPrivilege) responseBody, err := cli.imagePushPrivileged(authConfig, ref.String(), requestPrivilege)
if err != nil { if err != nil {
return err return err
} }
@ -434,6 +434,14 @@ func (cli *DockerCli) trustedPush(repoInfo *registry.RepositoryInfo, tag string,
} }
} }
var tag string
switch x := ref.(type) {
case reference.Canonical:
return errors.New("cannot push a digest reference")
case reference.NamedTagged:
tag = x.Tag()
}
// We want trust signatures to always take an explicit tag, // We want trust signatures to always take an explicit tag,
// otherwise it will act as an untrusted push. // otherwise it will act as an untrusted push.
if tag == "" { if tag == "" {

View file

@ -46,7 +46,7 @@ func encodeAuthToBase64(authConfig types.AuthConfig) (string, error) {
return base64.URLEncoding.EncodeToString(buf), nil return base64.URLEncoding.EncodeToString(buf), nil
} }
func (cli *DockerCli) registryAuthenticationPrivilegedFunc(index *registrytypes.IndexInfo, cmdName string) client.RequestPrivilegeFunc { func (cli *DockerCli) registryAuthenticationPrivilegedFunc(index *registrytypes.IndexInfo, cmdName string) types.RequestPrivilegeFunc {
return func() (string, error) { return func() (string, error) {
fmt.Fprintf(cli.out, "\nPlease login prior to %s:\n", cmdName) fmt.Fprintf(cli.out, "\nPlease login prior to %s:\n", cmdName)
indexServer := registry.GetAuthConfigKey(index) indexServer := registry.GetAuthConfigKey(index)
@ -69,16 +69,15 @@ func (cli *DockerCli) resizeTtyTo(id string, height, width int, isExec bool) {
} }
options := types.ResizeOptions{ options := types.ResizeOptions{
ID: id,
Height: height, Height: height,
Width: width, Width: width,
} }
var err error var err error
if isExec { if isExec {
err = cli.client.ContainerExecResize(context.Background(), options) err = cli.client.ContainerExecResize(context.Background(), id, options)
} else { } else {
err = cli.client.ContainerResize(context.Background(), options) err = cli.client.ContainerResize(context.Background(), id, options)
} }
if err != nil { if err != nil {

View file

@ -15,7 +15,7 @@ import (
// execBackend includes functions to implement to provide exec functionality. // execBackend includes functions to implement to provide exec functionality.
type execBackend interface { type execBackend interface {
ContainerExecCreate(config *types.ExecConfig) (string, error) ContainerExecCreate(name string, config *types.ExecConfig) (string, error)
ContainerExecInspect(id string) (*backend.ExecInspect, error) ContainerExecInspect(id string) (*backend.ExecInspect, error)
ContainerExecResize(name string, height, width int) error ContainerExecResize(name string, height, width int) error
ContainerExecStart(name string, stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) error ContainerExecStart(name string, stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) error

View file

@ -36,14 +36,13 @@ func (s *containerRouter) postContainerExecCreate(ctx context.Context, w http.Re
if err := json.NewDecoder(r.Body).Decode(execConfig); err != nil { if err := json.NewDecoder(r.Body).Decode(execConfig); err != nil {
return err return err
} }
execConfig.Container = name
if len(execConfig.Cmd) == 0 { if len(execConfig.Cmd) == 0 {
return fmt.Errorf("No exec command specified") return fmt.Errorf("No exec command specified")
} }
// Register an instance of Exec in container. // Register an instance of Exec in container.
id, err := s.backend.ContainerExecCreate(execConfig) id, err := s.backend.ContainerExecCreate(name, execConfig)
if err != nil { if err != nil {
logrus.Errorf("Error setting up exec command in container %s: %v", name, err) logrus.Errorf("Error setting up exec command in container %s: %v", name, err)
return err return err

View file

@ -14,7 +14,7 @@ type Backend interface {
GetNetworkByName(idName string) (libnetwork.Network, error) GetNetworkByName(idName string) (libnetwork.Network, error)
GetNetworksByID(partialID string) []libnetwork.Network GetNetworksByID(partialID string) []libnetwork.Network
FilterNetworks(netFilters filters.Args) ([]libnetwork.Network, error) FilterNetworks(netFilters filters.Args) ([]libnetwork.Network, error)
CreateNetwork(types.NetworkCreate) (*types.NetworkCreateResponse, error) CreateNetwork(nc types.NetworkCreateRequest) (*types.NetworkCreateResponse, error)
ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error
DisconnectContainerFromNetwork(containerName string, network libnetwork.Network, force bool) error DisconnectContainerFromNetwork(containerName string, network libnetwork.Network, force bool) error
DeleteNetwork(name string) error DeleteNetwork(name string) error

View file

@ -51,7 +51,7 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r
} }
func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
var create types.NetworkCreate var create types.NetworkCreateRequest
if err := httputils.ParseForm(r); err != nil { if err := httputils.ParseForm(r); err != nil {
return err return err

View file

@ -88,8 +88,8 @@ func (d *Daemon) getActiveContainer(name string) (*container.Container, error) {
} }
// ContainerExecCreate sets up an exec in a running container. // ContainerExecCreate sets up an exec in a running container.
func (d *Daemon) ContainerExecCreate(config *types.ExecConfig) (string, error) { func (d *Daemon) ContainerExecCreate(name string, config *types.ExecConfig) (string, error) {
container, err := d.getActiveContainer(config.Container) container, err := d.getActiveContainer(name)
if err != nil { if err != nil {
return "", err return "", err
} }

View file

@ -94,7 +94,7 @@ func (daemon *Daemon) getAllNetworks() []libnetwork.Network {
} }
// CreateNetwork creates a network with the given name, driver and other optional parameters // CreateNetwork creates a network with the given name, driver and other optional parameters
func (daemon *Daemon) CreateNetwork(create types.NetworkCreate) (*types.NetworkCreateResponse, error) { func (daemon *Daemon) CreateNetwork(create types.NetworkCreateRequest) (*types.NetworkCreateResponse, error) {
if runconfig.IsPreDefinedNetwork(create.Name) { if runconfig.IsPreDefinedNetwork(create.Name) {
err := fmt.Errorf("%s is a pre-defined network and cannot be created", create.Name) err := fmt.Errorf("%s is a pre-defined network and cannot be created", create.Name)
return nil, errors.NewErrorWithStatusCode(err, http.StatusForbidden) return nil, errors.NewErrorWithStatusCode(err, http.StatusForbidden)

View file

@ -25,7 +25,7 @@ clone git golang.org/x/net 78cb2c067747f08b343f20614155233ab4ea2ad3 https://gith
clone git golang.org/x/sys eb2c74142fd19a79b3f237334c7384d5167b1b46 https://github.com/golang/sys.git clone git golang.org/x/sys eb2c74142fd19a79b3f237334c7384d5167b1b46 https://github.com/golang/sys.git
clone git github.com/docker/go-units 651fc226e7441360384da338d0fd37f2440ffbe3 clone git github.com/docker/go-units 651fc226e7441360384da338d0fd37f2440ffbe3
clone git github.com/docker/go-connections v0.2.0 clone git github.com/docker/go-connections v0.2.0
clone git github.com/docker/engine-api 8924d6900370b4c7e7984be5adc61f50a80d7537 clone git github.com/docker/engine-api a6dca654f28f26b648115649f6382252ada81119
clone git github.com/RackSec/srslog 259aed10dfa74ea2961eddd1d9847619f6e98837 clone git github.com/RackSec/srslog 259aed10dfa74ea2961eddd1d9847619f6e98837
clone git github.com/imdario/mergo 0.2.1 clone git github.com/imdario/mergo 0.2.1

View file

@ -28,9 +28,11 @@ func (s *DockerSuite) TestApiNetworkCreateDelete(c *check.C) {
testRequires(c, DaemonIsLinux) testRequires(c, DaemonIsLinux)
// Create a network // Create a network
name := "testnetwork" name := "testnetwork"
config := types.NetworkCreate{ config := types.NetworkCreateRequest{
Name: name, Name: name,
CheckDuplicate: true, NetworkCreate: types.NetworkCreate{
CheckDuplicate: true,
},
} }
id := createNetwork(c, config, true) id := createNetwork(c, config, true)
c.Assert(isNetworkAvailable(c, name), checker.Equals, true) c.Assert(isNetworkAvailable(c, name), checker.Equals, true)
@ -43,13 +45,17 @@ func (s *DockerSuite) TestApiNetworkCreateDelete(c *check.C) {
func (s *DockerSuite) TestApiNetworkCreateCheckDuplicate(c *check.C) { func (s *DockerSuite) TestApiNetworkCreateCheckDuplicate(c *check.C) {
testRequires(c, DaemonIsLinux) testRequires(c, DaemonIsLinux)
name := "testcheckduplicate" name := "testcheckduplicate"
configOnCheck := types.NetworkCreate{ configOnCheck := types.NetworkCreateRequest{
Name: name, Name: name,
CheckDuplicate: true, NetworkCreate: types.NetworkCreate{
CheckDuplicate: true,
},
} }
configNotCheck := types.NetworkCreate{ configNotCheck := types.NetworkCreateRequest{
Name: name, Name: name,
CheckDuplicate: false, NetworkCreate: types.NetworkCreate{
CheckDuplicate: false,
},
} }
// Creating a new network first // Creating a new network first
@ -99,11 +105,13 @@ func (s *DockerSuite) TestApiNetworkInspect(c *check.C) {
Driver: "default", Driver: "default",
Config: []network.IPAMConfig{{Subnet: "172.28.0.0/16", IPRange: "172.28.5.0/24", Gateway: "172.28.5.254"}}, Config: []network.IPAMConfig{{Subnet: "172.28.0.0/16", IPRange: "172.28.5.0/24", Gateway: "172.28.5.254"}},
} }
config := types.NetworkCreate{ config := types.NetworkCreateRequest{
Name: "br0", Name: "br0",
Driver: "bridge", NetworkCreate: types.NetworkCreate{
IPAM: ipam, Driver: "bridge",
Options: map[string]string{"foo": "bar", "opts": "dopts"}, IPAM: ipam,
Options: map[string]string{"foo": "bar", "opts": "dopts"},
},
} }
id0 := createNetwork(c, config, true) id0 := createNetwork(c, config, true)
c.Assert(isNetworkAvailable(c, "br0"), checker.Equals, true) c.Assert(isNetworkAvailable(c, "br0"), checker.Equals, true)
@ -125,7 +133,7 @@ func (s *DockerSuite) TestApiNetworkConnectDisconnect(c *check.C) {
testRequires(c, DaemonIsLinux) testRequires(c, DaemonIsLinux)
// Create test network // Create test network
name := "testnetwork" name := "testnetwork"
config := types.NetworkCreate{ config := types.NetworkCreateRequest{
Name: name, Name: name,
} }
id := createNetwork(c, config, true) id := createNetwork(c, config, true)
@ -169,10 +177,12 @@ func (s *DockerSuite) TestApiNetworkIpamMultipleBridgeNetworks(c *check.C) {
Driver: "default", Driver: "default",
Config: []network.IPAMConfig{{Subnet: "192.178.0.0/16", IPRange: "192.178.128.0/17", Gateway: "192.178.138.100"}}, Config: []network.IPAMConfig{{Subnet: "192.178.0.0/16", IPRange: "192.178.128.0/17", Gateway: "192.178.138.100"}},
} }
config0 := types.NetworkCreate{ config0 := types.NetworkCreateRequest{
Name: "test0", Name: "test0",
Driver: "bridge", NetworkCreate: types.NetworkCreate{
IPAM: ipam0, Driver: "bridge",
IPAM: ipam0,
},
} }
id0 := createNetwork(c, config0, true) id0 := createNetwork(c, config0, true)
c.Assert(isNetworkAvailable(c, "test0"), checker.Equals, true) c.Assert(isNetworkAvailable(c, "test0"), checker.Equals, true)
@ -182,10 +192,12 @@ func (s *DockerSuite) TestApiNetworkIpamMultipleBridgeNetworks(c *check.C) {
Config: []network.IPAMConfig{{Subnet: "192.178.128.0/17", Gateway: "192.178.128.1"}}, Config: []network.IPAMConfig{{Subnet: "192.178.128.0/17", Gateway: "192.178.128.1"}},
} }
// test1 bridge network overlaps with test0 // test1 bridge network overlaps with test0
config1 := types.NetworkCreate{ config1 := types.NetworkCreateRequest{
Name: "test1", Name: "test1",
Driver: "bridge", NetworkCreate: types.NetworkCreate{
IPAM: ipam1, Driver: "bridge",
IPAM: ipam1,
},
} }
createNetwork(c, config1, false) createNetwork(c, config1, false)
c.Assert(isNetworkAvailable(c, "test1"), checker.Equals, false) c.Assert(isNetworkAvailable(c, "test1"), checker.Equals, false)
@ -195,10 +207,12 @@ func (s *DockerSuite) TestApiNetworkIpamMultipleBridgeNetworks(c *check.C) {
Config: []network.IPAMConfig{{Subnet: "192.169.0.0/16", Gateway: "192.169.100.100"}}, Config: []network.IPAMConfig{{Subnet: "192.169.0.0/16", Gateway: "192.169.100.100"}},
} }
// test2 bridge network does not overlap // test2 bridge network does not overlap
config2 := types.NetworkCreate{ config2 := types.NetworkCreateRequest{
Name: "test2", Name: "test2",
Driver: "bridge", NetworkCreate: types.NetworkCreate{
IPAM: ipam2, Driver: "bridge",
IPAM: ipam2,
},
} }
createNetwork(c, config2, true) createNetwork(c, config2, true)
c.Assert(isNetworkAvailable(c, "test2"), checker.Equals, true) c.Assert(isNetworkAvailable(c, "test2"), checker.Equals, true)
@ -209,11 +223,11 @@ func (s *DockerSuite) TestApiNetworkIpamMultipleBridgeNetworks(c *check.C) {
c.Assert(isNetworkAvailable(c, "test1"), checker.Equals, true) c.Assert(isNetworkAvailable(c, "test1"), checker.Equals, true)
// for networks w/o ipam specified, docker will choose proper non-overlapping subnets // for networks w/o ipam specified, docker will choose proper non-overlapping subnets
createNetwork(c, types.NetworkCreate{Name: "test3"}, true) createNetwork(c, types.NetworkCreateRequest{Name: "test3"}, true)
c.Assert(isNetworkAvailable(c, "test3"), checker.Equals, true) c.Assert(isNetworkAvailable(c, "test3"), checker.Equals, true)
createNetwork(c, types.NetworkCreate{Name: "test4"}, true) createNetwork(c, types.NetworkCreateRequest{Name: "test4"}, true)
c.Assert(isNetworkAvailable(c, "test4"), checker.Equals, true) c.Assert(isNetworkAvailable(c, "test4"), checker.Equals, true)
createNetwork(c, types.NetworkCreate{Name: "test5"}, true) createNetwork(c, types.NetworkCreateRequest{Name: "test5"}, true)
c.Assert(isNetworkAvailable(c, "test5"), checker.Equals, true) c.Assert(isNetworkAvailable(c, "test5"), checker.Equals, true)
for i := 1; i < 6; i++ { for i := 1; i < 6; i++ {
@ -230,9 +244,11 @@ func (s *DockerSuite) TestApiCreateDeletePredefinedNetworks(c *check.C) {
func createDeletePredefinedNetwork(c *check.C, name string) { func createDeletePredefinedNetwork(c *check.C, name string) {
// Create pre-defined network // Create pre-defined network
config := types.NetworkCreate{ config := types.NetworkCreateRequest{
Name: name, Name: name,
CheckDuplicate: true, NetworkCreate: types.NetworkCreate{
CheckDuplicate: true,
},
} }
shouldSucceed := false shouldSucceed := false
createNetwork(c, config, shouldSucceed) createNetwork(c, config, shouldSucceed)
@ -289,7 +305,7 @@ func getNetworkResource(c *check.C, id string) *types.NetworkResource {
return &nr return &nr
} }
func createNetwork(c *check.C, config types.NetworkCreate, shouldSucceed bool) string { func createNetwork(c *check.C, config types.NetworkCreateRequest, shouldSucceed bool) string {
status, resp, err := sockRequest("POST", "/networks/create", config) status, resp, err := sockRequest("POST", "/networks/create", config)
if !shouldSucceed { if !shouldSucceed {
c.Assert(status, checker.Not(checker.Equals), http.StatusCreated) c.Assert(status, checker.Not(checker.Equals), http.StatusCreated)

View file

@ -114,6 +114,12 @@ func (cli *Client) ClientVersion() string {
return cli.version return cli.version
} }
// UpdateClientVersion updates the version string associated with this
// instance of the Client.
func (cli *Client) UpdateClientVersion(v string) {
cli.version = v
}
// ParseHost verifies that the given host strings is valid. // ParseHost verifies that the given host strings is valid.
func ParseHost(host string) (string, string, string, error) { func ParseHost(host string) (string, string, string, error) {
protoAddrParts := strings.SplitN(host, "://", 2) protoAddrParts := strings.SplitN(host, "://", 2)

View file

@ -11,7 +11,7 @@ import (
// It returns a types.HijackedConnection with the hijacked connection // It returns a types.HijackedConnection with the hijacked connection
// and the a reader to get output. It's up to the called to close // and the a reader to get output. It's up to the called to close
// the hijacked connection by calling types.HijackedResponse.Close. // the hijacked connection by calling types.HijackedResponse.Close.
func (cli *Client) ContainerAttach(ctx context.Context, options types.ContainerAttachOptions) (types.HijackedResponse, error) { func (cli *Client) ContainerAttach(ctx context.Context, container string, options types.ContainerAttachOptions) (types.HijackedResponse, error) {
query := url.Values{} query := url.Values{}
if options.Stream { if options.Stream {
query.Set("stream", "1") query.Set("stream", "1")
@ -30,5 +30,5 @@ func (cli *Client) ContainerAttach(ctx context.Context, options types.ContainerA
} }
headers := map[string][]string{"Content-Type": {"text/plain"}} headers := map[string][]string{"Content-Type": {"text/plain"}}
return cli.postHijacked(ctx, "/containers/"+options.ContainerID+"/attach", query, nil, headers) return cli.postHijacked(ctx, "/containers/"+container+"/attach", query, nil, headers)
} }

View file

@ -2,18 +2,36 @@ package client
import ( import (
"encoding/json" "encoding/json"
"errors"
"net/url" "net/url"
distreference "github.com/docker/distribution/reference"
"github.com/docker/engine-api/types" "github.com/docker/engine-api/types"
"github.com/docker/engine-api/types/reference"
"golang.org/x/net/context" "golang.org/x/net/context"
) )
// ContainerCommit applies changes into a container and creates a new tagged image. // ContainerCommit applies changes into a container and creates a new tagged image.
func (cli *Client) ContainerCommit(ctx context.Context, options types.ContainerCommitOptions) (types.ContainerCommitResponse, error) { func (cli *Client) ContainerCommit(ctx context.Context, container string, options types.ContainerCommitOptions) (types.ContainerCommitResponse, error) {
var repository, tag string
if options.Reference != "" {
distributionRef, err := distreference.ParseNamed(options.Reference)
if err != nil {
return types.ContainerCommitResponse{}, err
}
if _, isCanonical := distributionRef.(distreference.Canonical); isCanonical {
return types.ContainerCommitResponse{}, errors.New("refusing to create a tag with a digest reference")
}
tag = reference.GetTagFromNamedRef(distributionRef)
repository = distributionRef.Name()
}
query := url.Values{} query := url.Values{}
query.Set("container", options.ContainerID) query.Set("container", container)
query.Set("repo", options.RepositoryName) query.Set("repo", repository)
query.Set("tag", options.Tag) query.Set("tag", tag)
query.Set("comment", options.Comment) query.Set("comment", options.Comment)
query.Set("author", options.Author) query.Set("author", options.Author)
for _, change := range options.Changes { for _, change := range options.Changes {

View file

@ -8,9 +8,9 @@ import (
) )
// ContainerExecCreate creates a new exec configuration to run an exec process. // ContainerExecCreate creates a new exec configuration to run an exec process.
func (cli *Client) ContainerExecCreate(ctx context.Context, config types.ExecConfig) (types.ContainerExecCreateResponse, error) { func (cli *Client) ContainerExecCreate(ctx context.Context, container string, config types.ExecConfig) (types.ContainerExecCreateResponse, error) {
var response types.ContainerExecCreateResponse var response types.ContainerExecCreateResponse
resp, err := cli.post(ctx, "/containers/"+config.Container+"/exec", nil, config, nil) resp, err := cli.post(ctx, "/containers/"+container+"/exec", nil, config, nil)
if err != nil { if err != nil {
return response, err return response, err
} }

View file

@ -35,7 +35,8 @@ func (cli *Client) ContainerList(ctx context.Context, options types.ContainerLis
} }
if options.Filter.Len() > 0 { if options.Filter.Len() > 0 {
filterJSON, err := filters.ToParam(options.Filter) filterJSON, err := filters.ToParamWithVersion(cli.version, options.Filter)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -13,7 +13,7 @@ import (
// ContainerLogs returns the logs generated by a container in an io.ReadCloser. // ContainerLogs returns the logs generated by a container in an io.ReadCloser.
// It's up to the caller to close the stream. // It's up to the caller to close the stream.
func (cli *Client) ContainerLogs(ctx context.Context, options types.ContainerLogsOptions) (io.ReadCloser, error) { func (cli *Client) ContainerLogs(ctx context.Context, container string, options types.ContainerLogsOptions) (io.ReadCloser, error) {
query := url.Values{} query := url.Values{}
if options.ShowStdout { if options.ShowStdout {
query.Set("stdout", "1") query.Set("stdout", "1")
@ -40,7 +40,7 @@ func (cli *Client) ContainerLogs(ctx context.Context, options types.ContainerLog
} }
query.Set("tail", options.Tail) query.Set("tail", options.Tail)
resp, err := cli.get(ctx, "/containers/"+options.ContainerID+"/logs", query, nil) resp, err := cli.get(ctx, "/containers/"+container+"/logs", query, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -8,7 +8,7 @@ import (
) )
// ContainerRemove kills and removes a container from the docker host. // ContainerRemove kills and removes a container from the docker host.
func (cli *Client) ContainerRemove(ctx context.Context, options types.ContainerRemoveOptions) error { func (cli *Client) ContainerRemove(ctx context.Context, containerID string, options types.ContainerRemoveOptions) error {
query := url.Values{} query := url.Values{}
if options.RemoveVolumes { if options.RemoveVolumes {
query.Set("v", "1") query.Set("v", "1")
@ -21,7 +21,7 @@ func (cli *Client) ContainerRemove(ctx context.Context, options types.ContainerR
query.Set("force", "1") query.Set("force", "1")
} }
resp, err := cli.delete(ctx, "/containers/"+options.ContainerID, query, nil) resp, err := cli.delete(ctx, "/containers/"+containerID, query, nil)
ensureReaderClosed(resp) ensureReaderClosed(resp)
return err return err
} }

View file

@ -9,13 +9,13 @@ import (
) )
// ContainerResize changes the size of the tty for a container. // ContainerResize changes the size of the tty for a container.
func (cli *Client) ContainerResize(ctx context.Context, options types.ResizeOptions) error { func (cli *Client) ContainerResize(ctx context.Context, containerID string, options types.ResizeOptions) error {
return cli.resize(ctx, "/containers/"+options.ID, options.Height, options.Width) return cli.resize(ctx, "/containers/"+containerID, options.Height, options.Width)
} }
// ContainerExecResize changes the size of the tty for an exec process running inside a container. // ContainerExecResize changes the size of the tty for an exec process running inside a container.
func (cli *Client) ContainerExecResize(ctx context.Context, options types.ResizeOptions) error { func (cli *Client) ContainerExecResize(ctx context.Context, execID string, options types.ResizeOptions) error {
return cli.resize(ctx, "/exec/"+options.ID, options.Height, options.Width) return cli.resize(ctx, "/exec/"+execID, options.Height, options.Width)
} }
func (cli *Client) resize(ctx context.Context, basePath string, height, width int) error { func (cli *Client) resize(ctx context.Context, basePath string, height, width int) error {

View file

@ -3,6 +3,7 @@ package client
import ( import (
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"io"
"net/http" "net/http"
"net/url" "net/url"
"regexp" "regexp"
@ -20,7 +21,7 @@ var headerRegexp = regexp.MustCompile(`\ADocker/.+\s\((.+)\)\z`)
// ImageBuild sends request to the daemon to build images. // ImageBuild sends request to the daemon to build images.
// The Body in the response implement an io.ReadCloser and it's up to the caller to // The Body in the response implement an io.ReadCloser and it's up to the caller to
// close it. // close it.
func (cli *Client) ImageBuild(ctx context.Context, options types.ImageBuildOptions) (types.ImageBuildResponse, error) { func (cli *Client) ImageBuild(ctx context.Context, buildContext io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
query, err := imageBuildOptionsToQuery(options) query, err := imageBuildOptionsToQuery(options)
if err != nil { if err != nil {
return types.ImageBuildResponse{}, err return types.ImageBuildResponse{}, err
@ -34,7 +35,7 @@ func (cli *Client) ImageBuild(ctx context.Context, options types.ImageBuildOptio
headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf)) headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf))
headers.Set("Content-Type", "application/tar") headers.Set("Content-Type", "application/tar")
serverResp, err := cli.postRaw(ctx, "/build", query, options.Context, headers) serverResp, err := cli.postRaw(ctx, "/build", query, buildContext, headers)
if err != nil { if err != nil {
return types.ImageBuildResponse{}, err return types.ImageBuildResponse{}, err
} }

View file

@ -7,14 +7,20 @@ import (
"golang.org/x/net/context" "golang.org/x/net/context"
"github.com/docker/engine-api/types" "github.com/docker/engine-api/types"
"github.com/docker/engine-api/types/reference"
) )
// ImageCreate creates a new image based in the parent options. // ImageCreate creates a new image based in the parent options.
// It returns the JSON content in the response body. // It returns the JSON content in the response body.
func (cli *Client) ImageCreate(ctx context.Context, options types.ImageCreateOptions) (io.ReadCloser, error) { func (cli *Client) ImageCreate(ctx context.Context, parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error) {
repository, tag, err := reference.Parse(parentReference)
if err != nil {
return nil, err
}
query := url.Values{} query := url.Values{}
query.Set("fromImage", options.Parent) query.Set("fromImage", repository)
query.Set("tag", options.Tag) query.Set("tag", tag)
resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth) resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -6,22 +6,30 @@ import (
"golang.org/x/net/context" "golang.org/x/net/context"
"github.com/docker/distribution/reference"
"github.com/docker/engine-api/types" "github.com/docker/engine-api/types"
) )
// ImageImport creates a new image based in the source options. // ImageImport creates a new image based in the source options.
// It returns the JSON content in the response body. // It returns the JSON content in the response body.
func (cli *Client) ImageImport(ctx context.Context, options types.ImageImportOptions) (io.ReadCloser, error) { func (cli *Client) ImageImport(ctx context.Context, source types.ImageImportSource, ref string, options types.ImageImportOptions) (io.ReadCloser, error) {
if ref != "" {
//Check if the given image name can be resolved
if _, err := reference.ParseNamed(ref); err != nil {
return nil, err
}
}
query := url.Values{} query := url.Values{}
query.Set("fromSrc", options.SourceName) query.Set("fromSrc", source.SourceName)
query.Set("repo", options.RepositoryName) query.Set("repo", ref)
query.Set("tag", options.Tag) query.Set("tag", options.Tag)
query.Set("message", options.Message) query.Set("message", options.Message)
for _, change := range options.Changes { for _, change := range options.Changes {
query.Add("changes", change) query.Add("changes", change)
} }
resp, err := cli.postRaw(ctx, "/images/create", query, options.Source, nil) resp, err := cli.postRaw(ctx, "/images/create", query, source.Source, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -8,22 +8,32 @@ import (
"golang.org/x/net/context" "golang.org/x/net/context"
"github.com/docker/engine-api/types" "github.com/docker/engine-api/types"
"github.com/docker/engine-api/types/reference"
) )
// ImagePull requests the docker host to pull an image from a remote registry. // ImagePull requests the docker host to pull an image from a remote registry.
// It executes the privileged function if the operation is unauthorized // It executes the privileged function if the operation is unauthorized
// and it tries one more time. // and it tries one more time.
// It's up to the caller to handle the io.ReadCloser and close it properly. // It's up to the caller to handle the io.ReadCloser and close it properly.
func (cli *Client) ImagePull(ctx context.Context, options types.ImagePullOptions, privilegeFunc RequestPrivilegeFunc) (io.ReadCloser, error) { //
// FIXME(vdemeester): there is currently used in a few way in docker/docker
// - if not in trusted content, ref is used to pass the whole reference, and tag is empty
// - if in trusted content, ref is used to pass the reference name, and tag for the digest
func (cli *Client) ImagePull(ctx context.Context, ref string, options types.ImagePullOptions) (io.ReadCloser, error) {
repository, tag, err := reference.Parse(ref)
if err != nil {
return nil, err
}
query := url.Values{} query := url.Values{}
query.Set("fromImage", options.ImageID) query.Set("fromImage", repository)
if options.Tag != "" { if tag != "" {
query.Set("tag", options.Tag) query.Set("tag", tag)
} }
resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth) resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth)
if resp.statusCode == http.StatusUnauthorized { if resp.statusCode == http.StatusUnauthorized {
newAuthHeader, privilegeErr := privilegeFunc() newAuthHeader, privilegeErr := options.PrivilegeFunc()
if privilegeErr != nil { if privilegeErr != nil {
return nil, privilegeErr return nil, privilegeErr
} }

View file

@ -1,30 +1,44 @@
package client package client
import ( import (
"errors"
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
"golang.org/x/net/context" "golang.org/x/net/context"
distreference "github.com/docker/distribution/reference"
"github.com/docker/engine-api/types" "github.com/docker/engine-api/types"
"github.com/docker/engine-api/types/reference"
) )
// ImagePush requests the docker host to push an image to a remote registry. // ImagePush requests the docker host to push an image to a remote registry.
// It executes the privileged function if the operation is unauthorized // It executes the privileged function if the operation is unauthorized
// and it tries one more time. // and it tries one more time.
// It's up to the caller to handle the io.ReadCloser and close it properly. // It's up to the caller to handle the io.ReadCloser and close it properly.
func (cli *Client) ImagePush(ctx context.Context, options types.ImagePushOptions, privilegeFunc RequestPrivilegeFunc) (io.ReadCloser, error) { func (cli *Client) ImagePush(ctx context.Context, ref string, options types.ImagePushOptions) (io.ReadCloser, error) {
query := url.Values{} distributionRef, err := distreference.ParseNamed(ref)
query.Set("tag", options.Tag) if err != nil {
return nil, err
}
resp, err := cli.tryImagePush(ctx, options.ImageID, query, options.RegistryAuth) if _, isCanonical := distributionRef.(distreference.Canonical); isCanonical {
return nil, errors.New("cannot push a digest reference")
}
tag := reference.GetTagFromNamedRef(distributionRef)
query := url.Values{}
query.Set("tag", tag)
resp, err := cli.tryImagePush(ctx, distributionRef.Name(), query, options.RegistryAuth)
if resp.statusCode == http.StatusUnauthorized { if resp.statusCode == http.StatusUnauthorized {
newAuthHeader, privilegeErr := privilegeFunc() newAuthHeader, privilegeErr := options.PrivilegeFunc()
if privilegeErr != nil { if privilegeErr != nil {
return nil, privilegeErr return nil, privilegeErr
} }
resp, err = cli.tryImagePush(ctx, options.ImageID, query, newAuthHeader) resp, err = cli.tryImagePush(ctx, distributionRef.Name(), query, newAuthHeader)
} }
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -9,7 +9,7 @@ import (
) )
// ImageRemove removes an image from the docker host. // ImageRemove removes an image from the docker host.
func (cli *Client) ImageRemove(ctx context.Context, options types.ImageRemoveOptions) ([]types.ImageDelete, error) { func (cli *Client) ImageRemove(ctx context.Context, imageID string, options types.ImageRemoveOptions) ([]types.ImageDelete, error) {
query := url.Values{} query := url.Values{}
if options.Force { if options.Force {
@ -19,7 +19,7 @@ func (cli *Client) ImageRemove(ctx context.Context, options types.ImageRemoveOpt
query.Set("noprune", "1") query.Set("noprune", "1")
} }
resp, err := cli.delete(ctx, "/images/"+options.ImageID, query, nil) resp, err := cli.delete(ctx, "/images/"+imageID, query, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -12,14 +12,14 @@ import (
// ImageSearch makes the docker host to search by a term in a remote registry. // ImageSearch makes the docker host to search by a term in a remote registry.
// The list of results is not sorted in any fashion. // The list of results is not sorted in any fashion.
func (cli *Client) ImageSearch(ctx context.Context, options types.ImageSearchOptions, privilegeFunc RequestPrivilegeFunc) ([]registry.SearchResult, error) { func (cli *Client) ImageSearch(ctx context.Context, term string, options types.ImageSearchOptions) ([]registry.SearchResult, error) {
var results []registry.SearchResult var results []registry.SearchResult
query := url.Values{} query := url.Values{}
query.Set("term", options.Term) query.Set("term", term)
resp, err := cli.tryImageSearch(ctx, query, options.RegistryAuth) resp, err := cli.tryImageSearch(ctx, query, options.RegistryAuth)
if resp.statusCode == http.StatusUnauthorized { if resp.statusCode == http.StatusUnauthorized {
newAuthHeader, privilegeErr := privilegeFunc() newAuthHeader, privilegeErr := options.PrivilegeFunc()
if privilegeErr != nil { if privilegeErr != nil {
return results, privilegeErr return results, privilegeErr
} }

View file

@ -1,22 +1,38 @@
package client package client
import ( import (
"errors"
"fmt"
"net/url" "net/url"
"github.com/docker/engine-api/types"
"golang.org/x/net/context" "golang.org/x/net/context"
distreference "github.com/docker/distribution/reference"
"github.com/docker/engine-api/types"
"github.com/docker/engine-api/types/reference"
) )
// ImageTag tags an image in the docker host // ImageTag tags an image in the docker host
func (cli *Client) ImageTag(ctx context.Context, options types.ImageTagOptions) error { func (cli *Client) ImageTag(ctx context.Context, imageID, ref string, options types.ImageTagOptions) error {
distributionRef, err := distreference.ParseNamed(ref)
if err != nil {
return fmt.Errorf("Error parsing reference: %q is not a valid repository/tag", ref)
}
if _, isCanonical := distributionRef.(distreference.Canonical); isCanonical {
return errors.New("refusing to create a tag with a digest reference")
}
tag := reference.GetTagFromNamedRef(distributionRef)
query := url.Values{} query := url.Values{}
query.Set("repo", options.RepositoryName) query.Set("repo", distributionRef.Name())
query.Set("tag", options.Tag) query.Set("tag", tag)
if options.Force { if options.Force {
query.Set("force", "1") query.Set("force", "1")
} }
resp, err := cli.post(ctx, "/images/"+options.ImageID+"/tag", query, nil, nil) resp, err := cli.post(ctx, "/images/"+imageID+"/tag", query, nil, nil)
ensureReaderClosed(resp) ensureReaderClosed(resp)
return err return err
} }

View file

@ -15,59 +15,60 @@ import (
// APIClient is an interface that clients that talk with a docker server must implement. // APIClient is an interface that clients that talk with a docker server must implement.
type APIClient interface { type APIClient interface {
ClientVersion() string ClientVersion() string
ContainerAttach(ctx context.Context, options types.ContainerAttachOptions) (types.HijackedResponse, error) ContainerAttach(ctx context.Context, container string, options types.ContainerAttachOptions) (types.HijackedResponse, error)
ContainerCommit(ctx context.Context, options types.ContainerCommitOptions) (types.ContainerCommitResponse, error) ContainerCommit(ctx context.Context, container string, options types.ContainerCommitOptions) (types.ContainerCommitResponse, error)
ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, containerName string) (types.ContainerCreateResponse, error) ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, containerName string) (types.ContainerCreateResponse, error)
ContainerDiff(ctx context.Context, ontainerID string) ([]types.ContainerChange, error) ContainerDiff(ctx context.Context, container string) ([]types.ContainerChange, error)
ContainerExecAttach(ctx context.Context, execID string, config types.ExecConfig) (types.HijackedResponse, error) ContainerExecAttach(ctx context.Context, execID string, config types.ExecConfig) (types.HijackedResponse, error)
ContainerExecCreate(ctx context.Context, config types.ExecConfig) (types.ContainerExecCreateResponse, error) ContainerExecCreate(ctx context.Context, container string, config types.ExecConfig) (types.ContainerExecCreateResponse, error)
ContainerExecInspect(ctx context.Context, execID string) (types.ContainerExecInspect, error) ContainerExecInspect(ctx context.Context, execID string) (types.ContainerExecInspect, error)
ContainerExecResize(ctx context.Context, options types.ResizeOptions) error ContainerExecResize(ctx context.Context, execID string, options types.ResizeOptions) error
ContainerExecStart(ctx context.Context, execID string, config types.ExecStartCheck) error ContainerExecStart(ctx context.Context, execID string, config types.ExecStartCheck) error
ContainerExport(ctx context.Context, containerID string) (io.ReadCloser, error) ContainerExport(ctx context.Context, container string) (io.ReadCloser, error)
ContainerInspect(ctx context.Context, containerID string) (types.ContainerJSON, error) ContainerInspect(ctx context.Context, container string) (types.ContainerJSON, error)
ContainerInspectWithRaw(ctx context.Context, containerID string, getSize bool) (types.ContainerJSON, []byte, error) ContainerInspectWithRaw(ctx context.Context, container string, getSize bool) (types.ContainerJSON, []byte, error)
ContainerKill(ctx context.Context, containerID, signal string) error ContainerKill(ctx context.Context, container, signal string) error
ContainerList(ctx context.Context, options types.ContainerListOptions) ([]types.Container, error) ContainerList(ctx context.Context, options types.ContainerListOptions) ([]types.Container, error)
ContainerLogs(ctx context.Context, options types.ContainerLogsOptions) (io.ReadCloser, error) ContainerLogs(ctx context.Context, container string, options types.ContainerLogsOptions) (io.ReadCloser, error)
ContainerPause(ctx context.Context, containerID string) error ContainerPause(ctx context.Context, container string) error
ContainerRemove(ctx context.Context, options types.ContainerRemoveOptions) error ContainerRemove(ctx context.Context, container string, options types.ContainerRemoveOptions) error
ContainerRename(ctx context.Context, containerID, newContainerName string) error ContainerRename(ctx context.Context, container, newContainerName string) error
ContainerResize(ctx context.Context, options types.ResizeOptions) error ContainerResize(ctx context.Context, container string, options types.ResizeOptions) error
ContainerRestart(ctx context.Context, containerID string, timeout int) error ContainerRestart(ctx context.Context, container string, timeout int) error
ContainerStatPath(ctx context.Context, containerID, path string) (types.ContainerPathStat, error) ContainerStatPath(ctx context.Context, container, path string) (types.ContainerPathStat, error)
ContainerStats(ctx context.Context, containerID string, stream bool) (io.ReadCloser, error) ContainerStats(ctx context.Context, container string, stream bool) (io.ReadCloser, error)
ContainerStart(ctx context.Context, containerID string) error ContainerStart(ctx context.Context, container string) error
ContainerStop(ctx context.Context, containerID string, timeout int) error ContainerStop(ctx context.Context, container string, timeout int) error
ContainerTop(ctx context.Context, containerID string, arguments []string) (types.ContainerProcessList, error) ContainerTop(ctx context.Context, container string, arguments []string) (types.ContainerProcessList, error)
ContainerUnpause(ctx context.Context, containerID string) error ContainerUnpause(ctx context.Context, container string) error
ContainerUpdate(ctx context.Context, containerID string, updateConfig container.UpdateConfig) error ContainerUpdate(ctx context.Context, container string, updateConfig container.UpdateConfig) error
ContainerWait(ctx context.Context, containerID string) (int, error) ContainerWait(ctx context.Context, container string) (int, error)
CopyFromContainer(ctx context.Context, containerID, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) CopyFromContainer(ctx context.Context, container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error)
CopyToContainer(ctx context.Context, options types.CopyToContainerOptions) error CopyToContainer(ctx context.Context, options types.CopyToContainerOptions) error
Events(ctx context.Context, options types.EventsOptions) (io.ReadCloser, error) Events(ctx context.Context, options types.EventsOptions) (io.ReadCloser, error)
ImageBuild(ctx context.Context, options types.ImageBuildOptions) (types.ImageBuildResponse, error) ImageBuild(ctx context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error)
ImageCreate(ctx context.Context, options types.ImageCreateOptions) (io.ReadCloser, error) ImageCreate(ctx context.Context, parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error)
ImageHistory(ctx context.Context, imageID string) ([]types.ImageHistory, error) ImageHistory(ctx context.Context, image string) ([]types.ImageHistory, error)
ImageImport(ctx context.Context, options types.ImageImportOptions) (io.ReadCloser, error) ImageImport(ctx context.Context, source types.ImageImportSource, ref string, options types.ImageImportOptions) (io.ReadCloser, error)
ImageInspectWithRaw(ctx context.Context, imageID string, getSize bool) (types.ImageInspect, []byte, error) ImageInspectWithRaw(ctx context.Context, image string, getSize bool) (types.ImageInspect, []byte, error)
ImageList(ctx context.Context, options types.ImageListOptions) ([]types.Image, error) ImageList(ctx context.Context, options types.ImageListOptions) ([]types.Image, error)
ImageLoad(ctx context.Context, input io.Reader, quiet bool) (types.ImageLoadResponse, error) ImageLoad(ctx context.Context, input io.Reader, quiet bool) (types.ImageLoadResponse, error)
ImagePull(ctx context.Context, options types.ImagePullOptions, privilegeFunc RequestPrivilegeFunc) (io.ReadCloser, error) ImagePull(ctx context.Context, ref string, options types.ImagePullOptions) (io.ReadCloser, error)
ImagePush(ctx context.Context, options types.ImagePushOptions, privilegeFunc RequestPrivilegeFunc) (io.ReadCloser, error) ImagePush(ctx context.Context, ref string, options types.ImagePushOptions) (io.ReadCloser, error)
ImageRemove(ctx context.Context, options types.ImageRemoveOptions) ([]types.ImageDelete, error) ImageRemove(ctx context.Context, image string, options types.ImageRemoveOptions) ([]types.ImageDelete, error)
ImageSearch(ctx context.Context, options types.ImageSearchOptions, privilegeFunc RequestPrivilegeFunc) ([]registry.SearchResult, error) ImageSearch(ctx context.Context, term string, options types.ImageSearchOptions) ([]registry.SearchResult, error)
ImageSave(ctx context.Context, imageIDs []string) (io.ReadCloser, error) ImageSave(ctx context.Context, images []string) (io.ReadCloser, error)
ImageTag(ctx context.Context, options types.ImageTagOptions) error ImageTag(ctx context.Context, image, ref string, options types.ImageTagOptions) error
Info(ctx context.Context) (types.Info, error) Info(ctx context.Context) (types.Info, error)
NetworkConnect(ctx context.Context, networkID, containerID string, config *network.EndpointSettings) error NetworkConnect(ctx context.Context, networkID, container string, config *network.EndpointSettings) error
NetworkCreate(ctx context.Context, options types.NetworkCreate) (types.NetworkCreateResponse, error) NetworkCreate(ctx context.Context, name string, options types.NetworkCreate) (types.NetworkCreateResponse, error)
NetworkDisconnect(ctx context.Context, networkID, containerID string, force bool) error NetworkDisconnect(ctx context.Context, networkID, container string, force bool) error
NetworkInspect(ctx context.Context, networkID string) (types.NetworkResource, error) NetworkInspect(ctx context.Context, networkID string) (types.NetworkResource, error)
NetworkList(ctx context.Context, options types.NetworkListOptions) ([]types.NetworkResource, error) NetworkList(ctx context.Context, options types.NetworkListOptions) ([]types.NetworkResource, error)
NetworkRemove(ctx context.Context, networkID string) error NetworkRemove(ctx context.Context, networkID string) error
RegistryLogin(ctx context.Context, auth types.AuthConfig) (types.AuthResponse, error) RegistryLogin(ctx context.Context, auth types.AuthConfig) (types.AuthResponse, error)
ServerVersion(ctx context.Context) (types.Version, error) ServerVersion(ctx context.Context) (types.Version, error)
UpdateClientVersion(v string)
VolumeCreate(ctx context.Context, options types.VolumeCreateRequest) (types.Volume, error) VolumeCreate(ctx context.Context, options types.VolumeCreateRequest) (types.Volume, error)
VolumeInspect(ctx context.Context, volumeID string) (types.Volume, error) VolumeInspect(ctx context.Context, volumeID string) (types.Volume, error)
VolumeList(ctx context.Context, filter filters.Args) (types.VolumesListResponse, error) VolumeList(ctx context.Context, filter filters.Args) (types.VolumesListResponse, error)

View file

@ -8,9 +8,13 @@ import (
) )
// NetworkCreate creates a new network in the docker host. // NetworkCreate creates a new network in the docker host.
func (cli *Client) NetworkCreate(ctx context.Context, options types.NetworkCreate) (types.NetworkCreateResponse, error) { func (cli *Client) NetworkCreate(ctx context.Context, name string, options types.NetworkCreate) (types.NetworkCreateResponse, error) {
networkCreateRequest := types.NetworkCreateRequest{
NetworkCreate: options,
Name: name,
}
var response types.NetworkCreateResponse var response types.NetworkCreateResponse
serverResp, err := cli.post(ctx, "/networks/create", nil, options, nil) serverResp, err := cli.post(ctx, "/networks/create", nil, networkCreateRequest, nil)
if err != nil { if err != nil {
return response, err return response, err
} }

View file

@ -1,9 +1 @@
package client package client
// RequestPrivilegeFunc is a function interface that
// clients can supply to retry operations after
// getting an authorization error.
// This function returns the registry authentication
// header value in base 64 format, or an error
// if the privilege request fails.
type RequestPrivilegeFunc func() (string, error)

View file

@ -56,12 +56,14 @@ func (cli *Client) delete(ctx context.Context, path string, query url.Values, he
} }
func (cli *Client) sendRequest(ctx context.Context, method, path string, query url.Values, obj interface{}, headers map[string][]string) (*serverResponse, error) { func (cli *Client) sendRequest(ctx context.Context, method, path string, query url.Values, obj interface{}, headers map[string][]string) (*serverResponse, error) {
body, err := encodeData(obj) var body io.Reader
if err != nil {
return nil, err
}
if body != nil { if obj != nil {
var err error
body, err = encodeData(obj)
if err != nil {
return nil, err
}
if headers == nil { if headers == nil {
headers = make(map[string][]string) headers = make(map[string][]string)
} }

View file

@ -12,24 +12,21 @@ import (
// ContainerAttachOptions holds parameters to attach to a container. // ContainerAttachOptions holds parameters to attach to a container.
type ContainerAttachOptions struct { type ContainerAttachOptions struct {
ContainerID string Stream bool
Stream bool Stdin bool
Stdin bool Stdout bool
Stdout bool Stderr bool
Stderr bool DetachKeys string
DetachKeys string
} }
// ContainerCommitOptions holds parameters to commit changes into a container. // ContainerCommitOptions holds parameters to commit changes into a container.
type ContainerCommitOptions struct { type ContainerCommitOptions struct {
ContainerID string Reference string
RepositoryName string Comment string
Tag string Author string
Comment string Changes []string
Author string Pause bool
Changes []string Config *container.Config
Pause bool
Config *container.Config
} }
// ContainerExecInspect holds information returned by exec inspect. // ContainerExecInspect holds information returned by exec inspect.
@ -54,18 +51,16 @@ type ContainerListOptions struct {
// ContainerLogsOptions holds parameters to filter logs with. // ContainerLogsOptions holds parameters to filter logs with.
type ContainerLogsOptions struct { type ContainerLogsOptions struct {
ContainerID string ShowStdout bool
ShowStdout bool ShowStderr bool
ShowStderr bool Since string
Since string Timestamps bool
Timestamps bool Follow bool
Follow bool Tail string
Tail string
} }
// ContainerRemoveOptions holds parameters to remove containers. // ContainerRemoveOptions holds parameters to remove containers.
type ContainerRemoveOptions struct { type ContainerRemoveOptions struct {
ContainerID string
RemoveVolumes bool RemoveVolumes bool
RemoveLinks bool RemoveLinks bool
Force bool Force bool
@ -155,19 +150,20 @@ type ImageBuildResponse struct {
// ImageCreateOptions holds information to create images. // ImageCreateOptions holds information to create images.
type ImageCreateOptions struct { type ImageCreateOptions struct {
Parent string // Parent is the name of the image to pull
Tag string // Tag is the name to tag this image with
RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry
} }
// ImageImportSource holds source information for ImageImport
type ImageImportSource struct {
Source io.Reader // Source is the data to send to the server to create this image from (mutually exclusive with SourceName)
SourceName string // SourceName is the name of the image to pull (mutually exclusive with Source)
}
// ImageImportOptions holds information to import images from the client host. // ImageImportOptions holds information to import images from the client host.
type ImageImportOptions struct { type ImageImportOptions struct {
Source io.Reader // Source is the data to send to the server to create this image from (mutually exclusive with SourceName) Tag string // Tag is the name to tag this image with. This attribute is deprecated.
SourceName string // SourceName is the name of the image to pull (mutually exclusive with Source) Message string // Message is the message to tag the image with
RepositoryName string // RepositoryName is the name of the repository to import this image into Changes []string // Changes are the raw changes to apply to this image
Message string // Message is the message to tag the image with
Tag string // Tag is the name to tag this image with
Changes []string // Changes are the raw changes to apply to this image
} }
// ImageListOptions holds parameters to filter the list of images with. // ImageListOptions holds parameters to filter the list of images with.
@ -185,40 +181,42 @@ type ImageLoadResponse struct {
// ImagePullOptions holds information to pull images. // ImagePullOptions holds information to pull images.
type ImagePullOptions struct { type ImagePullOptions struct {
ImageID string // ImageID is the name of the image to pull RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry
Tag string // Tag is the name of the tag to be pulled PrivilegeFunc RequestPrivilegeFunc
RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry
} }
// RequestPrivilegeFunc is a function interface that
// clients can supply to retry operations after
// getting an authorization error.
// This function returns the registry authentication
// header value in base 64 format, or an error
// if the privilege request fails.
type RequestPrivilegeFunc func() (string, error)
//ImagePushOptions holds information to push images. //ImagePushOptions holds information to push images.
type ImagePushOptions ImagePullOptions type ImagePushOptions ImagePullOptions
// ImageRemoveOptions holds parameters to remove images. // ImageRemoveOptions holds parameters to remove images.
type ImageRemoveOptions struct { type ImageRemoveOptions struct {
ImageID string
Force bool Force bool
PruneChildren bool PruneChildren bool
} }
// ImageSearchOptions holds parameters to search images with. // ImageSearchOptions holds parameters to search images with.
type ImageSearchOptions struct { type ImageSearchOptions struct {
Term string RegistryAuth string
RegistryAuth string PrivilegeFunc RequestPrivilegeFunc
} }
// ImageTagOptions holds parameters to tag an image // ImageTagOptions holds parameters to tag an image
type ImageTagOptions struct { type ImageTagOptions struct {
ImageID string Force bool
RepositoryName string
Tag string
Force bool
} }
// ResizeOptions holds parameters to resize a tty. // ResizeOptions holds parameters to resize a tty.
// It can be used to resize container ttys and // It can be used to resize container ttys and
// exec process ttys too. // exec process ttys too.
type ResizeOptions struct { type ResizeOptions struct {
ID string
Height int Height int
Width int Width int
} }

View file

@ -44,7 +44,6 @@ type ExecConfig struct {
User string // User that will run the command User string // User that will run the command
Privileged bool // Is the container in privileged mode Privileged bool // Is the container in privileged mode
Tty bool // Attach standard streams to a tty. Tty bool // Attach standard streams to a tty.
Container string // Name of the container (to execute in)
AttachStdin bool // Attach the standard input, makes possible user interaction AttachStdin bool // Attach the standard input, makes possible user interaction
AttachStderr bool // Attach the standard output AttachStderr bool // Attach the standard output
AttachStdout bool // Attach the standard error AttachStdout bool // Attach the standard error

View file

@ -19,7 +19,6 @@ type Config struct {
AttachStdout bool // Attach the standard output AttachStdout bool // Attach the standard output
AttachStderr bool // Attach the standard error AttachStderr bool // Attach the standard error
ExposedPorts map[nat.Port]struct{} `json:",omitempty"` // List of exposed ports ExposedPorts map[nat.Port]struct{} `json:",omitempty"` // List of exposed ports
PublishService string `json:",omitempty"` // Name of the network service exposed by the container
Tty bool // Attach standard streams to a tty, including stdin if it is not closed. Tty bool // Attach standard streams to a tty, including stdin if it is not closed.
OpenStdin bool // Open stdin OpenStdin bool // Open stdin
StdinOnce bool // If true, close stdin after the 1 attached client disconnects. StdinOnce bool // If true, close stdin after the 1 attached client disconnects.

View file

@ -92,11 +92,13 @@ func (n UsernsMode) Valid() bool {
// CgroupSpec represents the cgroup to use for the container. // CgroupSpec represents the cgroup to use for the container.
type CgroupSpec string type CgroupSpec string
// IsContainer indicates whether the container is using another container cgroup
func (c CgroupSpec) IsContainer() bool { func (c CgroupSpec) IsContainer() bool {
parts := strings.SplitN(string(c), ":", 2) parts := strings.SplitN(string(c), ":", 2)
return len(parts) > 1 && parts[0] == "container" return len(parts) > 1 && parts[0] == "container"
} }
// Valid indicates whether the cgroup spec is valid.
func (c CgroupSpec) Valid() bool { func (c CgroupSpec) Valid() bool {
return c.IsContainer() || c == "" return c.IsContainer() || c == ""
} }

View file

@ -7,6 +7,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"regexp" "regexp"
"strconv"
"strings" "strings"
) )
@ -68,6 +69,28 @@ func ToParam(a Args) (string, error) {
return string(buf), nil return string(buf), nil
} }
// ToParamWithVersion packs the Args into a string for easy transport from client to server.
// The generated string will depend on the specified version (corresponding to the API version).
func ToParamWithVersion(version string, a Args) (string, error) {
// this way we don't URL encode {}, just empty space
if a.Len() == 0 {
return "", nil
}
// for daemons older than v1.10, filter must be of the form map[string][]string
buf := []byte{}
err := errors.New("")
if version != "" && compareTo(version, "1.22") == -1 {
buf, err = json.Marshal(convertArgsToSlice(a.fields))
} else {
buf, err = json.Marshal(a.fields)
}
if err != nil {
return "", err
}
return string(buf), nil
}
// FromParam unpacks the filter Args. // FromParam unpacks the filter Args.
func FromParam(p string) (Args, error) { func FromParam(p string) (Args, error) {
if len(p) == 0 { if len(p) == 0 {
@ -255,3 +278,48 @@ func deprecatedArgs(d map[string][]string) map[string]map[string]bool {
} }
return m return m
} }
func convertArgsToSlice(f map[string]map[string]bool) map[string][]string {
m := map[string][]string{}
for k, v := range f {
values := []string{}
for kk := range v {
if v[kk] {
values = append(values, kk)
}
}
m[k] = values
}
return m
}
// compareTo compares two version strings
// returns -1 if v1 < v2, 1 if v1 > v2, 0 otherwise
func compareTo(v1, v2 string) int {
var (
currTab = strings.Split(v1, ".")
otherTab = strings.Split(v2, ".")
)
max := len(currTab)
if len(otherTab) > max {
max = len(otherTab)
}
for i := 0; i < max; i++ {
var currInt, otherInt int
if len(currTab) > i {
currInt, _ = strconv.Atoi(currTab[i])
}
if len(otherTab) > i {
otherInt, _ = strconv.Atoi(otherTab[i])
}
if currInt > otherInt {
return 1
}
if otherInt > currInt {
return -1
}
}
return 0
}

View file

@ -0,0 +1,32 @@
package reference
import (
distreference "github.com/docker/distribution/reference"
)
// Parse parses the given references and return the repository and
// tag (if present) from it. If there is an error during parsing, it will
// return an error.
func Parse(ref string) (string, string, error) {
distributionRef, err := distreference.ParseNamed(ref)
if err != nil {
return "", "", err
}
tag := GetTagFromNamedRef(distributionRef)
return distributionRef.Name(), tag, nil
}
// GetTagFromNamedRef returns a tag from the specified reference.
// This function is necessary as long as the docker "server" api make the distinction between repository
// and tags.
func GetTagFromNamedRef(ref distreference.Named) string {
var tag string
switch x := ref.(type) {
case distreference.Digested:
tag = x.Digest().String()
case distreference.NamedTagged:
tag = x.Tag()
}
return tag
}

View file

@ -91,6 +91,9 @@ type NetworkStats struct {
type PidsStats struct { type PidsStats struct {
// Current is the number of pids in the cgroup // Current is the number of pids in the cgroup
Current uint64 `json:"current,omitempty"` Current uint64 `json:"current,omitempty"`
// Limit is the hard limit on the number of pids in the cgroup.
// A "Limit" of 0 means that there is no limit.
Limit uint64 `json:"limit,omitempty"`
} }
// Stats is Ultimate struct aggregating all types of stats of one container // Stats is Ultimate struct aggregating all types of stats of one container

View file

@ -290,7 +290,7 @@ type ContainerState struct {
FinishedAt string FinishedAt string
} }
// NodeData stores information about the node that a container // ContainerNode stores information about the node that a container
// is running on. It's only available in Docker Swarm // is running on. It's only available in Docker Swarm
type ContainerNode struct { type ContainerNode struct {
ID string ID string
@ -438,7 +438,6 @@ type EndpointResource struct {
// NetworkCreate is the expected body of the "create network" http request message // NetworkCreate is the expected body of the "create network" http request message
type NetworkCreate struct { type NetworkCreate struct {
Name string
CheckDuplicate bool CheckDuplicate bool
Driver string Driver string
EnableIPv6 bool EnableIPv6 bool
@ -448,6 +447,12 @@ type NetworkCreate struct {
Labels map[string]string Labels map[string]string
} }
// NetworkCreateRequest is the request message sent to the server for network create call.
type NetworkCreateRequest struct {
NetworkCreate
Name string
}
// NetworkCreateResponse is the response message sent by the server for network create call // NetworkCreateResponse is the response message sent by the server for network create call
type NetworkCreateResponse struct { type NetworkCreateResponse struct {
ID string `json:"Id"` ID string `json:"Id"`