mirror of https://github.com/docker/cli.git
Merge pull request #3847 from thaJeztah/context_lazy_evaluate
context: implement lazy loading, and other improvements
This commit is contained in:
commit
ab794859fe
|
@ -2,12 +2,14 @@ package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/cli/cli/config"
|
"github.com/docker/cli/cli/config"
|
||||||
|
@ -78,6 +80,8 @@ type DockerCli struct {
|
||||||
contentTrust bool
|
contentTrust bool
|
||||||
contextStore store.Store
|
contextStore store.Store
|
||||||
currentContext string
|
currentContext string
|
||||||
|
init sync.Once
|
||||||
|
initErr error
|
||||||
dockerEndpoint docker.Endpoint
|
dockerEndpoint docker.Endpoint
|
||||||
contextStoreConfig store.Config
|
contextStoreConfig store.Config
|
||||||
initTimeout time.Duration
|
initTimeout time.Duration
|
||||||
|
@ -91,6 +95,7 @@ func (cli *DockerCli) DefaultVersion() string {
|
||||||
// CurrentVersion returns the API version currently negotiated, or the default
|
// CurrentVersion returns the API version currently negotiated, or the default
|
||||||
// version otherwise.
|
// version otherwise.
|
||||||
func (cli *DockerCli) CurrentVersion() string {
|
func (cli *DockerCli) CurrentVersion() string {
|
||||||
|
_ = cli.initialize()
|
||||||
if cli.client == nil {
|
if cli.client == nil {
|
||||||
return api.DefaultVersion
|
return api.DefaultVersion
|
||||||
}
|
}
|
||||||
|
@ -99,6 +104,10 @@ func (cli *DockerCli) CurrentVersion() string {
|
||||||
|
|
||||||
// Client returns the APIClient
|
// Client returns the APIClient
|
||||||
func (cli *DockerCli) Client() client.APIClient {
|
func (cli *DockerCli) Client() client.APIClient {
|
||||||
|
if err := cli.initialize(); err != nil {
|
||||||
|
_, _ = fmt.Fprintf(cli.Err(), "Failed to initialize: %s\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
return cli.client
|
return cli.client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +152,7 @@ func (cli *DockerCli) ConfigFile() *configfile.ConfigFile {
|
||||||
// ServerInfo returns the server version details for the host this client is
|
// ServerInfo returns the server version details for the host this client is
|
||||||
// connected to
|
// connected to
|
||||||
func (cli *DockerCli) ServerInfo() ServerInfo {
|
func (cli *DockerCli) ServerInfo() ServerInfo {
|
||||||
// TODO(thaJeztah) make ServerInfo() lazily load the info (ping only when needed)
|
_ = cli.initialize()
|
||||||
return cli.serverInfo
|
return cli.serverInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,8 +212,6 @@ func WithInitializeClient(makeClient func(dockerCli *DockerCli) (client.APIClien
|
||||||
// Initialize the dockerCli runs initialization that must happen after command
|
// Initialize the dockerCli runs initialization that must happen after command
|
||||||
// line flags are parsed.
|
// line flags are parsed.
|
||||||
func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions, ops ...InitializeOpt) error {
|
func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions, ops ...InitializeOpt) error {
|
||||||
var err error
|
|
||||||
|
|
||||||
for _, o := range ops {
|
for _, o := range ops {
|
||||||
if err := o(cli); err != nil {
|
if err := o(cli); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -232,18 +239,6 @@ func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions, ops ...Initialize
|
||||||
return ResolveDefaultContext(cli.options, cli.contextStoreConfig)
|
return ResolveDefaultContext(cli.options, cli.contextStoreConfig)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cli.dockerEndpoint, err = resolveDockerEndpoint(cli.contextStore, resolveContextName(opts, cli.configFile))
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "unable to resolve docker endpoint")
|
|
||||||
}
|
|
||||||
|
|
||||||
if cli.client == nil {
|
|
||||||
cli.client, err = newAPIClientFromEndpoint(cli.dockerEndpoint, cli.configFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cli.initializeFromClient()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,6 +277,9 @@ func newAPIClientFromEndpoint(ep docker.Endpoint, configFile *configfile.ConfigF
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolveDockerEndpoint(s store.Reader, contextName string) (docker.Endpoint, error) {
|
func resolveDockerEndpoint(s store.Reader, contextName string) (docker.Endpoint, error) {
|
||||||
|
if s == nil {
|
||||||
|
return docker.Endpoint{}, fmt.Errorf("no context store initialized")
|
||||||
|
}
|
||||||
ctxMeta, err := s.GetMetadata(contextName)
|
ctxMeta, err := s.GetMetadata(contextName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return docker.Endpoint{}, err
|
return docker.Endpoint{}, err
|
||||||
|
@ -331,7 +329,7 @@ func (cli *DockerCli) getInitTimeout() time.Duration {
|
||||||
|
|
||||||
func (cli *DockerCli) initializeFromClient() {
|
func (cli *DockerCli) initializeFromClient() {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
if !strings.HasPrefix(cli.DockerEndpoint().Host, "ssh://") {
|
if !strings.HasPrefix(cli.dockerEndpoint.Host, "ssh://") {
|
||||||
// @FIXME context.WithTimeout doesn't work with connhelper / ssh connections
|
// @FIXME context.WithTimeout doesn't work with connhelper / ssh connections
|
||||||
// time="2020-04-10T10:16:26Z" level=warning msg="commandConn.CloseWrite: commandconn: failed to wait: signal: killed"
|
// time="2020-04-10T10:16:26Z" level=warning msg="commandConn.CloseWrite: commandconn: failed to wait: signal: killed"
|
||||||
var cancel func()
|
var cancel func()
|
||||||
|
@ -428,9 +426,39 @@ func resolveContextName(opts *cliflags.ClientOptions, config *configfile.ConfigF
|
||||||
|
|
||||||
// DockerEndpoint returns the current docker endpoint
|
// DockerEndpoint returns the current docker endpoint
|
||||||
func (cli *DockerCli) DockerEndpoint() docker.Endpoint {
|
func (cli *DockerCli) DockerEndpoint() docker.Endpoint {
|
||||||
|
if err := cli.initialize(); err != nil {
|
||||||
|
// Note that we're not terminating here, as this function may be used
|
||||||
|
// in cases where we're able to continue.
|
||||||
|
_, _ = fmt.Fprintf(cli.Err(), "%v\n", cli.initErr)
|
||||||
|
}
|
||||||
return cli.dockerEndpoint
|
return cli.dockerEndpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cli *DockerCli) getDockerEndPoint() (ep docker.Endpoint, err error) {
|
||||||
|
cn := cli.CurrentContext()
|
||||||
|
if cn == DefaultContextName {
|
||||||
|
return resolveDefaultDockerEndpoint(cli.options)
|
||||||
|
}
|
||||||
|
return resolveDockerEndpoint(cli.contextStore, cn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cli *DockerCli) initialize() error {
|
||||||
|
cli.init.Do(func() {
|
||||||
|
cli.dockerEndpoint, cli.initErr = cli.getDockerEndPoint()
|
||||||
|
if cli.initErr != nil {
|
||||||
|
cli.initErr = errors.Wrap(cli.initErr, "unable to resolve docker endpoint")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cli.client == nil {
|
||||||
|
if cli.client, cli.initErr = newAPIClientFromEndpoint(cli.dockerEndpoint, cli.configFile); cli.initErr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cli.initializeFromClient()
|
||||||
|
})
|
||||||
|
return cli.initErr
|
||||||
|
}
|
||||||
|
|
||||||
// Apply all the operation on the cli
|
// Apply all the operation on the cli
|
||||||
func (cli *DockerCli) Apply(ops ...DockerCliOption) error {
|
func (cli *DockerCli) Apply(ops ...DockerCliOption) error {
|
||||||
for _, op := range ops {
|
for _, op := range ops {
|
||||||
|
|
|
@ -118,7 +118,7 @@ func (c *fakeClient) NegotiateAPIVersionPing(types.Ping) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInitializeFromClient(t *testing.T) {
|
func TestInitializeFromClient(t *testing.T) {
|
||||||
defaultVersion := "v1.55"
|
const defaultVersion = "v1.55"
|
||||||
|
|
||||||
testcases := []struct {
|
testcases := []struct {
|
||||||
doc string
|
doc string
|
||||||
|
@ -160,7 +160,8 @@ func TestInitializeFromClient(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cli := &DockerCli{client: apiclient}
|
cli := &DockerCli{client: apiclient}
|
||||||
cli.initializeFromClient()
|
err := cli.Initialize(flags.NewClientOptions())
|
||||||
|
assert.NilError(t, err)
|
||||||
assert.DeepEqual(t, cli.ServerInfo(), testcase.expectedServer)
|
assert.DeepEqual(t, cli.ServerInfo(), testcase.expectedServer)
|
||||||
assert.Equal(t, apiclient.negotiated, testcase.negotiated)
|
assert.Equal(t, apiclient.negotiated, testcase.negotiated)
|
||||||
})
|
})
|
||||||
|
@ -202,6 +203,7 @@ func TestInitializeFromClientHangs(t *testing.T) {
|
||||||
cli := &DockerCli{client: apiClient, initTimeout: time.Millisecond}
|
cli := &DockerCli{client: apiClient, initTimeout: time.Millisecond}
|
||||||
err := cli.Initialize(flags.NewClientOptions())
|
err := cli.Initialize(flags.NewClientOptions())
|
||||||
assert.Check(t, err)
|
assert.Check(t, err)
|
||||||
|
cli.CurrentVersion()
|
||||||
close(initializedCh)
|
close(initializedCh)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
@ -50,26 +50,54 @@ func runList(dockerCli command.Cli, opts *listOptions) error {
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
curContext = dockerCli.CurrentContext()
|
curContext = dockerCli.CurrentContext()
|
||||||
|
curFound bool
|
||||||
contexts []*formatter.ClientContext
|
contexts []*formatter.ClientContext
|
||||||
)
|
)
|
||||||
for _, rawMeta := range contextMap {
|
for _, rawMeta := range contextMap {
|
||||||
isCurrent := rawMeta.Name == curContext
|
isCurrent := rawMeta.Name == curContext
|
||||||
|
if isCurrent {
|
||||||
|
curFound = true
|
||||||
|
}
|
||||||
meta, err := command.GetDockerContext(rawMeta)
|
meta, err := command.GetDockerContext(rawMeta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
// Add a stub-entry to the list, including the error-message
|
||||||
|
// indicating that the context couldn't be loaded.
|
||||||
|
contexts = append(contexts, &formatter.ClientContext{
|
||||||
|
Name: rawMeta.Name,
|
||||||
|
Current: isCurrent,
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
var errMsg string
|
||||||
dockerEndpoint, err := docker.EndpointFromContext(rawMeta)
|
dockerEndpoint, err := docker.EndpointFromContext(rawMeta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
errMsg = err.Error()
|
||||||
}
|
}
|
||||||
desc := formatter.ClientContext{
|
desc := formatter.ClientContext{
|
||||||
Name: rawMeta.Name,
|
Name: rawMeta.Name,
|
||||||
Current: isCurrent,
|
Current: isCurrent,
|
||||||
Description: meta.Description,
|
Description: meta.Description,
|
||||||
DockerEndpoint: dockerEndpoint.Host,
|
DockerEndpoint: dockerEndpoint.Host,
|
||||||
|
Error: errMsg,
|
||||||
}
|
}
|
||||||
contexts = append(contexts, &desc)
|
contexts = append(contexts, &desc)
|
||||||
}
|
}
|
||||||
|
if !curFound {
|
||||||
|
// The currently specified context wasn't found. We add a stub-entry
|
||||||
|
// to the list, including the error-message indicating that the context
|
||||||
|
// wasn't found.
|
||||||
|
var errMsg string
|
||||||
|
_, err := dockerCli.ContextStore().GetMetadata(curContext)
|
||||||
|
if err != nil {
|
||||||
|
errMsg = err.Error()
|
||||||
|
}
|
||||||
|
contexts = append(contexts, &formatter.ClientContext{
|
||||||
|
Name: curContext,
|
||||||
|
Current: true,
|
||||||
|
Error: errMsg,
|
||||||
|
})
|
||||||
|
}
|
||||||
sort.Slice(contexts, func(i, j int) bool {
|
sort.Slice(contexts, func(i, j int) bool {
|
||||||
return sortorder.NaturalLess(contexts[i].Name, contexts[j].Name)
|
return sortorder.NaturalLess(contexts[i].Name, contexts[j].Name)
|
||||||
})
|
})
|
||||||
|
|
|
@ -39,3 +39,11 @@ func TestListQuiet(t *testing.T) {
|
||||||
assert.NilError(t, runList(cli, &listOptions{quiet: true}))
|
assert.NilError(t, runList(cli, &listOptions{quiet: true}))
|
||||||
golden.Assert(t, cli.OutBuffer().String(), "quiet-list.golden")
|
golden.Assert(t, cli.OutBuffer().String(), "quiet-list.golden")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestListError(t *testing.T) {
|
||||||
|
cli := makeFakeCli(t)
|
||||||
|
cli.SetCurrentContext("nosuchcontext")
|
||||||
|
cli.OutBuffer().Reset()
|
||||||
|
assert.NilError(t, runList(cli, &listOptions{}))
|
||||||
|
golden.Assert(t, cli.OutBuffer().String(), "list-with-error.golden")
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
NAME DESCRIPTION DOCKER ENDPOINT ERROR
|
||||||
|
default Current DOCKER_HOST based configuration unix:///var/run/docker.sock
|
||||||
|
nosuchcontext * context "nosuchcontext": context not found: …
|
|
@ -1,4 +1,4 @@
|
||||||
NAME DESCRIPTION DOCKER ENDPOINT
|
NAME DESCRIPTION DOCKER ENDPOINT ERROR
|
||||||
current * description of current https://someswarmserver.example.com
|
current * description of current https://someswarmserver.example.com
|
||||||
default Current DOCKER_HOST based configuration unix:///var/run/docker.sock
|
default Current DOCKER_HOST based configuration unix:///var/run/docker.sock
|
||||||
other description of other https://someswarmserver.example.com
|
other description of other https://someswarmserver.example.com
|
||||||
|
|
|
@ -1,20 +1,22 @@
|
||||||
package formatter
|
package formatter
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// ClientContextTableFormat is the default client context format
|
// ClientContextTableFormat is the default client context format.
|
||||||
ClientContextTableFormat = "table {{.Name}}{{if .Current}} *{{end}}\t{{.Description}}\t{{.DockerEndpoint}}"
|
ClientContextTableFormat = "table {{.Name}}{{if .Current}} *{{end}}\t{{.Description}}\t{{.DockerEndpoint}}\t{{.Error}}"
|
||||||
|
|
||||||
dockerEndpointHeader = "DOCKER ENDPOINT"
|
dockerEndpointHeader = "DOCKER ENDPOINT"
|
||||||
quietContextFormat = "{{.Name}}"
|
quietContextFormat = "{{.Name}}"
|
||||||
|
|
||||||
|
maxErrLength = 45
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewClientContextFormat returns a Format for rendering using a Context
|
// NewClientContextFormat returns a Format for rendering using a Context
|
||||||
func NewClientContextFormat(source string, quiet bool) Format {
|
func NewClientContextFormat(source string, quiet bool) Format {
|
||||||
if quiet {
|
if quiet {
|
||||||
return Format(quietContextFormat)
|
return quietContextFormat
|
||||||
}
|
}
|
||||||
if source == TableFormatKey {
|
if source == TableFormatKey {
|
||||||
return Format(ClientContextTableFormat)
|
return ClientContextTableFormat
|
||||||
}
|
}
|
||||||
return Format(source)
|
return Format(source)
|
||||||
}
|
}
|
||||||
|
@ -25,6 +27,7 @@ type ClientContext struct {
|
||||||
Description string
|
Description string
|
||||||
DockerEndpoint string
|
DockerEndpoint string
|
||||||
Current bool
|
Current bool
|
||||||
|
Error string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClientContextWrite writes formatted contexts using the Context
|
// ClientContextWrite writes formatted contexts using the Context
|
||||||
|
@ -51,6 +54,7 @@ func newClientContextContext() *clientContextContext {
|
||||||
"Name": NameHeader,
|
"Name": NameHeader,
|
||||||
"Description": DescriptionHeader,
|
"Description": DescriptionHeader,
|
||||||
"DockerEndpoint": dockerEndpointHeader,
|
"DockerEndpoint": dockerEndpointHeader,
|
||||||
|
"Error": ErrorHeader,
|
||||||
}
|
}
|
||||||
return &ctx
|
return &ctx
|
||||||
}
|
}
|
||||||
|
@ -75,6 +79,12 @@ func (c *clientContextContext) DockerEndpoint() string {
|
||||||
return c.c.DockerEndpoint
|
return c.c.DockerEndpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Error returns the truncated error (if any) that occurred when loading the context.
|
||||||
|
func (c *clientContextContext) Error() string {
|
||||||
|
// TODO(thaJeztah) add "--no-trunc" option to context ls and set default to 30 cols to match "docker service ps"
|
||||||
|
return Ellipsis(c.c.Error, maxErrLength)
|
||||||
|
}
|
||||||
|
|
||||||
// KubernetesEndpoint returns the kubernetes endpoint.
|
// KubernetesEndpoint returns the kubernetes endpoint.
|
||||||
//
|
//
|
||||||
// Deprecated: support for kubernetes endpoints in contexts has been removed, and this formatting option will always be empty.
|
// Deprecated: support for kubernetes endpoints in contexts has been removed, and this formatting option will always be empty.
|
||||||
|
|
|
@ -16,6 +16,7 @@ const (
|
||||||
StatusHeader = "STATUS"
|
StatusHeader = "STATUS"
|
||||||
PortsHeader = "PORTS"
|
PortsHeader = "PORTS"
|
||||||
ImageHeader = "IMAGE"
|
ImageHeader = "IMAGE"
|
||||||
|
ErrorHeader = "ERROR"
|
||||||
ContainerIDHeader = "CONTAINER ID"
|
ContainerIDHeader = "CONTAINER ID"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@ const (
|
||||||
taskIDHeader = "ID"
|
taskIDHeader = "ID"
|
||||||
desiredStateHeader = "DESIRED STATE"
|
desiredStateHeader = "DESIRED STATE"
|
||||||
currentStateHeader = "CURRENT STATE"
|
currentStateHeader = "CURRENT STATE"
|
||||||
errorHeader = "ERROR"
|
|
||||||
|
|
||||||
maxErrLength = 30
|
maxErrLength = 30
|
||||||
)
|
)
|
||||||
|
@ -61,7 +60,7 @@ func FormatWrite(ctx formatter.Context, tasks []swarm.Task, names map[string]str
|
||||||
"Node": nodeHeader,
|
"Node": nodeHeader,
|
||||||
"DesiredState": desiredStateHeader,
|
"DesiredState": desiredStateHeader,
|
||||||
"CurrentState": currentStateHeader,
|
"CurrentState": currentStateHeader,
|
||||||
"Error": errorHeader,
|
"Error": formatter.ErrorHeader,
|
||||||
"Ports": formatter.PortsHeader,
|
"Ports": formatter.PortsHeader,
|
||||||
}
|
}
|
||||||
return ctx.Write(&taskCtx, render)
|
return ctx.Write(&taskCtx, render)
|
||||||
|
@ -124,11 +123,11 @@ func (c *taskContext) CurrentState() string {
|
||||||
func (c *taskContext) Error() string {
|
func (c *taskContext) Error() string {
|
||||||
// Trim and quote the error message.
|
// Trim and quote the error message.
|
||||||
taskErr := c.task.Status.Err
|
taskErr := c.task.Status.Err
|
||||||
if c.trunc && len(taskErr) > maxErrLength {
|
if c.trunc {
|
||||||
taskErr = fmt.Sprintf("%s…", taskErr[:maxErrLength-1])
|
taskErr = formatter.Ellipsis(taskErr, maxErrLength)
|
||||||
}
|
}
|
||||||
if len(taskErr) > 0 {
|
if len(taskErr) > 0 {
|
||||||
taskErr = fmt.Sprintf("\"%s\"", taskErr)
|
taskErr = fmt.Sprintf(`"%s"`, taskErr)
|
||||||
}
|
}
|
||||||
return taskErr
|
return taskErr
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ func parseTypedOrMap(payload []byte, getter TypeGetter) (interface{}, error) {
|
||||||
func (s *metadataStore) get(name string) (Metadata, error) {
|
func (s *metadataStore) get(name string) (Metadata, error) {
|
||||||
m, err := s.getByID(contextdirOf(name))
|
m, err := s.getByID(contextdirOf(name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return m, errors.Wrapf(err, "load context %q", name)
|
return m, errors.Wrapf(err, "context %q", name)
|
||||||
}
|
}
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ func (s *metadataStore) getByID(id contextdir) (Metadata, error) {
|
||||||
bytes, err := os.ReadFile(filepath.Join(s.contextDir(id), metaFile))
|
bytes, err := os.ReadFile(filepath.Join(s.contextDir(id), metaFile))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
return Metadata{}, errdefs.NotFound(errors.Wrap(err, "context does not exist"))
|
return Metadata{}, errdefs.NotFound(errors.Wrap(err, "context not found"))
|
||||||
}
|
}
|
||||||
return Metadata{}, err
|
return Metadata{}, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
NAME DESCRIPTION DOCKER ENDPOINT
|
NAME DESCRIPTION DOCKER ENDPOINT ERROR
|
||||||
default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock
|
default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock
|
||||||
remote my remote cluster ssh://someserver
|
remote my remote cluster ssh://someserver
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
NAME DESCRIPTION DOCKER ENDPOINT
|
NAME DESCRIPTION DOCKER ENDPOINT ERROR
|
||||||
default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock
|
default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock
|
||||||
test unix:///var/run/docker.sock
|
test unix:///var/run/docker.sock
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
NAME DESCRIPTION DOCKER ENDPOINT
|
NAME DESCRIPTION DOCKER ENDPOINT ERROR
|
||||||
default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock
|
default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock
|
||||||
remote my remote cluster ssh://someserver
|
remote my remote cluster ssh://someserver
|
||||||
|
|
Loading…
Reference in New Issue