Bump buildkit to master and fix versions incompatible with go mod 1.13

Bump github.com/gogo/googleapis to v1.3.2
Bump github.com/docker/cli to master

Signed-off-by: Silvin Lubecki <silvin.lubecki@docker.com>
This commit is contained in:
Silvin Lubecki
2020-03-03 16:46:38 +01:00
parent 54549235da
commit bbc902b4d6
1384 changed files with 186012 additions and 165455 deletions

View File

@@ -6,11 +6,13 @@ import (
"os"
"os/exec"
"path/filepath"
"sort"
"strings"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/config"
"github.com/spf13/cobra"
"vbom.ml/util/sortorder"
)
// ReexecEnvvar is the name of an ennvar which is set to the command
@@ -141,6 +143,10 @@ func ListPlugins(dockerCli command.Cli, rootcmd *cobra.Command) ([]Plugin, error
}
}
sort.Slice(plugins, func(i, j int) bool {
return sortorder.NaturalLess(plugins[i].Name, plugins[j].Name)
})
return plugins, nil
}

View File

@@ -22,9 +22,8 @@ import (
"github.com/docker/cli/cli/streams"
"github.com/docker/cli/cli/trust"
"github.com/docker/cli/cli/version"
"github.com/docker/cli/internal/containerizedengine"
dopts "github.com/docker/cli/opts"
clitypes "github.com/docker/cli/types"
"github.com/docker/docker/api"
"github.com/docker/docker/api/types"
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/docker/docker/client"
@@ -60,7 +59,6 @@ type Cli interface {
ManifestStore() manifeststore.Store
RegistryClient(bool) registryclient.RegistryClient
ContentTrustEnabled() bool
NewContainerizedEngineClient(sockPath string) (clitypes.ContainerizedClient, error)
ContextStore() store.Store
CurrentContext() string
StackOrchestrator(flagValue string) (Orchestrator, error)
@@ -70,24 +68,23 @@ type Cli interface {
// DockerCli is an instance the docker command line client.
// Instances of the client can be returned from NewDockerCli.
type DockerCli struct {
configFile *configfile.ConfigFile
in *streams.In
out *streams.Out
err io.Writer
client client.APIClient
serverInfo ServerInfo
clientInfo ClientInfo
contentTrust bool
newContainerizeClient func(string) (clitypes.ContainerizedClient, error)
contextStore store.Store
currentContext string
dockerEndpoint docker.Endpoint
contextStoreConfig store.Config
configFile *configfile.ConfigFile
in *streams.In
out *streams.Out
err io.Writer
client client.APIClient
serverInfo ServerInfo
clientInfo *ClientInfo
contentTrust bool
contextStore store.Store
currentContext string
dockerEndpoint docker.Endpoint
contextStoreConfig store.Config
}
// DefaultVersion returns api.defaultVersion or DOCKER_API_VERSION if specified.
func (cli *DockerCli) DefaultVersion() string {
return cli.clientInfo.DefaultVersion
return cli.ClientInfo().DefaultVersion
}
// Client returns the APIClient
@@ -126,9 +123,16 @@ func ShowHelp(err io.Writer) func(*cobra.Command, []string) error {
// ConfigFile returns the ConfigFile
func (cli *DockerCli) ConfigFile() *configfile.ConfigFile {
if cli.configFile == nil {
cli.loadConfigFile()
}
return cli.configFile
}
func (cli *DockerCli) loadConfigFile() {
cli.configFile = cliconfig.LoadDefaultConfigFile(cli.err)
}
// ServerInfo returns the server version details for the host this client is
// connected to
func (cli *DockerCli) ServerInfo() ServerInfo {
@@ -137,7 +141,34 @@ func (cli *DockerCli) ServerInfo() ServerInfo {
// ClientInfo returns the client details for the cli
func (cli *DockerCli) ClientInfo() ClientInfo {
return cli.clientInfo
if cli.clientInfo == nil {
_ = cli.loadClientInfo()
}
return *cli.clientInfo
}
func (cli *DockerCli) loadClientInfo() error {
var experimentalValue string
// Environment variable always overrides configuration
if experimentalValue = os.Getenv("DOCKER_CLI_EXPERIMENTAL"); experimentalValue == "" {
experimentalValue = cli.ConfigFile().Experimental
}
hasExperimental, err := isEnabled(experimentalValue)
if err != nil {
return errors.Wrap(err, "Experimental field")
}
var v string
if cli.client != nil {
v = cli.client.ClientVersion()
} else {
v = api.DefaultVersion
}
cli.clientInfo = &ClientInfo{
DefaultVersion: v,
HasExperimental: hasExperimental,
}
return nil
}
// ContentTrustEnabled returns whether content trust has been enabled by an
@@ -207,7 +238,7 @@ func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions, ops ...Initialize
debug.Enable()
}
cli.configFile = cliconfig.LoadDefaultConfigFile(cli.err)
cli.loadConfigFile()
baseContextStore := store.New(cliconfig.ContextStoreDir(), cli.contextStoreConfig)
cli.contextStore = &ContextStoreWithDefault{
@@ -239,18 +270,9 @@ func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions, ops ...Initialize
return err
}
}
var experimentalValue string
// Environment variable always overrides configuration
if experimentalValue = os.Getenv("DOCKER_CLI_EXPERIMENTAL"); experimentalValue == "" {
experimentalValue = cli.configFile.Experimental
}
hasExperimental, err := isEnabled(experimentalValue)
err = cli.loadClientInfo()
if err != nil {
return errors.Wrap(err, "Experimental field")
}
cli.clientInfo = ClientInfo{
DefaultVersion: cli.client.ClientVersion(),
HasExperimental: hasExperimental,
return err
}
cli.initializeFromClient()
return nil
@@ -381,11 +403,6 @@ func (cli *DockerCli) NotaryClient(imgRefAndAuth trust.ImageRefAndAuth, actions
return trust.GetNotaryRepository(cli.In(), cli.Out(), UserAgent(), imgRefAndAuth.RepoInfo(), imgRefAndAuth.AuthConfig(), actions...)
}
// NewContainerizedEngineClient returns a containerized engine client
func (cli *DockerCli) NewContainerizedEngineClient(sockPath string) (clitypes.ContainerizedClient, error) {
return cli.newContainerizeClient(sockPath)
}
// ContextStore returns the ContextStore
func (cli *DockerCli) ContextStore() store.Store {
return cli.contextStore
@@ -445,13 +462,12 @@ type ClientInfo struct {
}
// NewDockerCli returns a DockerCli instance with all operators applied on it.
// It applies by default the standard streams, the content trust from
// environment and the default containerized client constructor operations.
// It applies by default the standard streams, and the content trust from
// environment.
func NewDockerCli(ops ...DockerCliOption) (*DockerCli, error) {
cli := &DockerCli{}
defaultOps := []DockerCliOption{
WithContentTrustFromEnv(),
WithContainerizedClient(containerizedengine.NewClient),
}
cli.contextStoreConfig = DefaultContextStoreConfig()
ops = append(defaultOps, ops...)

View File

@@ -9,7 +9,6 @@ import (
"github.com/docker/cli/cli/context/docker"
"github.com/docker/cli/cli/context/store"
"github.com/docker/cli/cli/streams"
clitypes "github.com/docker/cli/types"
"github.com/docker/docker/pkg/term"
)
@@ -83,14 +82,6 @@ func WithContentTrust(enabled bool) DockerCliOption {
}
}
// WithContainerizedClient sets the containerized client constructor on a cli.
func WithContainerizedClient(containerizedFn func(string) (clitypes.ContainerizedClient, error)) DockerCliOption {
return func(cli *DockerCli) error {
cli.newContainerizeClient = containerizedFn
return nil
}
}
// WithContextEndpointType add support for an additional typed endpoint in the context store
// Plugins should use this to store additional endpoints configuration in the context store
func WithContextEndpointType(endpointName string, endpointType store.TypeGetter) DockerCliOption {

View File

@@ -78,7 +78,7 @@ func PromptForConfirmation(ins io.Reader, outs io.Writer, message string) bool {
}
message += " [y/N] "
fmt.Fprintf(outs, message)
_, _ = fmt.Fprint(outs, message)
// On Windows, force the use of the regular OS stdin stream.
if runtime.GOOS == "windows" {
@@ -130,7 +130,7 @@ func AddPlatformFlag(flags *pflag.FlagSet, target *string) {
// ValidateOutputPath validates the output paths of the `export` and `save` commands.
func ValidateOutputPath(path string) error {
dir := filepath.Dir(path)
dir := filepath.Dir(filepath.Clean(path))
if dir != "" && dir != "." {
if _, err := os.Stat(dir); os.IsNotExist(err) {
return errors.Errorf("invalid output path: directory %q does not exist", dir)
@@ -139,6 +139,10 @@ func ValidateOutputPath(path string) error {
// check whether `path` points to a regular file
// (if the path exists and doesn't point to a directory)
if fileInfo, err := os.Stat(path); !os.IsNotExist(err) {
if err != nil {
return err
}
if fileInfo.Mode().IsDir() || fileInfo.Mode().IsRegular() {
return nil
}

View File

@@ -54,7 +54,6 @@ func Interpolate(config map[string]interface{}, opts Options) (map[string]interf
func recursiveInterpolate(value interface{}, path Path, opts Options) (interface{}, error) {
switch value := value.(type) {
case string:
newValue, err := opts.Substitute(value, template.Mapping(opts.LookupValue))
if err != nil || newValue == value {
@@ -91,7 +90,6 @@ func recursiveInterpolate(value interface{}, path Path, opts Options) (interface
default:
return value, nil
}
}

View File

@@ -19,6 +19,7 @@ var interpolateTypeCastMapping = map[interp.Path]interp.Cast{
servicePath("deploy", "rollback_config", "parallelism"): toInt,
servicePath("deploy", "rollback_config", "max_failure_ratio"): toFloat,
servicePath("deploy", "restart_policy", "max_attempts"): toInt,
servicePath("deploy", "placement", "max_replicas_per_node"): toInt,
servicePath("ports", interp.PathMatchList, "target"): toInt,
servicePath("ports", interp.PathMatchList, "published"): toInt,
servicePath("ulimits", interp.PathMatchAll): toInt,

View File

@@ -297,10 +297,13 @@ func Transform(source interface{}, target interface{}, additionalTransformers ..
return decoder.Decode(source)
}
// TransformerFunc defines a function to perform the actual transformation
type TransformerFunc func(interface{}) (interface{}, error)
// Transformer defines a map to type transformer
type Transformer struct {
TypeOf reflect.Type
Func func(interface{}) (interface{}, error)
Func TransformerFunc
}
func createTransformHook(additionalTransformers ...Transformer) mapstructure.DecodeHookFuncType {
@@ -684,7 +687,7 @@ func absPath(workingDir string, filePath string) string {
return filepath.Join(workingDir, filePath)
}
func transformMapStringString(data interface{}) (interface{}, error) {
var transformMapStringString TransformerFunc = func(data interface{}) (interface{}, error) {
switch value := data.(type) {
case map[string]interface{}:
return toMapStringString(value, false), nil
@@ -695,7 +698,7 @@ func transformMapStringString(data interface{}) (interface{}, error) {
}
}
func transformExternal(data interface{}) (interface{}, error) {
var transformExternal TransformerFunc = func(data interface{}) (interface{}, error) {
switch value := data.(type) {
case bool:
return map[string]interface{}{"external": value}, nil
@@ -706,7 +709,7 @@ func transformExternal(data interface{}) (interface{}, error) {
}
}
func transformServicePort(data interface{}) (interface{}, error) {
var transformServicePort TransformerFunc = func(data interface{}) (interface{}, error) {
switch entries := data.(type) {
case []interface{}:
// We process the list instead of individual items here.
@@ -739,7 +742,7 @@ func transformServicePort(data interface{}) (interface{}, error) {
}
}
func transformStringSourceMap(data interface{}) (interface{}, error) {
var transformStringSourceMap TransformerFunc = func(data interface{}) (interface{}, error) {
switch value := data.(type) {
case string:
return map[string]interface{}{"source": value}, nil
@@ -750,7 +753,7 @@ func transformStringSourceMap(data interface{}) (interface{}, error) {
}
}
func transformBuildConfig(data interface{}) (interface{}, error) {
var transformBuildConfig TransformerFunc = func(data interface{}) (interface{}, error) {
switch value := data.(type) {
case string:
return map[string]interface{}{"context": value}, nil
@@ -761,7 +764,7 @@ func transformBuildConfig(data interface{}) (interface{}, error) {
}
}
func transformServiceVolumeConfig(data interface{}) (interface{}, error) {
var transformServiceVolumeConfig TransformerFunc = func(data interface{}) (interface{}, error) {
switch value := data.(type) {
case string:
return ParseVolume(value)
@@ -772,7 +775,7 @@ func transformServiceVolumeConfig(data interface{}) (interface{}, error) {
}
}
func transformServiceNetworkMap(value interface{}) (interface{}, error) {
var transformServiceNetworkMap TransformerFunc = func(value interface{}) (interface{}, error) {
if list, ok := value.([]interface{}); ok {
mapValue := map[interface{}]interface{}{}
for _, name := range list {
@@ -783,7 +786,7 @@ func transformServiceNetworkMap(value interface{}) (interface{}, error) {
return value, nil
}
func transformStringOrNumberList(value interface{}) (interface{}, error) {
var transformStringOrNumberList TransformerFunc = func(value interface{}) (interface{}, error) {
list := value.([]interface{})
result := make([]string, len(list))
for i, item := range list {
@@ -792,7 +795,7 @@ func transformStringOrNumberList(value interface{}) (interface{}, error) {
return result, nil
}
func transformStringList(data interface{}) (interface{}, error) {
var transformStringList TransformerFunc = func(data interface{}) (interface{}, error) {
switch value := data.(type) {
case string:
return []string{value}, nil
@@ -803,13 +806,13 @@ func transformStringList(data interface{}) (interface{}, error) {
}
}
func transformMappingOrListFunc(sep string, allowNil bool) func(interface{}) (interface{}, error) {
func transformMappingOrListFunc(sep string, allowNil bool) TransformerFunc {
return func(data interface{}) (interface{}, error) {
return transformMappingOrList(data, sep, allowNil), nil
}
}
func transformListOrMappingFunc(sep string, allowNil bool) func(interface{}) (interface{}, error) {
func transformListOrMappingFunc(sep string, allowNil bool) TransformerFunc {
return func(data interface{}) (interface{}, error) {
return transformListOrMapping(data, sep, allowNil), nil
}
@@ -848,14 +851,14 @@ func transformMappingOrList(mappingOrList interface{}, sep string, allowNil bool
panic(errors.Errorf("expected a map or a list, got %T: %#v", mappingOrList, mappingOrList))
}
func transformShellCommand(value interface{}) (interface{}, error) {
var transformShellCommand TransformerFunc = func(value interface{}) (interface{}, error) {
if str, ok := value.(string); ok {
return shellwords.Parse(str)
}
return value, nil
}
func transformHealthCheckTest(data interface{}) (interface{}, error) {
var transformHealthCheckTest TransformerFunc = func(data interface{}) (interface{}, error) {
switch value := data.(type) {
case string:
return append([]string{"CMD-SHELL"}, value), nil
@@ -866,7 +869,7 @@ func transformHealthCheckTest(data interface{}) (interface{}, error) {
}
}
func transformSize(value interface{}) (interface{}, error) {
var transformSize TransformerFunc = func(value interface{}) (interface{}, error) {
switch value := value.(type) {
case int:
return int64(value), nil
@@ -876,7 +879,7 @@ func transformSize(value interface{}) (interface{}, error) {
panic(errors.Errorf("invalid type for size %T", value))
}
func transformStringToDuration(value interface{}) (interface{}, error) {
var transformStringToDuration TransformerFunc = func(value interface{}) (interface{}, error) {
switch value := value.(type) {
case string:
d, err := time.ParseDuration(value)

View File

@@ -57,9 +57,12 @@ func mergeServices(base, override []types.ServiceConfig) ([]types.ServiceConfig,
reflect.TypeOf([]types.ServicePortConfig{}): mergeSlice(toServicePortConfigsMap, toServicePortConfigsSlice),
reflect.TypeOf([]types.ServiceSecretConfig{}): mergeSlice(toServiceSecretConfigsMap, toServiceSecretConfigsSlice),
reflect.TypeOf([]types.ServiceConfigObjConfig{}): mergeSlice(toServiceConfigObjConfigsMap, toSServiceConfigObjConfigsSlice),
reflect.TypeOf(&types.UlimitsConfig{}): mergeUlimitsConfig,
reflect.TypeOf(&types.ServiceNetworkConfig{}): mergeServiceNetworkConfig,
},
}
for name, overrideService := range overrideServices {
overrideService := overrideService
if baseService, ok := baseServices[name]; ok {
if err := mergo.Merge(&baseService, &overrideService, mergo.WithAppendSlice, mergo.WithOverride, mergo.WithTransformers(specials)); err != nil {
return base, errors.Wrapf(err, "cannot merge service %s", name)
@@ -200,6 +203,28 @@ func mergeLoggingConfig(dst, src reflect.Value) error {
return nil
}
//nolint: unparam
func mergeUlimitsConfig(dst, src reflect.Value) error {
if src.Interface() != reflect.Zero(reflect.TypeOf(src.Interface())).Interface() {
dst.Elem().Set(src.Elem())
}
return nil
}
//nolint: unparam
func mergeServiceNetworkConfig(dst, src reflect.Value) error {
if src.Interface() != reflect.Zero(reflect.TypeOf(src.Interface())).Interface() {
dst.Elem().FieldByName("Aliases").Set(src.Elem().FieldByName("Aliases"))
if ipv4 := src.Elem().FieldByName("Ipv4Address").Interface().(string); ipv4 != "" {
dst.Elem().FieldByName("Ipv4Address").SetString(ipv4)
}
if ipv6 := src.Elem().FieldByName("Ipv6Address").Interface().(string); ipv6 != "" {
dst.Elem().FieldByName("Ipv6Address").SetString(ipv6)
}
}
return nil
}
func getLoggingDriver(v reflect.Value) string {
return v.FieldByName("Driver").String()
}

View File

@@ -111,6 +111,9 @@ func isFilePath(source string) bool {
case '.', '/', '~':
return true
}
if len([]rune(source)) == 1 {
return false
}
// windows named pipes
if strings.HasPrefix(source, `\\`) {

View File

@@ -6,6 +6,8 @@ import (
"bytes"
"compress/gzip"
"encoding/base64"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
@@ -100,7 +102,24 @@ func (f *_escFile) Close() error {
}
func (f *_escFile) Readdir(count int) ([]os.FileInfo, error) {
return nil, nil
if !f.isDir {
return nil, fmt.Errorf(" escFile.Readdir: '%s' is not directory", f.name)
}
fis, ok := _escDirs[f.local]
if !ok {
return nil, fmt.Errorf(" escFile.Readdir: '%s' is directory, but we have no info about content of this dir, local=%s", f.name, f.local)
}
limit := count
if count <= 0 || limit > len(fis) {
limit = len(fis)
}
if len(fis) == 0 && count > 0 {
return nil, io.EOF
}
return fis[0:limit], nil
}
func (f *_escFile) Stat() (os.FileInfo, error) {
@@ -191,6 +210,7 @@ func _escFSMustString(useLocal bool, name string) string {
var _escData = map[string]*_escFile{
"/data/config_schema_v3.0.json": {
name: "config_schema_v3.0.json",
local: "data/config_schema_v3.0.json",
size: 11063,
modtime: 1518458244,
@@ -226,6 +246,7 @@ xHv6XdkMqA34L74ys3aKw8XE5Pt4DNh+IZaN/DMhad9yDyAlGzbxc2F0fns2HUJ234BlbrgaD1QS+++Y
},
"/data/config_schema_v3.1.json": {
name: "config_schema_v3.1.json",
local: "data/config_schema_v3.1.json",
size: 12209,
modtime: 1518458244,
@@ -262,6 +283,7 @@ f55aMuPsI9DxPLh9jLlw/TGcbUX23yn6OwAA//8cyfJJsS8AAA==
},
"/data/config_schema_v3.2.json": {
name: "config_schema_v3.2.json",
local: "data/config_schema_v3.2.json",
size: 13755,
modtime: 1518458244,
@@ -300,6 +322,7 @@ ZbmZv+QaLHpS4rzkKyabuw8zkGHuhdMrnbUrtIOnbTqoMzZd83f41N8R/735o4f/lZziOLoU+2E3AJpH
},
"/data/config_schema_v3.3.json": {
name: "config_schema_v3.3.json",
local: "data/config_schema_v3.3.json",
size: 15491,
modtime: 1518458244,
@@ -340,6 +363,7 @@ b/Iu7P/nxf8DAAD//7pHo+CDPAAA
},
"/data/config_schema_v3.4.json": {
name: "config_schema_v3.4.json",
local: "data/config_schema_v3.4.json",
size: 15874,
modtime: 1518458244,
@@ -381,6 +405,7 @@ PS1sPmQbucDQbzovyv9fFv8LAAD//+uCPa4CPgAA
},
"/data/config_schema_v3.5.json": {
name: "config_schema_v3.5.json",
local: "data/config_schema_v3.5.json",
size: 16802,
modtime: 1518458244,
@@ -423,6 +448,7 @@ Pum2n6FuR/KZkNgb9IOAvY0qfF0fuE7P2bsPTT1Xf8bV4ab+/7z5fwAAAP//yoGbgKJBAAA=
},
"/data/config_schema_v3.6.json": {
name: "config_schema_v3.6.json",
local: "data/config_schema_v3.6.json",
size: 17084,
modtime: 1518458244,
@@ -466,6 +492,7 @@ oqbZ4ab+/7z5fwAAAP//nm8U9rxCAAA=
},
"/data/config_schema_v3.7.json": {
name: "config_schema_v3.7.json",
local: "data/config_schema_v3.7.json",
size: 17854,
modtime: 1518458244,
@@ -509,6 +536,7 @@ bnBpPlHfjORjkTRf1wyAwiYqMXd9/G6313QfoXs6/sbZ66r6e179PwAA//8ZL3SpvkUAAA==
},
"/data/config_schema_v3.8.json": {
name: "config_schema_v3.8.json",
local: "data/config_schema_v3.8.json",
size: 18246,
modtime: 1518458244,
@@ -553,56 +581,69 @@ ean7MQBPP+U4w19V/z+t/hsAAP//Fd/bF0ZHAAA=
},
"/data/config_schema_v3.9.json": {
name: "config_schema_v3.9.json",
local: "data/config_schema_v3.9.json",
size: 18246,
size: 18291,
modtime: 1518458244,
compressed: `
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
vNT9GICnn3Kc4a+q/59W/w0AAP//CCwovkZHAAA=
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
vNT9coCnn3Ic4a+q/59W/w0AAP//UTBYfXNHAAA=
`,
},
"/": {
isDir: true,
local: "",
},
"/data": {
name: "data",
local: `data`,
isDir: true,
local: "data",
},
}
var _escDirs = map[string][]os.FileInfo{
"data": {
_escData["/data/config_schema_v3.0.json"],
_escData["/data/config_schema_v3.1.json"],
_escData["/data/config_schema_v3.2.json"],
_escData["/data/config_schema_v3.3.json"],
_escData["/data/config_schema_v3.4.json"],
_escData["/data/config_schema_v3.5.json"],
_escData["/data/config_schema_v3.6.json"],
_escData["/data/config_schema_v3.7.json"],
_escData["/data/config_schema_v3.8.json"],
_escData["/data/config_schema_v3.9.json"],
},
}

View File

@@ -11,6 +11,7 @@ var UnsupportedProperties = []string{
"build",
"cap_add",
"cap_drop",
"cgroupns_mode",
"cgroup_parent",
"devices",
"domainname",
@@ -103,7 +104,7 @@ type Config struct {
Volumes map[string]VolumeConfig `yaml:",omitempty" json:"volumes,omitempty"`
Secrets map[string]SecretConfig `yaml:",omitempty" json:"secrets,omitempty"`
Configs map[string]ConfigObjConfig `yaml:",omitempty" json:"configs,omitempty"`
Extras map[string]interface{} `yaml:",inline", json:"-"`
Extras map[string]interface{} `yaml:",inline" json:"-"`
}
// MarshalJSON makes Config implement json.Marshaler
@@ -159,6 +160,7 @@ type ServiceConfig struct {
Build BuildConfig `yaml:",omitempty" json:"build,omitempty"`
CapAdd []string `mapstructure:"cap_add" yaml:"cap_add,omitempty" json:"cap_add,omitempty"`
CapDrop []string `mapstructure:"cap_drop" yaml:"cap_drop,omitempty" json:"cap_drop,omitempty"`
CgroupNSMode string `mapstructure:"cgroupns_mode" yaml:"cgroupns_mode,omitempty" json:"cgroupns_mode,omitempty"`
CgroupParent string `mapstructure:"cgroup_parent" yaml:"cgroup_parent,omitempty" json:"cgroup_parent,omitempty"`
Command ShellCommand `yaml:",omitempty" json:"command,omitempty"`
Configs []ServiceConfigObjConfig `yaml:",omitempty" json:"configs,omitempty"`

View File

@@ -10,6 +10,7 @@ import (
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/config/credentials"
"github.com/docker/cli/cli/config/types"
"github.com/docker/docker/pkg/homedir"
"github.com/pkg/errors"
)
@@ -27,10 +28,7 @@ var (
func init() {
if configDir == "" {
homedir, err := os.UserHomeDir()
if err == nil {
configDir = filepath.Join(homedir, configFileDir)
}
configDir = filepath.Join(homedir.Get(), configFileDir)
}
}
@@ -114,7 +112,7 @@ func Load(configDir string) (*configfile.ConfigFile, error) {
}
confFile := filepath.Join(homedir, oldConfigfile)
if _, err := os.Stat(confFile); err != nil {
return configFile, nil //missing file is not an error
return configFile, nil // missing file is not an error
}
file, err := os.Open(confFile)
if err != nil {

View File

@@ -123,9 +123,11 @@ func (configFile *ConfigFile) LoadFromReader(configData io.Reader) error {
}
var err error
for addr, ac := range configFile.AuthConfigs {
ac.Username, ac.Password, err = decodeAuth(ac.Auth)
if err != nil {
return err
if ac.Auth != "" {
ac.Username, ac.Password, err = decodeAuth(ac.Auth)
if err != nil {
return err
}
}
ac.Auth = ""
ac.ServerAddress = addr
@@ -194,6 +196,9 @@ func (configFile *ConfigFile) Save() error {
os.Remove(temp.Name())
return err
}
// Try copying the current config file (if any) ownership and permissions
copyFilePermissions(configFile.Filename, temp.Name())
return os.Rename(temp.Name(), configFile.Filename)
}

View File

@@ -0,0 +1,35 @@
// +build !windows
package configfile
import (
"os"
"syscall"
)
// copyFilePermissions copies file ownership and permissions from "src" to "dst",
// ignoring any error during the process.
func copyFilePermissions(src, dst string) {
var (
mode os.FileMode = 0600
uid, gid int
)
fi, err := os.Stat(src)
if err != nil {
return
}
if fi.Mode().IsRegular() {
mode = fi.Mode()
}
if err := os.Chmod(dst, mode); err != nil {
return
}
uid = int(fi.Sys().(*syscall.Stat_t).Uid)
gid = int(fi.Sys().(*syscall.Stat_t).Gid)
if uid > 0 && gid > 0 {
_ = os.Chown(dst, uid, gid)
}
}

View File

@@ -0,0 +1,5 @@
package configfile
func copyFilePermissions(src, dst string) {
// TODO implement for Windows
}

View File

@@ -21,6 +21,13 @@ type EndpointMeta struct {
DefaultNamespace string `json:",omitempty"`
AuthProvider *clientcmdapi.AuthProviderConfig `json:",omitempty"`
Exec *clientcmdapi.ExecConfig `json:",omitempty"`
UsernamePassword *UsernamePassword `json:"usernamePassword,omitempty"`
}
// UsernamePassword contains username/password auth info
type UsernamePassword struct {
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
}
var _ command.EndpointDefaultResolver = &EndpointMeta{}
@@ -62,6 +69,10 @@ func (c *Endpoint) KubernetesConfig() clientcmd.ClientConfig {
authInfo.ClientCertificateData = c.TLSData.Cert
authInfo.ClientKeyData = c.TLSData.Key
}
if c.UsernamePassword != nil {
authInfo.Username = c.UsernamePassword.Username
authInfo.Password = c.UsernamePassword.Password
}
authInfo.AuthProvider = c.AuthProvider
authInfo.Exec = c.Exec
cfg.Clusters["cluster"] = cluster

View File

@@ -39,6 +39,13 @@ func FromKubeConfig(kubeconfig, kubeContext, namespaceOverride string) (Endpoint
Key: key,
}
}
var usernamePassword *UsernamePassword
if clientcfg.Username != "" || clientcfg.Password != "" {
usernamePassword = &UsernamePassword{
Username: clientcfg.Username,
Password: clientcfg.Password,
}
}
return Endpoint{
EndpointMeta: EndpointMeta{
EndpointMetaBase: context.EndpointMetaBase{
@@ -48,6 +55,7 @@ func FromKubeConfig(kubeconfig, kubeContext, namespaceOverride string) (Endpoint
DefaultNamespace: ns,
AuthProvider: clientcfg.AuthProvider,
Exec: clientcfg.ExecProvider,
UsernamePassword: usernamePassword,
},
TLSData: tlsData,
}, nil

View File

@@ -11,7 +11,7 @@ import (
"github.com/docker/distribution/manifest/schema2"
"github.com/docker/distribution/reference"
"github.com/docker/distribution/registry/api/errcode"
"github.com/docker/distribution/registry/api/v2"
v2 "github.com/docker/distribution/registry/api/v2"
distclient "github.com/docker/distribution/registry/client"
"github.com/docker/docker/registry"
digest "github.com/opencontainers/go-digest"
@@ -103,9 +103,6 @@ func pullManifestSchemaV2ImageConfig(ctx context.Context, dgst digest.Digest, re
}
verifier := dgst.Verifier()
if err != nil {
return nil, err
}
if _, err := verifier.Write(configJSON); err != nil {
return nil, err
}
@@ -212,7 +209,6 @@ func (c *client) iterateEndpoints(ctx context.Context, namedRef reference.Named,
confirmedTLSRegistries := make(map[string]bool)
for _, endpoint := range endpoints {
if endpoint.Version == registry.APIVersion1 {
logrus.Debugf("skipping v1 endpoint %s", endpoint.URL)
continue

View File

@@ -99,6 +99,7 @@ func ExactArgs(number int) cobra.PositionalArgs {
}
}
//nolint: unparam
func pluralize(word string, number int) string {
if number == 1 {
return word

View File

@@ -1,78 +0,0 @@
package containerizedengine
import (
"context"
"io"
"github.com/containerd/containerd"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/remotes/docker"
clitypes "github.com/docker/cli/types"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/jsonmessage"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
// NewClient returns a new containerizedengine client
// This client can be used to manage the lifecycle of
// dockerd running as a container on containerd.
func NewClient(sockPath string) (clitypes.ContainerizedClient, error) {
if sockPath == "" {
sockPath = containerdSockPath
}
cclient, err := containerd.New(sockPath)
if err != nil {
return nil, err
}
return &baseClient{
cclient: cclient,
}, nil
}
// Close will close the underlying clients
func (c *baseClient) Close() error {
return c.cclient.Close()
}
func (c *baseClient) pullWithAuth(ctx context.Context, imageName string, out clitypes.OutStream,
authConfig *types.AuthConfig) (containerd.Image, error) {
resolver := docker.NewResolver(docker.ResolverOptions{
Credentials: func(string) (string, string, error) {
return authConfig.Username, authConfig.Password, nil
},
})
ongoing := newJobs(imageName)
pctx, stopProgress := context.WithCancel(ctx)
progress := make(chan struct{})
bufin, bufout := io.Pipe()
go func() {
showProgress(pctx, ongoing, c.cclient.ContentStore(), bufout)
}()
go func() {
jsonmessage.DisplayJSONMessagesToStream(bufin, out, nil)
close(progress)
}()
h := images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
if desc.MediaType != images.MediaTypeDockerSchema1Manifest {
ongoing.add(desc)
}
return nil, nil
})
image, err := c.cclient.Pull(ctx, imageName,
containerd.WithResolver(resolver),
containerd.WithImageHandler(h),
containerd.WithPullUnpack)
stopProgress()
if err != nil {
return nil, err
}
<-progress
return image, nil
}

View File

@@ -1,215 +0,0 @@
package containerizedengine
import (
"context"
"encoding/json"
"fmt"
"io"
"strings"
"sync"
"time"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/remotes"
"github.com/docker/docker/pkg/jsonmessage"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/sirupsen/logrus"
)
func showProgress(ctx context.Context, ongoing *jobs, cs content.Store, out io.WriteCloser) {
var (
ticker = time.NewTicker(100 * time.Millisecond)
start = time.Now()
enc = json.NewEncoder(out)
statuses = map[string]statusInfo{}
done bool
)
defer ticker.Stop()
outer:
for {
select {
case <-ticker.C:
resolved := "resolved"
if !ongoing.isResolved() {
resolved = "resolving"
}
statuses[ongoing.name] = statusInfo{
Ref: ongoing.name,
Status: resolved,
}
keys := []string{ongoing.name}
activeSeen := map[string]struct{}{}
if !done {
active, err := cs.ListStatuses(ctx, "")
if err != nil {
logrus.Debugf("active check failed: %s", err)
continue
}
// update status of active entries!
for _, active := range active {
statuses[active.Ref] = statusInfo{
Ref: active.Ref,
Status: "downloading",
Offset: active.Offset,
Total: active.Total,
StartedAt: active.StartedAt,
UpdatedAt: active.UpdatedAt,
}
activeSeen[active.Ref] = struct{}{}
}
}
err := updateNonActive(ctx, ongoing, cs, statuses, &keys, activeSeen, &done, start)
if err != nil {
continue outer
}
var ordered []statusInfo
for _, key := range keys {
ordered = append(ordered, statuses[key])
}
for _, si := range ordered {
jm := si.JSONMessage()
err := enc.Encode(jm)
if err != nil {
logrus.Debugf("failed to encode progress message: %s", err)
}
}
if done {
out.Close()
return
}
case <-ctx.Done():
done = true // allow ui to update once more
}
}
}
func updateNonActive(ctx context.Context, ongoing *jobs, cs content.Store, statuses map[string]statusInfo, keys *[]string, activeSeen map[string]struct{}, done *bool, start time.Time) error {
for _, j := range ongoing.jobs() {
key := remotes.MakeRefKey(ctx, j)
*keys = append(*keys, key)
if _, ok := activeSeen[key]; ok {
continue
}
status, ok := statuses[key]
if !*done && (!ok || status.Status == "downloading") {
info, err := cs.Info(ctx, j.Digest)
if err != nil {
if !errdefs.IsNotFound(err) {
logrus.Debugf("failed to get content info: %s", err)
return err
}
statuses[key] = statusInfo{
Ref: key,
Status: "waiting",
}
} else if info.CreatedAt.After(start) {
statuses[key] = statusInfo{
Ref: key,
Status: "done",
Offset: info.Size,
Total: info.Size,
UpdatedAt: info.CreatedAt,
}
} else {
statuses[key] = statusInfo{
Ref: key,
Status: "exists",
}
}
} else if *done {
if ok {
if status.Status != "done" && status.Status != "exists" {
status.Status = "done"
statuses[key] = status
}
} else {
statuses[key] = statusInfo{
Ref: key,
Status: "done",
}
}
}
}
return nil
}
type jobs struct {
name string
added map[digest.Digest]struct{}
descs []ocispec.Descriptor
mu sync.Mutex
resolved bool
}
func newJobs(name string) *jobs {
return &jobs{
name: name,
added: map[digest.Digest]struct{}{},
}
}
func (j *jobs) add(desc ocispec.Descriptor) {
j.mu.Lock()
defer j.mu.Unlock()
j.resolved = true
if _, ok := j.added[desc.Digest]; ok {
return
}
j.descs = append(j.descs, desc)
j.added[desc.Digest] = struct{}{}
}
func (j *jobs) jobs() []ocispec.Descriptor {
j.mu.Lock()
defer j.mu.Unlock()
var descs []ocispec.Descriptor
return append(descs, j.descs...)
}
func (j *jobs) isResolved() bool {
j.mu.Lock()
defer j.mu.Unlock()
return j.resolved
}
// statusInfo holds the status info for an upload or download
type statusInfo struct {
Ref string
Status string
Offset int64
Total int64
StartedAt time.Time
UpdatedAt time.Time
}
func (s statusInfo) JSONMessage() jsonmessage.JSONMessage {
// Shorten the ID to use up less width on the display
id := s.Ref
if strings.Contains(id, ":") {
split := strings.SplitN(id, ":", 2)
id = split[1]
}
id = fmt.Sprintf("%.12s", id)
return jsonmessage.JSONMessage{
ID: id,
Status: s.Status,
Progress: &jsonmessage.JSONProgress{
Current: s.Offset,
Total: s.Total,
},
}
}

View File

@@ -1,49 +0,0 @@
package containerizedengine
import (
"context"
"errors"
"github.com/containerd/containerd"
"github.com/containerd/containerd/containers"
"github.com/containerd/containerd/content"
)
const (
containerdSockPath = "/run/containerd/containerd.sock"
engineNamespace = "com.docker"
)
var (
// ErrEngineAlreadyPresent returned when engine already present and should not be
ErrEngineAlreadyPresent = errors.New("engine already present, use the update command to change versions")
// ErrEngineNotPresent returned when the engine is not present and should be
ErrEngineNotPresent = errors.New("engine not present")
// ErrMalformedConfigFileParam returned if the engine config file parameter is malformed
ErrMalformedConfigFileParam = errors.New("malformed --config-file param on engine")
// ErrEngineConfigLookupFailure returned if unable to lookup existing engine configuration
ErrEngineConfigLookupFailure = errors.New("unable to lookup existing engine configuration")
// ErrEngineShutdownTimeout returned if the engine failed to shutdown in time
ErrEngineShutdownTimeout = errors.New("timeout waiting for engine to exit")
)
type baseClient struct {
cclient containerdClient
}
// containerdClient abstracts the containerd client to aid in testability
type containerdClient interface {
Containers(ctx context.Context, filters ...string) ([]containerd.Container, error)
NewContainer(ctx context.Context, id string, opts ...containerd.NewContainerOpts) (containerd.Container, error)
Pull(ctx context.Context, ref string, opts ...containerd.RemoteOpt) (containerd.Image, error)
GetImage(ctx context.Context, ref string) (containerd.Image, error)
Close() error
ContentStore() content.Store
ContainerService() containers.Store
Install(context.Context, containerd.Image, ...containerd.InstallOpts) error
Version(ctx context.Context) (containerd.Version, error)
}

View File

@@ -1,183 +0,0 @@
package containerizedengine
import (
"context"
"encoding/json"
"fmt"
"strings"
"github.com/containerd/containerd"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/namespaces"
"github.com/docker/cli/internal/versions"
clitypes "github.com/docker/cli/types"
"github.com/docker/distribution/reference"
"github.com/docker/docker/api/types"
ver "github.com/hashicorp/go-version"
"github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)
// ActivateEngine will switch the image from the CE to EE image
func (c *baseClient) ActivateEngine(ctx context.Context, opts clitypes.EngineInitOptions, out clitypes.OutStream,
authConfig *types.AuthConfig) error {
// If the user didn't specify an image, determine the correct enterprise image to use
if opts.EngineImage == "" {
localMetadata, err := versions.GetCurrentRuntimeMetadata(opts.RuntimeMetadataDir)
if err != nil {
return errors.Wrap(err, "unable to determine the installed engine version. Specify which engine image to update with --engine-image")
}
engineImage := localMetadata.EngineImage
if engineImage == clitypes.EnterpriseEngineImage || engineImage == clitypes.CommunityEngineImage {
opts.EngineImage = clitypes.EnterpriseEngineImage
} else {
// Chop off the standard prefix and retain any trailing OS specific image details
// e.g., engine-community-dm -> engine-enterprise-dm
engineImage = strings.TrimPrefix(engineImage, clitypes.EnterpriseEngineImage)
engineImage = strings.TrimPrefix(engineImage, clitypes.CommunityEngineImage)
opts.EngineImage = clitypes.EnterpriseEngineImage + engineImage
}
}
ctx = namespaces.WithNamespace(ctx, engineNamespace)
return c.DoUpdate(ctx, opts, out, authConfig)
}
// DoUpdate performs the underlying engine update
func (c *baseClient) DoUpdate(ctx context.Context, opts clitypes.EngineInitOptions, out clitypes.OutStream,
authConfig *types.AuthConfig) error {
ctx = namespaces.WithNamespace(ctx, engineNamespace)
if opts.EngineVersion == "" {
// TODO - Future enhancement: This could be improved to be
// smart about figuring out the latest patch rev for the
// current engine version and automatically apply it so users
// could stay in sync by simply having a scheduled
// `docker engine update`
return fmt.Errorf("pick the version you want to update to with --version")
}
var localMetadata *clitypes.RuntimeMetadata
if opts.EngineImage == "" {
var err error
localMetadata, err = versions.GetCurrentRuntimeMetadata(opts.RuntimeMetadataDir)
if err != nil {
return errors.Wrap(err, "unable to determine the installed engine version. Specify which engine image to update with --engine-image set to 'engine-community' or 'engine-enterprise'")
}
opts.EngineImage = localMetadata.EngineImage
}
imageName := fmt.Sprintf("%s/%s:%s", opts.RegistryPrefix, opts.EngineImage, opts.EngineVersion)
// Look for desired image
image, err := c.cclient.GetImage(ctx, imageName)
if err != nil {
if errdefs.IsNotFound(err) {
image, err = c.pullWithAuth(ctx, imageName, out, authConfig)
if err != nil {
return errors.Wrapf(err, "unable to pull image %s", imageName)
}
} else {
return errors.Wrapf(err, "unable to check for image %s", imageName)
}
}
// Make sure we're safe to proceed
newMetadata, err := c.PreflightCheck(ctx, image)
if err != nil {
return err
}
if localMetadata != nil {
if localMetadata.Platform != newMetadata.Platform {
fmt.Fprintf(out, "\nNotice: you have switched to \"%s\". Refer to %s for update instructions.\n\n", newMetadata.Platform, getReleaseNotesURL(imageName))
}
}
if err := c.cclient.Install(ctx, image, containerd.WithInstallReplace, containerd.WithInstallPath("/usr")); err != nil {
return err
}
return versions.WriteRuntimeMetadata(opts.RuntimeMetadataDir, newMetadata)
}
// PreflightCheck verifies the specified image is compatible with the local system before proceeding to update/activate
// If things look good, the RuntimeMetadata for the new image is returned and can be written out to the host
func (c *baseClient) PreflightCheck(ctx context.Context, image containerd.Image) (*clitypes.RuntimeMetadata, error) {
var metadata clitypes.RuntimeMetadata
ic, err := image.Config(ctx)
if err != nil {
return nil, err
}
var (
ociimage v1.Image
config v1.ImageConfig
)
switch ic.MediaType {
case v1.MediaTypeImageConfig, images.MediaTypeDockerSchema2Config:
p, err := content.ReadBlob(ctx, image.ContentStore(), ic)
if err != nil {
return nil, err
}
if err := json.Unmarshal(p, &ociimage); err != nil {
return nil, err
}
config = ociimage.Config
default:
return nil, fmt.Errorf("unknown image %s config media type %s", image.Name(), ic.MediaType)
}
metadataString, ok := config.Labels["com.docker."+clitypes.RuntimeMetadataName]
if !ok {
return nil, fmt.Errorf("image %s does not contain runtime metadata label %s", image.Name(), clitypes.RuntimeMetadataName)
}
err = json.Unmarshal([]byte(metadataString), &metadata)
if err != nil {
return nil, errors.Wrapf(err, "malformed runtime metadata file in %s", image.Name())
}
// Current CLI only supports host install runtime
if metadata.Runtime != "host_install" {
return nil, fmt.Errorf("unsupported daemon image: %s\nConsult the release notes at %s for upgrade instructions", metadata.Runtime, getReleaseNotesURL(image.Name()))
}
// Verify local containerd is new enough
localVersion, err := c.cclient.Version(ctx)
if err != nil {
return nil, err
}
if metadata.ContainerdMinVersion != "" {
lv, err := ver.NewVersion(localVersion.Version)
if err != nil {
return nil, err
}
mv, err := ver.NewVersion(metadata.ContainerdMinVersion)
if err != nil {
return nil, err
}
if lv.LessThan(mv) {
return nil, fmt.Errorf("local containerd is too old: %s - this engine version requires %s or newer.\nConsult the release notes at %s for upgrade instructions",
localVersion.Version, metadata.ContainerdMinVersion, getReleaseNotesURL(image.Name()))
}
} // If omitted on metadata, no hard dependency on containerd version beyond 18.09 baseline
// All checks look OK, proceed with update
return &metadata, nil
}
// getReleaseNotesURL returns a release notes url
// If the image name does not contain a version tag, the base release notes URL is returned
func getReleaseNotesURL(imageName string) string {
versionTag := ""
distributionRef, err := reference.ParseNormalizedNamed(imageName)
if err == nil {
taggedRef, ok := distributionRef.(reference.NamedTagged)
if ok {
versionTag = taggedRef.Tag()
}
}
return fmt.Sprintf("%s/%s", clitypes.ReleaseNotePrefix, versionTag)
}

View File

@@ -1,127 +0,0 @@
package versions
import (
"context"
"encoding/json"
"io/ioutil"
"os"
"path"
"path/filepath"
"sort"
registryclient "github.com/docker/cli/cli/registry/client"
clitypes "github.com/docker/cli/types"
"github.com/docker/distribution/reference"
ver "github.com/hashicorp/go-version"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
const (
// defaultRuntimeMetadataDir is the location where the metadata file is stored
defaultRuntimeMetadataDir = "/var/lib/docker-engine"
)
// GetEngineVersions reports the versions of the engine that are available
func GetEngineVersions(ctx context.Context, registryClient registryclient.RegistryClient, registryPrefix, imageName, versionString string) (clitypes.AvailableVersions, error) {
if imageName == "" {
var err error
localMetadata, err := GetCurrentRuntimeMetadata("")
if err != nil {
return clitypes.AvailableVersions{}, err
}
imageName = localMetadata.EngineImage
}
imageRef, err := reference.ParseNormalizedNamed(path.Join(registryPrefix, imageName))
if err != nil {
return clitypes.AvailableVersions{}, err
}
tags, err := registryClient.GetTags(ctx, imageRef)
if err != nil {
return clitypes.AvailableVersions{}, err
}
return parseTags(tags, versionString)
}
func parseTags(tags []string, currentVersion string) (clitypes.AvailableVersions, error) {
var ret clitypes.AvailableVersions
currentVer, err := ver.NewVersion(currentVersion)
if err != nil {
return ret, errors.Wrapf(err, "failed to parse existing version %s", currentVersion)
}
downgrades := []clitypes.DockerVersion{}
patches := []clitypes.DockerVersion{}
upgrades := []clitypes.DockerVersion{}
currentSegments := currentVer.Segments()
for _, tag := range tags {
tmp, err := ver.NewVersion(tag)
if err != nil {
logrus.Debugf("Unable to parse %s: %s", tag, err)
continue
}
testVersion := clitypes.DockerVersion{Version: *tmp, Tag: tag}
if testVersion.LessThan(currentVer) {
downgrades = append(downgrades, testVersion)
continue
}
testSegments := testVersion.Segments()
// lib always provides min 3 segments
if testSegments[0] == currentSegments[0] &&
testSegments[1] == currentSegments[1] {
patches = append(patches, testVersion)
} else {
upgrades = append(upgrades, testVersion)
}
}
sort.Slice(downgrades, func(i, j int) bool {
return downgrades[i].Version.LessThan(&downgrades[j].Version)
})
sort.Slice(patches, func(i, j int) bool {
return patches[i].Version.LessThan(&patches[j].Version)
})
sort.Slice(upgrades, func(i, j int) bool {
return upgrades[i].Version.LessThan(&upgrades[j].Version)
})
ret.Downgrades = downgrades
ret.Patches = patches
ret.Upgrades = upgrades
return ret, nil
}
// GetCurrentRuntimeMetadata loads the current daemon runtime metadata information from the local host
func GetCurrentRuntimeMetadata(metadataDir string) (*clitypes.RuntimeMetadata, error) {
if metadataDir == "" {
metadataDir = defaultRuntimeMetadataDir
}
filename := filepath.Join(metadataDir, clitypes.RuntimeMetadataName+".json")
data, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
var res clitypes.RuntimeMetadata
err = json.Unmarshal(data, &res)
if err != nil {
return nil, errors.Wrapf(err, "malformed runtime metadata file %s", filename)
}
return &res, nil
}
// WriteRuntimeMetadata stores the metadata on the local system
func WriteRuntimeMetadata(metadataDir string, metadata *clitypes.RuntimeMetadata) error {
if metadataDir == "" {
metadataDir = defaultRuntimeMetadataDir
}
filename := filepath.Join(metadataDir, clitypes.RuntimeMetadataName+".json")
data, err := json.Marshal(metadata)
if err != nil {
return err
}
os.Remove(filename)
return ioutil.WriteFile(filename, data, 0644)
}

View File

@@ -32,7 +32,7 @@ func (o *ConfigOpt) Set(value string) error {
}
// support a simple syntax of --config foo
if len(fields) == 1 {
if len(fields) == 1 && !strings.Contains(fields[0], "=") {
options.File.Name = fields[0]
options.ConfigName = fields[0]
o.values = append(o.values, options)
@@ -72,6 +72,9 @@ func (o *ConfigOpt) Set(value string) error {
if options.ConfigName == "" {
return fmt.Errorf("source is required")
}
if options.File.Name == "" {
options.File.Name = options.ConfigName
}
o.values = append(o.values, options)
return nil

View File

@@ -24,6 +24,12 @@ var (
DefaultTLSHost = fmt.Sprintf("tcp://%s:%d", DefaultHTTPHost, DefaultTLSHTTPPort)
// DefaultNamedPipe defines the default named pipe used by docker on Windows
DefaultNamedPipe = `//./pipe/docker_engine`
// hostGatewayName defines a special string which users can append to --add-host
// to add an extra entry in /etc/hosts that maps host.docker.internal to the host IP
// TODO Consider moving the HostGatewayName constant defined in docker at
// github.com/docker/docker/daemon/network/constants.go outside of the "daemon"
// package, so that the CLI can consume it.
hostGatewayName = "host-gateway"
)
// ValidateHost validates that the specified string is a valid host and returns it.
@@ -160,8 +166,11 @@ func ValidateExtraHost(val string) (string, error) {
if len(arr) != 2 || len(arr[0]) == 0 {
return "", fmt.Errorf("bad format for add-host: %q", val)
}
if _, err := ValidateIPAddress(arr[1]); err != nil {
return "", fmt.Errorf("invalid IP address in add-host: %q", arr[1])
// Skip IPaddr validation for "host-gateway" string
if arr[1] != hostGatewayName {
if _, err := ValidateIPAddress(arr[1]); err != nil {
return "", fmt.Errorf("invalid IP address in add-host: %q", arr[1])
}
}
return val, nil
}

View File

@@ -8,9 +8,11 @@ import (
)
const (
networkOptName = "name"
networkOptAlias = "alias"
driverOpt = "driver-opt"
networkOptName = "name"
networkOptAlias = "alias"
networkOptIPv4Address = "ip"
networkOptIPv6Address = "ip6"
driverOpt = "driver-opt"
)
// NetworkAttachmentOpts represents the network options for endpoint creation
@@ -19,8 +21,8 @@ type NetworkAttachmentOpts struct {
Aliases []string
DriverOpts map[string]string
Links []string // TODO add support for links in the csv notation of `--network`
IPv4Address string // TODO add support for IPv4-address in the csv notation of `--network`
IPv6Address string // TODO add support for IPv6-address in the csv notation of `--network`
IPv4Address string
IPv6Address string
LinkLocalIPs []string // TODO add support for LinkLocalIPs in the csv notation of `--network` ?
}
@@ -60,6 +62,10 @@ func (n *NetworkOpt) Set(value string) error {
netOpt.Target = value
case networkOptAlias:
netOpt.Aliases = append(netOpt.Aliases, value)
case networkOptIPv4Address:
netOpt.IPv4Address = value
case networkOptIPv6Address:
netOpt.IPv6Address = value
case driverOpt:
key, value, err = parseDriverOpt(value)
if err == nil {

View File

@@ -160,7 +160,7 @@ func ConvertPortToPortConfig(
for i := startHostPort; i <= endHostPort; i++ {
ports = append(ports, swarm.PortConfig{
//TODO Name: ?
// TODO Name: ?
Protocol: swarm.PortConfigProtocol(strings.ToLower(port.Proto())),
TargetPort: uint32(port.Int()),
PublishedPort: uint32(i),

View File

@@ -32,7 +32,7 @@ func (o *SecretOpt) Set(value string) error {
}
// support a simple syntax of --secret foo
if len(fields) == 1 {
if len(fields) == 1 && !strings.Contains(fields[0], "=") {
options.File.Name = fields[0]
options.SecretName = fields[0]
o.values = append(o.values, options)
@@ -72,6 +72,9 @@ func (o *SecretOpt) Set(value string) error {
if options.SecretName == "" {
return fmt.Errorf("source is required")
}
if options.File.Name == "" {
options.File.Name = options.SecretName
}
o.values = append(o.values, options)
return nil

View File

@@ -48,9 +48,6 @@ func ValidateThrottleIOpsDevice(val string) (*blkiodev.ThrottleDevice, error) {
if err != nil {
return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>. Number must be a positive integer", val)
}
if rate < 0 {
return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>. Number must be a positive integer", val)
}
return &blkiodev.ThrottleDevice{Path: split[0], Rate: rate}, nil
}

View File

@@ -1,88 +0,0 @@
package types
import (
"context"
"io"
"github.com/docker/docker/api/types"
ver "github.com/hashicorp/go-version"
)
const (
// CommunityEngineImage is the repo name for the community engine
CommunityEngineImage = "engine-community"
// EnterpriseEngineImage is the repo name for the enterprise engine
EnterpriseEngineImage = "engine-enterprise"
// RegistryPrefix is the default prefix used to pull engine images
RegistryPrefix = "docker.io/store/docker"
// ReleaseNotePrefix is where to point users to for release notes
ReleaseNotePrefix = "https://docs.docker.com/releasenotes"
// RuntimeMetadataName is the name of the runtime metadata file
// When stored as a label on the container it is prefixed by "com.docker."
RuntimeMetadataName = "distribution_based_engine"
)
// ContainerizedClient can be used to manage the lifecycle of
// dockerd running as a container on containerd.
type ContainerizedClient interface {
Close() error
ActivateEngine(ctx context.Context,
opts EngineInitOptions,
out OutStream,
authConfig *types.AuthConfig) error
DoUpdate(ctx context.Context,
opts EngineInitOptions,
out OutStream,
authConfig *types.AuthConfig) error
}
// EngineInitOptions contains the configuration settings
// use during initialization of a containerized docker engine
type EngineInitOptions struct {
RegistryPrefix string
EngineImage string
EngineVersion string
ConfigFile string
RuntimeMetadataDir string
}
// AvailableVersions groups the available versions which were discovered
type AvailableVersions struct {
Downgrades []DockerVersion
Patches []DockerVersion
Upgrades []DockerVersion
}
// DockerVersion wraps a semantic version to retain the original tag
// since the docker date based versions don't strictly follow semantic
// versioning (leading zeros, etc.)
type DockerVersion struct {
ver.Version
Tag string
}
// Update stores available updates for rendering in a table
type Update struct {
Type string
Version string
Notes string
}
// OutStream is an output stream used to write normal program output.
type OutStream interface {
io.Writer
FD() uintptr
IsTerminal() bool
}
// RuntimeMetadata holds platform information about the daemon
type RuntimeMetadata struct {
Platform string `json:"platform"`
ContainerdMinVersion string `json:"containerd_min_version"`
Runtime string `json:"runtime"`
EngineImage string `json:"engine_image"`
}