mirror of https://github.com/docker/cli.git
always add but hide experimental cmds and flags
Signed-off-by: Victor Vieux <vieux@docker.com> update cobra and use Tags Signed-off-by: Victor Vieux <vieux@docker.com> allow client to talk to an older server Signed-off-by: Victor Vieux <vieux@docker.com>
This commit is contained in:
parent
3f7264473d
commit
4f63bfb619
17
client.go
17
client.go
|
@ -79,6 +79,8 @@ type Client struct {
|
||||||
version string
|
version string
|
||||||
// custom http headers configured by users.
|
// custom http headers configured by users.
|
||||||
customHTTPHeaders map[string]string
|
customHTTPHeaders map[string]string
|
||||||
|
// manualOverride is set to true when the version was set by users.
|
||||||
|
manualOverride bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEnvClient initializes a new API client based on environment variables.
|
// NewEnvClient initializes a new API client based on environment variables.
|
||||||
|
@ -111,13 +113,19 @@ func NewEnvClient() (*Client, error) {
|
||||||
if host == "" {
|
if host == "" {
|
||||||
host = DefaultDockerHost
|
host = DefaultDockerHost
|
||||||
}
|
}
|
||||||
|
|
||||||
version := os.Getenv("DOCKER_API_VERSION")
|
version := os.Getenv("DOCKER_API_VERSION")
|
||||||
if version == "" {
|
if version == "" {
|
||||||
version = DefaultVersion
|
version = DefaultVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewClient(host, version, client, nil)
|
cli, err := NewClient(host, version, client, nil)
|
||||||
|
if err != nil {
|
||||||
|
return cli, err
|
||||||
|
}
|
||||||
|
if version != "" {
|
||||||
|
cli.manualOverride = true
|
||||||
|
}
|
||||||
|
return cli, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient initializes a new API client for the given host and API version.
|
// NewClient initializes a new API client for the given host and API version.
|
||||||
|
@ -211,7 +219,10 @@ func (cli *Client) ClientVersion() string {
|
||||||
// UpdateClientVersion updates the version string associated with this
|
// UpdateClientVersion updates the version string associated with this
|
||||||
// instance of the Client.
|
// instance of the Client.
|
||||||
func (cli *Client) UpdateClientVersion(v string) {
|
func (cli *Client) UpdateClientVersion(v string) {
|
||||||
cli.version = v
|
if !cli.manualOverride {
|
||||||
|
cli.version = v
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseHost verifies that the given host strings is valid.
|
// ParseHost verifies that the given host strings is valid.
|
||||||
|
|
|
@ -20,6 +20,11 @@ type configWrapper struct {
|
||||||
// It can be associated with a name, but it's not mandatory.
|
// It can be associated with a name, but it's not mandatory.
|
||||||
func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, containerName string) (container.ContainerCreateCreatedBody, error) {
|
func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, containerName string) (container.ContainerCreateCreatedBody, error) {
|
||||||
var response container.ContainerCreateCreatedBody
|
var response container.ContainerCreateCreatedBody
|
||||||
|
|
||||||
|
if err := cli.NewVersionError("1.25", "stop timeout"); config != nil && config.StopTimeout != nil && err != nil {
|
||||||
|
return response, err
|
||||||
|
}
|
||||||
|
|
||||||
query := url.Values{}
|
query := url.Values{}
|
||||||
if containerName != "" {
|
if containerName != "" {
|
||||||
query.Set("name", containerName)
|
query.Set("name", containerName)
|
||||||
|
|
|
@ -10,6 +10,11 @@ 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, container string, config types.ExecConfig) (types.IDResponse, error) {
|
func (cli *Client) ContainerExecCreate(ctx context.Context, container string, config types.ExecConfig) (types.IDResponse, error) {
|
||||||
var response types.IDResponse
|
var response types.IDResponse
|
||||||
|
|
||||||
|
if err := cli.NewVersionError("1.25", "env"); len(config.Env) != 0 && err != nil {
|
||||||
|
return response, err
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := cli.post(ctx, "/containers/"+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
|
||||||
|
|
|
@ -12,6 +12,10 @@ import (
|
||||||
func (cli *Client) ContainersPrune(ctx context.Context, cfg types.ContainersPruneConfig) (types.ContainersPruneReport, error) {
|
func (cli *Client) ContainersPrune(ctx context.Context, cfg types.ContainersPruneConfig) (types.ContainersPruneReport, error) {
|
||||||
var report types.ContainersPruneReport
|
var report types.ContainersPruneReport
|
||||||
|
|
||||||
|
if err := cli.NewVersionError("1.25", "container prune"); err != nil {
|
||||||
|
return report, err
|
||||||
|
}
|
||||||
|
|
||||||
serverResp, err := cli.post(ctx, "/containers/prune", nil, cfg, nil)
|
serverResp, err := cli.post(ctx, "/containers/prune", nil, cfg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return report, err
|
return report, err
|
||||||
|
|
11
errors.go
11
errors.go
|
@ -3,6 +3,8 @@ package client
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/types/versions"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrConnectionFailed is an error raised when the connection between the client and the server failed.
|
// ErrConnectionFailed is an error raised when the connection between the client and the server failed.
|
||||||
|
@ -206,3 +208,12 @@ func IsErrPluginPermissionDenied(err error) bool {
|
||||||
_, ok := err.(pluginPermissionDenied)
|
_, ok := err.(pluginPermissionDenied)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewVersionError returns an error if the APIVersion required
|
||||||
|
// if less than the current supported version
|
||||||
|
func (cli *Client) NewVersionError(APIrequired, feature string) error {
|
||||||
|
if versions.LessThan(cli.version, APIrequired) {
|
||||||
|
return fmt.Errorf("%q requires API version %s, but the Docker server is version %s", feature, APIrequired, cli.version)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ var headerRegexp = regexp.MustCompile(`\ADocker/.+\s\((.+)\)\z`)
|
||||||
// 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, buildContext io.Reader, 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 := cli.imageBuildOptionsToQuery(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.ImageBuildResponse{}, err
|
return types.ImageBuildResponse{}, err
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ func (cli *Client) ImageBuild(ctx context.Context, buildContext io.Reader, optio
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func imageBuildOptionsToQuery(options types.ImageBuildOptions) (url.Values, error) {
|
func (cli *Client) imageBuildOptionsToQuery(options types.ImageBuildOptions) (url.Values, error) {
|
||||||
query := url.Values{
|
query := url.Values{
|
||||||
"t": options.Tags,
|
"t": options.Tags,
|
||||||
"securityopt": options.SecurityOpt,
|
"securityopt": options.SecurityOpt,
|
||||||
|
@ -76,6 +76,9 @@ func imageBuildOptionsToQuery(options types.ImageBuildOptions) (url.Values, erro
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.Squash {
|
if options.Squash {
|
||||||
|
if err := cli.NewVersionError("1.25", "squash"); err != nil {
|
||||||
|
return query, err
|
||||||
|
}
|
||||||
query.Set("squash", "1")
|
query.Set("squash", "1")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,10 @@ import (
|
||||||
func (cli *Client) ImagesPrune(ctx context.Context, cfg types.ImagesPruneConfig) (types.ImagesPruneReport, error) {
|
func (cli *Client) ImagesPrune(ctx context.Context, cfg types.ImagesPruneConfig) (types.ImagesPruneReport, error) {
|
||||||
var report types.ImagesPruneReport
|
var report types.ImagesPruneReport
|
||||||
|
|
||||||
|
if err := cli.NewVersionError("1.25", "image prune"); err != nil {
|
||||||
|
return report, err
|
||||||
|
}
|
||||||
|
|
||||||
serverResp, err := cli.post(ctx, "/images/prune", nil, cfg, nil)
|
serverResp, err := cli.post(ctx, "/images/prune", nil, cfg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return report, err
|
return report, err
|
||||||
|
|
|
@ -129,7 +129,7 @@ type SystemAPIClient interface {
|
||||||
Info(ctx context.Context) (types.Info, error)
|
Info(ctx context.Context) (types.Info, error)
|
||||||
RegistryLogin(ctx context.Context, auth types.AuthConfig) (registry.AuthenticateOKBody, error)
|
RegistryLogin(ctx context.Context, auth types.AuthConfig) (registry.AuthenticateOKBody, error)
|
||||||
DiskUsage(ctx context.Context) (types.DiskUsage, error)
|
DiskUsage(ctx context.Context) (types.DiskUsage, error)
|
||||||
Ping(ctx context.Context) (bool, error)
|
Ping(ctx context.Context) (types.Ping, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// VolumeAPIClient defines API client methods for the volumes
|
// VolumeAPIClient defines API client methods for the volumes
|
||||||
|
|
29
ping.go
29
ping.go
|
@ -1,19 +1,30 @@
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import "golang.org/x/net/context"
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
// Ping pings the server and return the value of the "Docker-Experimental" header
|
"github.com/docker/docker/api/types"
|
||||||
func (cli *Client) Ping(ctx context.Context) (bool, error) {
|
"golang.org/x/net/context"
|
||||||
serverResp, err := cli.get(ctx, "/_ping", nil, nil)
|
)
|
||||||
|
|
||||||
|
// Ping pings the server and return the value of the "Docker-Experimental" & "API-Version" headers
|
||||||
|
func (cli *Client) Ping(ctx context.Context) (types.Ping, error) {
|
||||||
|
var ping types.Ping
|
||||||
|
req, err := cli.buildRequest("GET", fmt.Sprintf("%s/_ping", cli.basePath), nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return ping, err
|
||||||
|
}
|
||||||
|
serverResp, err := cli.doRequest(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
return ping, err
|
||||||
}
|
}
|
||||||
defer ensureReaderClosed(serverResp)
|
defer ensureReaderClosed(serverResp)
|
||||||
|
|
||||||
exp := serverResp.header.Get("Docker-Experimental")
|
ping.APIVersion = serverResp.header.Get("API-Version")
|
||||||
if exp != "true" {
|
|
||||||
return false, nil
|
if serverResp.header.Get("Docker-Experimental") == "true" {
|
||||||
|
ping.Experimental = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, nil
|
return ping, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -214,6 +214,9 @@ func (cli *Client) addHeaders(req *http.Request, headers headers) *http.Request
|
||||||
// Add CLI Config's HTTP Headers BEFORE we set the Docker headers
|
// Add CLI Config's HTTP Headers BEFORE we set the Docker headers
|
||||||
// then the user can't change OUR headers
|
// then the user can't change OUR headers
|
||||||
for k, v := range cli.customHTTPHeaders {
|
for k, v := range cli.customHTTPHeaders {
|
||||||
|
if versions.LessThan(cli.version, "1.25") && k == "User-Agent" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
req.Header.Set(k, v)
|
req.Header.Set(k, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,10 @@ import (
|
||||||
func (cli *Client) VolumesPrune(ctx context.Context, cfg types.VolumesPruneConfig) (types.VolumesPruneReport, error) {
|
func (cli *Client) VolumesPrune(ctx context.Context, cfg types.VolumesPruneConfig) (types.VolumesPruneReport, error) {
|
||||||
var report types.VolumesPruneReport
|
var report types.VolumesPruneReport
|
||||||
|
|
||||||
|
if err := cli.NewVersionError("1.25", "volume prune"); err != nil {
|
||||||
|
return report, err
|
||||||
|
}
|
||||||
|
|
||||||
serverResp, err := cli.post(ctx, "/volumes/prune", nil, cfg, nil)
|
serverResp, err := cli.post(ctx, "/volumes/prune", nil, cfg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return report, err
|
return report, err
|
||||||
|
|
|
@ -3,14 +3,17 @@ package client
|
||||||
import (
|
import (
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/types/versions"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// VolumeRemove removes a volume from the docker host.
|
// VolumeRemove removes a volume from the docker host.
|
||||||
func (cli *Client) VolumeRemove(ctx context.Context, volumeID string, force bool) error {
|
func (cli *Client) VolumeRemove(ctx context.Context, volumeID string, force bool) error {
|
||||||
query := url.Values{}
|
query := url.Values{}
|
||||||
if force {
|
if versions.GreaterThanOrEqualTo(cli.version, "1.25") {
|
||||||
query.Set("force", "1")
|
if force {
|
||||||
|
query.Set("force", "1")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
resp, err := cli.delete(ctx, "/volumes/"+volumeID, query, nil)
|
resp, err := cli.delete(ctx, "/volumes/"+volumeID, query, nil)
|
||||||
ensureReaderClosed(resp)
|
ensureReaderClosed(resp)
|
||||||
|
|
Loading…
Reference in New Issue