mirror of https://github.com/docker/cli.git
Add context store config options and expose context commands
This will allow plugins to have custom typed endpoints, as well as create/remove/update contexts with the exact same results as the main CLI (thinking of things like `docker ee login https://my-ucp-server --context ucp-prod)` Signed-off-by: Simon Ferquel <simon.ferquel@docker.com>
This commit is contained in:
parent
cf6c238660
commit
3126920af1
|
@ -81,14 +81,9 @@ type DockerCli struct {
|
||||||
contextStore store.Store
|
contextStore store.Store
|
||||||
currentContext string
|
currentContext string
|
||||||
dockerEndpoint docker.Endpoint
|
dockerEndpoint docker.Endpoint
|
||||||
|
contextStoreConfig store.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
var storeConfig = store.NewConfig(
|
|
||||||
func() interface{} { return &DockerContext{} },
|
|
||||||
store.EndpointTypeGetter(docker.DockerEndpoint, func() interface{} { return &docker.EndpointMeta{} }),
|
|
||||||
store.EndpointTypeGetter(kubcontext.KubernetesEndpoint, func() interface{} { return &kubcontext.EndpointMeta{} }),
|
|
||||||
)
|
|
||||||
|
|
||||||
// DefaultVersion returns api.defaultVersion or DOCKER_API_VERSION if specified.
|
// DefaultVersion returns api.defaultVersion or DOCKER_API_VERSION if specified.
|
||||||
func (cli *DockerCli) DefaultVersion() string {
|
func (cli *DockerCli) DefaultVersion() string {
|
||||||
return cli.clientInfo.DefaultVersion
|
return cli.clientInfo.DefaultVersion
|
||||||
|
@ -184,7 +179,7 @@ func (cli *DockerCli) RegistryClient(allowInsecure bool) registryclient.Registry
|
||||||
func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions) error {
|
func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions) error {
|
||||||
cli.configFile = cliconfig.LoadDefaultConfigFile(cli.err)
|
cli.configFile = cliconfig.LoadDefaultConfigFile(cli.err)
|
||||||
var err error
|
var err error
|
||||||
cli.contextStore = store.New(cliconfig.ContextStoreDir(), storeConfig)
|
cli.contextStore = store.New(cliconfig.ContextStoreDir(), cli.contextStoreConfig)
|
||||||
cli.currentContext, err = resolveContextName(opts.Common, cli.configFile, cli.contextStore)
|
cli.currentContext, err = resolveContextName(opts.Common, cli.configFile, cli.contextStore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -226,7 +221,7 @@ func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions) error {
|
||||||
|
|
||||||
// NewAPIClientFromFlags creates a new APIClient from command line flags
|
// NewAPIClientFromFlags creates a new APIClient from command line flags
|
||||||
func NewAPIClientFromFlags(opts *cliflags.CommonOptions, configFile *configfile.ConfigFile) (client.APIClient, error) {
|
func NewAPIClientFromFlags(opts *cliflags.CommonOptions, configFile *configfile.ConfigFile) (client.APIClient, error) {
|
||||||
store := store.New(cliconfig.ContextStoreDir(), storeConfig)
|
store := store.New(cliconfig.ContextStoreDir(), defaultContextStoreConfig())
|
||||||
contextName, err := resolveContextName(opts, configFile, store)
|
contextName, err := resolveContextName(opts, configFile, store)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -372,7 +367,7 @@ func (cli *DockerCli) StackOrchestrator(flagValue string) (Orchestrator, error)
|
||||||
if currentContext != "" {
|
if currentContext != "" {
|
||||||
contextstore := cli.contextStore
|
contextstore := cli.contextStore
|
||||||
if contextstore == nil {
|
if contextstore == nil {
|
||||||
contextstore = store.New(cliconfig.ContextStoreDir(), storeConfig)
|
contextstore = store.New(cliconfig.ContextStoreDir(), cli.contextStoreConfig)
|
||||||
}
|
}
|
||||||
ctxRaw, err := contextstore.GetContextMetadata(currentContext)
|
ctxRaw, err := contextstore.GetContextMetadata(currentContext)
|
||||||
if store.IsErrContextDoesNotExist(err) {
|
if store.IsErrContextDoesNotExist(err) {
|
||||||
|
@ -430,6 +425,7 @@ func NewDockerCli(ops ...DockerCliOption) (*DockerCli, error) {
|
||||||
WithContentTrustFromEnv(),
|
WithContentTrustFromEnv(),
|
||||||
WithContainerizedClient(containerizedengine.NewClient),
|
WithContainerizedClient(containerizedengine.NewClient),
|
||||||
}
|
}
|
||||||
|
cli.contextStoreConfig = defaultContextStoreConfig()
|
||||||
ops = append(defaultOps, ops...)
|
ops = append(defaultOps, ops...)
|
||||||
if err := cli.Apply(ops...); err != nil {
|
if err := cli.Apply(ops...); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -501,3 +497,11 @@ func resolveContextName(opts *cliflags.CommonOptions, config *configfile.ConfigF
|
||||||
}
|
}
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func defaultContextStoreConfig() store.Config {
|
||||||
|
return store.NewConfig(
|
||||||
|
func() interface{} { return &DockerContext{} },
|
||||||
|
store.EndpointTypeGetter(docker.DockerEndpoint, func() interface{} { return &docker.EndpointMeta{} }),
|
||||||
|
store.EndpointTypeGetter(kubcontext.KubernetesEndpoint, func() interface{} { return &kubcontext.EndpointMeta{} }),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/docker/cli/cli/context/docker"
|
||||||
|
"github.com/docker/cli/cli/context/kubernetes"
|
||||||
|
"github.com/docker/cli/cli/context/store"
|
||||||
"github.com/docker/cli/cli/streams"
|
"github.com/docker/cli/cli/streams"
|
||||||
clitypes "github.com/docker/cli/types"
|
clitypes "github.com/docker/cli/types"
|
||||||
"github.com/docker/docker/pkg/term"
|
"github.com/docker/docker/pkg/term"
|
||||||
|
@ -87,3 +91,16 @@ func WithContainerizedClient(containerizedFn func(string) (clitypes.Containerize
|
||||||
return nil
|
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 {
|
||||||
|
return func(cli *DockerCli) error {
|
||||||
|
switch endpointName {
|
||||||
|
case docker.DockerEndpoint, kubernetes.KubernetesEndpoint:
|
||||||
|
return fmt.Errorf("cannot change %q endpoint type", endpointName)
|
||||||
|
}
|
||||||
|
cli.contextStoreConfig.SetEndpoint(endpointName, endpointType)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -14,12 +14,13 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
type createOptions struct {
|
// CreateOptions are the options used for creating a context
|
||||||
name string
|
type CreateOptions struct {
|
||||||
description string
|
Name string
|
||||||
defaultStackOrchestrator string
|
Description string
|
||||||
docker map[string]string
|
DefaultStackOrchestrator string
|
||||||
kubernetes map[string]string
|
Docker map[string]string
|
||||||
|
Kubernetes map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func longCreateDescription() string {
|
func longCreateDescription() string {
|
||||||
|
@ -43,52 +44,53 @@ func longCreateDescription() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCreateCommand(dockerCli command.Cli) *cobra.Command {
|
func newCreateCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
opts := &createOptions{}
|
opts := &CreateOptions{}
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "create [OPTIONS] CONTEXT",
|
Use: "create [OPTIONS] CONTEXT",
|
||||||
Short: "Create a context",
|
Short: "Create a context",
|
||||||
Args: cli.ExactArgs(1),
|
Args: cli.ExactArgs(1),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
opts.name = args[0]
|
opts.Name = args[0]
|
||||||
return runCreate(dockerCli, opts)
|
return RunCreate(dockerCli, opts)
|
||||||
},
|
},
|
||||||
Long: longCreateDescription(),
|
Long: longCreateDescription(),
|
||||||
}
|
}
|
||||||
flags := cmd.Flags()
|
flags := cmd.Flags()
|
||||||
flags.StringVar(&opts.description, "description", "", "Description of the context")
|
flags.StringVar(&opts.Description, "description", "", "Description of the context")
|
||||||
flags.StringVar(
|
flags.StringVar(
|
||||||
&opts.defaultStackOrchestrator,
|
&opts.DefaultStackOrchestrator,
|
||||||
"default-stack-orchestrator", "",
|
"default-stack-orchestrator", "",
|
||||||
"Default orchestrator for stack operations to use with this context (swarm|kubernetes|all)")
|
"Default orchestrator for stack operations to use with this context (swarm|kubernetes|all)")
|
||||||
flags.StringToStringVar(&opts.docker, "docker", nil, "set the docker endpoint")
|
flags.StringToStringVar(&opts.Docker, "docker", nil, "set the docker endpoint")
|
||||||
flags.StringToStringVar(&opts.kubernetes, "kubernetes", nil, "set the kubernetes endpoint")
|
flags.StringToStringVar(&opts.Kubernetes, "kubernetes", nil, "set the kubernetes endpoint")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCreate(cli command.Cli, o *createOptions) error {
|
// RunCreate creates a Docker context
|
||||||
|
func RunCreate(cli command.Cli, o *CreateOptions) error {
|
||||||
s := cli.ContextStore()
|
s := cli.ContextStore()
|
||||||
if err := checkContextNameForCreation(s, o.name); err != nil {
|
if err := checkContextNameForCreation(s, o.Name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
stackOrchestrator, err := command.NormalizeOrchestrator(o.defaultStackOrchestrator)
|
stackOrchestrator, err := command.NormalizeOrchestrator(o.DefaultStackOrchestrator)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "unable to parse default-stack-orchestrator")
|
return errors.Wrap(err, "unable to parse default-stack-orchestrator")
|
||||||
}
|
}
|
||||||
contextMetadata := store.ContextMetadata{
|
contextMetadata := store.ContextMetadata{
|
||||||
Endpoints: make(map[string]interface{}),
|
Endpoints: make(map[string]interface{}),
|
||||||
Metadata: command.DockerContext{
|
Metadata: command.DockerContext{
|
||||||
Description: o.description,
|
Description: o.Description,
|
||||||
StackOrchestrator: stackOrchestrator,
|
StackOrchestrator: stackOrchestrator,
|
||||||
},
|
},
|
||||||
Name: o.name,
|
Name: o.Name,
|
||||||
}
|
}
|
||||||
if o.docker == nil {
|
if o.Docker == nil {
|
||||||
return errors.New("docker endpoint configuration is required")
|
return errors.New("docker endpoint configuration is required")
|
||||||
}
|
}
|
||||||
contextTLSData := store.ContextTLSData{
|
contextTLSData := store.ContextTLSData{
|
||||||
Endpoints: make(map[string]store.EndpointTLSData),
|
Endpoints: make(map[string]store.EndpointTLSData),
|
||||||
}
|
}
|
||||||
dockerEP, dockerTLS, err := getDockerEndpointMetadataAndTLS(cli, o.docker)
|
dockerEP, dockerTLS, err := getDockerEndpointMetadataAndTLS(cli, o.Docker)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "unable to create docker endpoint config")
|
return errors.Wrap(err, "unable to create docker endpoint config")
|
||||||
}
|
}
|
||||||
|
@ -96,8 +98,8 @@ func runCreate(cli command.Cli, o *createOptions) error {
|
||||||
if dockerTLS != nil {
|
if dockerTLS != nil {
|
||||||
contextTLSData.Endpoints[docker.DockerEndpoint] = *dockerTLS
|
contextTLSData.Endpoints[docker.DockerEndpoint] = *dockerTLS
|
||||||
}
|
}
|
||||||
if o.kubernetes != nil {
|
if o.Kubernetes != nil {
|
||||||
kubernetesEP, kubernetesTLS, err := getKubernetesEndpointMetadataAndTLS(cli, o.kubernetes)
|
kubernetesEP, kubernetesTLS, err := getKubernetesEndpointMetadataAndTLS(cli, o.Kubernetes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "unable to create kubernetes endpoint config")
|
return errors.Wrap(err, "unable to create kubernetes endpoint config")
|
||||||
}
|
}
|
||||||
|
@ -117,11 +119,11 @@ func runCreate(cli command.Cli, o *createOptions) error {
|
||||||
if err := s.CreateOrUpdateContext(contextMetadata); err != nil {
|
if err := s.CreateOrUpdateContext(contextMetadata); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := s.ResetContextTLSMaterial(o.name, &contextTLSData); err != nil {
|
if err := s.ResetContextTLSMaterial(o.Name, &contextTLSData); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Fprintln(cli.Out(), o.name)
|
fmt.Fprintln(cli.Out(), o.Name)
|
||||||
fmt.Fprintf(cli.Err(), "Successfully created context %q\n", o.name)
|
fmt.Fprintf(cli.Err(), "Successfully created context %q\n", o.Name)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,68 +46,68 @@ func TestCreateInvalids(t *testing.T) {
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
assert.NilError(t, cli.ContextStore().CreateOrUpdateContext(store.ContextMetadata{Name: "existing-context"}))
|
assert.NilError(t, cli.ContextStore().CreateOrUpdateContext(store.ContextMetadata{Name: "existing-context"}))
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
options createOptions
|
options CreateOptions
|
||||||
expecterErr string
|
expecterErr string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
expecterErr: `context name cannot be empty`,
|
expecterErr: `context name cannot be empty`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
options: createOptions{
|
options: CreateOptions{
|
||||||
name: " ",
|
Name: " ",
|
||||||
},
|
},
|
||||||
expecterErr: `context name " " is invalid`,
|
expecterErr: `context name " " is invalid`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
options: createOptions{
|
options: CreateOptions{
|
||||||
name: "existing-context",
|
Name: "existing-context",
|
||||||
},
|
},
|
||||||
expecterErr: `context "existing-context" already exists`,
|
expecterErr: `context "existing-context" already exists`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
options: createOptions{
|
options: CreateOptions{
|
||||||
name: "invalid-docker-host",
|
Name: "invalid-docker-host",
|
||||||
docker: map[string]string{
|
Docker: map[string]string{
|
||||||
keyHost: "some///invalid/host",
|
keyHost: "some///invalid/host",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expecterErr: `unable to parse docker host`,
|
expecterErr: `unable to parse docker host`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
options: createOptions{
|
options: CreateOptions{
|
||||||
name: "invalid-orchestrator",
|
Name: "invalid-orchestrator",
|
||||||
defaultStackOrchestrator: "invalid",
|
DefaultStackOrchestrator: "invalid",
|
||||||
},
|
},
|
||||||
expecterErr: `specified orchestrator "invalid" is invalid, please use either kubernetes, swarm or all`,
|
expecterErr: `specified orchestrator "invalid" is invalid, please use either kubernetes, swarm or all`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
options: createOptions{
|
options: CreateOptions{
|
||||||
name: "orchestrator-swarm-no-endpoint",
|
Name: "orchestrator-swarm-no-endpoint",
|
||||||
defaultStackOrchestrator: "swarm",
|
DefaultStackOrchestrator: "swarm",
|
||||||
},
|
},
|
||||||
expecterErr: `docker endpoint configuration is required`,
|
expecterErr: `docker endpoint configuration is required`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
options: createOptions{
|
options: CreateOptions{
|
||||||
name: "orchestrator-kubernetes-no-endpoint",
|
Name: "orchestrator-kubernetes-no-endpoint",
|
||||||
defaultStackOrchestrator: "kubernetes",
|
DefaultStackOrchestrator: "kubernetes",
|
||||||
docker: map[string]string{},
|
Docker: map[string]string{},
|
||||||
},
|
},
|
||||||
expecterErr: `cannot specify orchestrator "kubernetes" without configuring a Kubernetes endpoint`,
|
expecterErr: `cannot specify orchestrator "kubernetes" without configuring a Kubernetes endpoint`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
options: createOptions{
|
options: CreateOptions{
|
||||||
name: "orchestrator-all-no-endpoint",
|
Name: "orchestrator-all-no-endpoint",
|
||||||
defaultStackOrchestrator: "all",
|
DefaultStackOrchestrator: "all",
|
||||||
docker: map[string]string{},
|
Docker: map[string]string{},
|
||||||
},
|
},
|
||||||
expecterErr: `cannot specify orchestrator "all" without configuring a Kubernetes endpoint`,
|
expecterErr: `cannot specify orchestrator "all" without configuring a Kubernetes endpoint`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
tc := tc
|
tc := tc
|
||||||
t.Run(tc.options.name, func(t *testing.T) {
|
t.Run(tc.options.Name, func(t *testing.T) {
|
||||||
err := runCreate(cli, &tc.options)
|
err := RunCreate(cli, &tc.options)
|
||||||
assert.ErrorContains(t, err, tc.expecterErr)
|
assert.ErrorContains(t, err, tc.expecterErr)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -117,10 +117,10 @@ func TestCreateOrchestratorSwarm(t *testing.T) {
|
||||||
cli, cleanup := makeFakeCli(t)
|
cli, cleanup := makeFakeCli(t)
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|
||||||
err := runCreate(cli, &createOptions{
|
err := RunCreate(cli, &CreateOptions{
|
||||||
name: "test",
|
Name: "test",
|
||||||
defaultStackOrchestrator: "swarm",
|
DefaultStackOrchestrator: "swarm",
|
||||||
docker: map[string]string{},
|
Docker: map[string]string{},
|
||||||
})
|
})
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.Equal(t, "test\n", cli.OutBuffer().String())
|
assert.Equal(t, "test\n", cli.OutBuffer().String())
|
||||||
|
@ -131,9 +131,9 @@ func TestCreateOrchestratorEmpty(t *testing.T) {
|
||||||
cli, cleanup := makeFakeCli(t)
|
cli, cleanup := makeFakeCli(t)
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|
||||||
err := runCreate(cli, &createOptions{
|
err := RunCreate(cli, &CreateOptions{
|
||||||
name: "test",
|
Name: "test",
|
||||||
docker: map[string]string{},
|
Docker: map[string]string{},
|
||||||
})
|
})
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
}
|
}
|
||||||
|
@ -156,13 +156,13 @@ func createTestContextWithKube(t *testing.T, cli command.Cli) {
|
||||||
revert := env.Patch(t, "KUBECONFIG", "./testdata/test-kubeconfig")
|
revert := env.Patch(t, "KUBECONFIG", "./testdata/test-kubeconfig")
|
||||||
defer revert()
|
defer revert()
|
||||||
|
|
||||||
err := runCreate(cli, &createOptions{
|
err := RunCreate(cli, &CreateOptions{
|
||||||
name: "test",
|
Name: "test",
|
||||||
defaultStackOrchestrator: "all",
|
DefaultStackOrchestrator: "all",
|
||||||
kubernetes: map[string]string{
|
Kubernetes: map[string]string{
|
||||||
keyFromCurrent: "true",
|
keyFromCurrent: "true",
|
||||||
},
|
},
|
||||||
docker: map[string]string{},
|
Docker: map[string]string{},
|
||||||
})
|
})
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,14 +21,14 @@ func TestExportImportWithFile(t *testing.T) {
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
createTestContextWithKube(t, cli)
|
createTestContextWithKube(t, cli)
|
||||||
cli.ErrBuffer().Reset()
|
cli.ErrBuffer().Reset()
|
||||||
assert.NilError(t, runExport(cli, &exportOptions{
|
assert.NilError(t, RunExport(cli, &ExportOptions{
|
||||||
contextName: "test",
|
ContextName: "test",
|
||||||
dest: contextFile,
|
Dest: contextFile,
|
||||||
}))
|
}))
|
||||||
assert.Equal(t, cli.ErrBuffer().String(), fmt.Sprintf("Written file %q\n", contextFile))
|
assert.Equal(t, cli.ErrBuffer().String(), fmt.Sprintf("Written file %q\n", contextFile))
|
||||||
cli.OutBuffer().Reset()
|
cli.OutBuffer().Reset()
|
||||||
cli.ErrBuffer().Reset()
|
cli.ErrBuffer().Reset()
|
||||||
assert.NilError(t, runImport(cli, "test2", contextFile))
|
assert.NilError(t, RunImport(cli, "test2", contextFile))
|
||||||
context1, err := cli.ContextStore().GetContextMetadata("test")
|
context1, err := cli.ContextStore().GetContextMetadata("test")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
context2, err := cli.ContextStore().GetContextMetadata("test2")
|
context2, err := cli.ContextStore().GetContextMetadata("test2")
|
||||||
|
@ -48,15 +48,15 @@ func TestExportImportPipe(t *testing.T) {
|
||||||
createTestContextWithKube(t, cli)
|
createTestContextWithKube(t, cli)
|
||||||
cli.ErrBuffer().Reset()
|
cli.ErrBuffer().Reset()
|
||||||
cli.OutBuffer().Reset()
|
cli.OutBuffer().Reset()
|
||||||
assert.NilError(t, runExport(cli, &exportOptions{
|
assert.NilError(t, RunExport(cli, &ExportOptions{
|
||||||
contextName: "test",
|
ContextName: "test",
|
||||||
dest: "-",
|
Dest: "-",
|
||||||
}))
|
}))
|
||||||
assert.Equal(t, cli.ErrBuffer().String(), "")
|
assert.Equal(t, cli.ErrBuffer().String(), "")
|
||||||
cli.SetIn(streams.NewIn(ioutil.NopCloser(bytes.NewBuffer(cli.OutBuffer().Bytes()))))
|
cli.SetIn(streams.NewIn(ioutil.NopCloser(bytes.NewBuffer(cli.OutBuffer().Bytes()))))
|
||||||
cli.OutBuffer().Reset()
|
cli.OutBuffer().Reset()
|
||||||
cli.ErrBuffer().Reset()
|
cli.ErrBuffer().Reset()
|
||||||
assert.NilError(t, runImport(cli, "test2", "-"))
|
assert.NilError(t, RunImport(cli, "test2", "-"))
|
||||||
context1, err := cli.ContextStore().GetContextMetadata("test")
|
context1, err := cli.ContextStore().GetContextMetadata("test")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
context2, err := cli.ContextStore().GetContextMetadata("test2")
|
context2, err := cli.ContextStore().GetContextMetadata("test2")
|
||||||
|
@ -79,18 +79,18 @@ func TestExportKubeconfig(t *testing.T) {
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
createTestContextWithKube(t, cli)
|
createTestContextWithKube(t, cli)
|
||||||
cli.ErrBuffer().Reset()
|
cli.ErrBuffer().Reset()
|
||||||
assert.NilError(t, runExport(cli, &exportOptions{
|
assert.NilError(t, RunExport(cli, &ExportOptions{
|
||||||
contextName: "test",
|
ContextName: "test",
|
||||||
dest: contextFile,
|
Dest: contextFile,
|
||||||
kubeconfig: true,
|
Kubeconfig: true,
|
||||||
}))
|
}))
|
||||||
assert.Equal(t, cli.ErrBuffer().String(), fmt.Sprintf("Written file %q\n", contextFile))
|
assert.Equal(t, cli.ErrBuffer().String(), fmt.Sprintf("Written file %q\n", contextFile))
|
||||||
assert.NilError(t, runCreate(cli, &createOptions{
|
assert.NilError(t, RunCreate(cli, &CreateOptions{
|
||||||
name: "test2",
|
Name: "test2",
|
||||||
kubernetes: map[string]string{
|
Kubernetes: map[string]string{
|
||||||
keyKubeconfig: contextFile,
|
keyKubeconfig: contextFile,
|
||||||
},
|
},
|
||||||
docker: map[string]string{},
|
Docker: map[string]string{},
|
||||||
}))
|
}))
|
||||||
validateTestKubeEndpoint(t, cli.ContextStore(), "test2")
|
validateTestKubeEndpoint(t, cli.ContextStore(), "test2")
|
||||||
}
|
}
|
||||||
|
@ -105,6 +105,6 @@ func TestExportExistingFile(t *testing.T) {
|
||||||
createTestContextWithKube(t, cli)
|
createTestContextWithKube(t, cli)
|
||||||
cli.ErrBuffer().Reset()
|
cli.ErrBuffer().Reset()
|
||||||
assert.NilError(t, ioutil.WriteFile(contextFile, []byte{}, 0644))
|
assert.NilError(t, ioutil.WriteFile(contextFile, []byte{}, 0644))
|
||||||
err = runExport(cli, &exportOptions{contextName: "test", dest: contextFile})
|
err = RunExport(cli, &ExportOptions{ContextName: "test", Dest: contextFile})
|
||||||
assert.Assert(t, os.IsExist(err))
|
assert.Assert(t, os.IsExist(err))
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,36 +15,37 @@ import (
|
||||||
"k8s.io/client-go/tools/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
type exportOptions struct {
|
// ExportOptions are the options used for exporting a context
|
||||||
kubeconfig bool
|
type ExportOptions struct {
|
||||||
contextName string
|
Kubeconfig bool
|
||||||
dest string
|
ContextName string
|
||||||
|
Dest string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newExportCommand(dockerCli command.Cli) *cobra.Command {
|
func newExportCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
opts := &exportOptions{}
|
opts := &ExportOptions{}
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "export [OPTIONS] CONTEXT [FILE|-]",
|
Use: "export [OPTIONS] CONTEXT [FILE|-]",
|
||||||
Short: "Export a context to a tar or kubeconfig file",
|
Short: "Export a context to a tar or kubeconfig file",
|
||||||
Args: cli.RequiresRangeArgs(1, 2),
|
Args: cli.RequiresRangeArgs(1, 2),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
opts.contextName = args[0]
|
opts.ContextName = args[0]
|
||||||
if len(args) == 2 {
|
if len(args) == 2 {
|
||||||
opts.dest = args[1]
|
opts.Dest = args[1]
|
||||||
} else {
|
} else {
|
||||||
opts.dest = opts.contextName
|
opts.Dest = opts.ContextName
|
||||||
if opts.kubeconfig {
|
if opts.Kubeconfig {
|
||||||
opts.dest += ".kubeconfig"
|
opts.Dest += ".kubeconfig"
|
||||||
} else {
|
} else {
|
||||||
opts.dest += ".dockercontext"
|
opts.Dest += ".dockercontext"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return runExport(dockerCli, opts)
|
return RunExport(dockerCli, opts)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
flags := cmd.Flags()
|
flags := cmd.Flags()
|
||||||
flags.BoolVar(&opts.kubeconfig, "kubeconfig", false, "Export as a kubeconfig file")
|
flags.BoolVar(&opts.Kubeconfig, "kubeconfig", false, "Export as a kubeconfig file")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,24 +75,25 @@ func writeTo(dockerCli command.Cli, reader io.Reader, dest string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runExport(dockerCli command.Cli, opts *exportOptions) error {
|
// RunExport exports a Docker context
|
||||||
if err := validateContextName(opts.contextName); err != nil {
|
func RunExport(dockerCli command.Cli, opts *ExportOptions) error {
|
||||||
|
if err := validateContextName(opts.ContextName); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ctxMeta, err := dockerCli.ContextStore().GetContextMetadata(opts.contextName)
|
ctxMeta, err := dockerCli.ContextStore().GetContextMetadata(opts.ContextName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !opts.kubeconfig {
|
if !opts.Kubeconfig {
|
||||||
reader := store.Export(opts.contextName, dockerCli.ContextStore())
|
reader := store.Export(opts.ContextName, dockerCli.ContextStore())
|
||||||
defer reader.Close()
|
defer reader.Close()
|
||||||
return writeTo(dockerCli, reader, opts.dest)
|
return writeTo(dockerCli, reader, opts.Dest)
|
||||||
}
|
}
|
||||||
kubernetesEndpointMeta := kubernetes.EndpointFromContext(ctxMeta)
|
kubernetesEndpointMeta := kubernetes.EndpointFromContext(ctxMeta)
|
||||||
if kubernetesEndpointMeta == nil {
|
if kubernetesEndpointMeta == nil {
|
||||||
return fmt.Errorf("context %q has no kubernetes endpoint", opts.contextName)
|
return fmt.Errorf("context %q has no kubernetes endpoint", opts.ContextName)
|
||||||
}
|
}
|
||||||
kubernetesEndpoint, err := kubernetesEndpointMeta.WithTLSData(dockerCli.ContextStore(), opts.contextName)
|
kubernetesEndpoint, err := kubernetesEndpointMeta.WithTLSData(dockerCli.ContextStore(), opts.ContextName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -104,5 +106,5 @@ func runExport(dockerCli command.Cli, opts *exportOptions) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return writeTo(dockerCli, bytes.NewBuffer(data), opts.dest)
|
return writeTo(dockerCli, bytes.NewBuffer(data), opts.Dest)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,13 +17,14 @@ func newImportCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
Short: "Import a context from a tar file",
|
Short: "Import a context from a tar file",
|
||||||
Args: cli.ExactArgs(2),
|
Args: cli.ExactArgs(2),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
return runImport(dockerCli, args[0], args[1])
|
return RunImport(dockerCli, args[0], args[1])
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runImport(dockerCli command.Cli, name string, source string) error {
|
// RunImport imports a Docker context
|
||||||
|
func RunImport(dockerCli command.Cli, name string, source string) error {
|
||||||
if err := checkContextNameForCreation(dockerCli.ContextStore(), name); err != nil {
|
if err := checkContextNameForCreation(dockerCli.ContextStore(), name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,12 +14,12 @@ func createTestContextWithKubeAndSwarm(t *testing.T, cli command.Cli, name strin
|
||||||
revert := env.Patch(t, "KUBECONFIG", "./testdata/test-kubeconfig")
|
revert := env.Patch(t, "KUBECONFIG", "./testdata/test-kubeconfig")
|
||||||
defer revert()
|
defer revert()
|
||||||
|
|
||||||
err := runCreate(cli, &createOptions{
|
err := RunCreate(cli, &CreateOptions{
|
||||||
name: name,
|
Name: name,
|
||||||
defaultStackOrchestrator: orchestrator,
|
DefaultStackOrchestrator: orchestrator,
|
||||||
description: "description of " + name,
|
Description: "description of " + name,
|
||||||
kubernetes: map[string]string{keyFromCurrent: "true"},
|
Kubernetes: map[string]string{keyFromCurrent: "true"},
|
||||||
docker: map[string]string{keyHost: "https://someswarmserver"},
|
Docker: map[string]string{keyHost: "https://someswarmserver"},
|
||||||
})
|
})
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,32 +10,34 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
type removeOptions struct {
|
// RemoveOptions are the options used to remove contexts
|
||||||
force bool
|
type RemoveOptions struct {
|
||||||
|
Force bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
|
func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
var opts removeOptions
|
var opts RemoveOptions
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "rm CONTEXT [CONTEXT...]",
|
Use: "rm CONTEXT [CONTEXT...]",
|
||||||
Aliases: []string{"remove"},
|
Aliases: []string{"remove"},
|
||||||
Short: "Remove one or more contexts",
|
Short: "Remove one or more contexts",
|
||||||
Args: cli.RequiresMinArgs(1),
|
Args: cli.RequiresMinArgs(1),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
return runRemove(dockerCli, opts, args)
|
return RunRemove(dockerCli, opts, args)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cmd.Flags().BoolVarP(&opts.force, "force", "f", false, "Force the removal of a context in use")
|
cmd.Flags().BoolVarP(&opts.Force, "force", "f", false, "Force the removal of a context in use")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runRemove(dockerCli command.Cli, opts removeOptions, names []string) error {
|
// RunRemove removes one or more contexts
|
||||||
|
func RunRemove(dockerCli command.Cli, opts RemoveOptions, names []string) error {
|
||||||
var errs []string
|
var errs []string
|
||||||
currentCtx := dockerCli.CurrentContext()
|
currentCtx := dockerCli.CurrentContext()
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
if name == "default" {
|
if name == "default" {
|
||||||
errs = append(errs, `default: context "default" cannot be removed`)
|
errs = append(errs, `default: context "default" cannot be removed`)
|
||||||
} else if err := doRemove(dockerCli, name, name == currentCtx, opts.force); err != nil {
|
} else if err := doRemove(dockerCli, name, name == currentCtx, opts.Force); err != nil {
|
||||||
errs = append(errs, fmt.Sprintf("%s: %s", name, err))
|
errs = append(errs, fmt.Sprintf("%s: %s", name, err))
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintln(dockerCli.Out(), name)
|
fmt.Fprintln(dockerCli.Out(), name)
|
||||||
|
|
|
@ -17,7 +17,7 @@ func TestRemove(t *testing.T) {
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
createTestContextWithKubeAndSwarm(t, cli, "current", "all")
|
createTestContextWithKubeAndSwarm(t, cli, "current", "all")
|
||||||
createTestContextWithKubeAndSwarm(t, cli, "other", "all")
|
createTestContextWithKubeAndSwarm(t, cli, "other", "all")
|
||||||
assert.NilError(t, runRemove(cli, removeOptions{}, []string{"other"}))
|
assert.NilError(t, RunRemove(cli, RemoveOptions{}, []string{"other"}))
|
||||||
_, err := cli.ContextStore().GetContextMetadata("current")
|
_, err := cli.ContextStore().GetContextMetadata("current")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
_, err = cli.ContextStore().GetContextMetadata("other")
|
_, err = cli.ContextStore().GetContextMetadata("other")
|
||||||
|
@ -29,7 +29,7 @@ func TestRemoveNotAContext(t *testing.T) {
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
createTestContextWithKubeAndSwarm(t, cli, "current", "all")
|
createTestContextWithKubeAndSwarm(t, cli, "current", "all")
|
||||||
createTestContextWithKubeAndSwarm(t, cli, "other", "all")
|
createTestContextWithKubeAndSwarm(t, cli, "other", "all")
|
||||||
err := runRemove(cli, removeOptions{}, []string{"not-a-context"})
|
err := RunRemove(cli, RemoveOptions{}, []string{"not-a-context"})
|
||||||
assert.ErrorContains(t, err, `context "not-a-context" does not exist`)
|
assert.ErrorContains(t, err, `context "not-a-context" does not exist`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ func TestRemoveCurrent(t *testing.T) {
|
||||||
createTestContextWithKubeAndSwarm(t, cli, "current", "all")
|
createTestContextWithKubeAndSwarm(t, cli, "current", "all")
|
||||||
createTestContextWithKubeAndSwarm(t, cli, "other", "all")
|
createTestContextWithKubeAndSwarm(t, cli, "other", "all")
|
||||||
cli.SetCurrentContext("current")
|
cli.SetCurrentContext("current")
|
||||||
err := runRemove(cli, removeOptions{}, []string{"current"})
|
err := RunRemove(cli, RemoveOptions{}, []string{"current"})
|
||||||
assert.ErrorContains(t, err, "current: context is in use, set -f flag to force remove")
|
assert.ErrorContains(t, err, "current: context is in use, set -f flag to force remove")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ func TestRemoveCurrentForce(t *testing.T) {
|
||||||
createTestContextWithKubeAndSwarm(t, cli, "current", "all")
|
createTestContextWithKubeAndSwarm(t, cli, "current", "all")
|
||||||
createTestContextWithKubeAndSwarm(t, cli, "other", "all")
|
createTestContextWithKubeAndSwarm(t, cli, "other", "all")
|
||||||
cli.SetCurrentContext("current")
|
cli.SetCurrentContext("current")
|
||||||
assert.NilError(t, runRemove(cli, removeOptions{force: true}, []string{"current"}))
|
assert.NilError(t, RunRemove(cli, RemoveOptions{Force: true}, []string{"current"}))
|
||||||
reloadedConfig, err := config.Load(configDir)
|
reloadedConfig, err := config.Load(configDir)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.Equal(t, "", reloadedConfig.CurrentContext)
|
assert.Equal(t, "", reloadedConfig.CurrentContext)
|
||||||
|
|
|
@ -14,12 +14,13 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
type updateOptions struct {
|
// UpdateOptions are the options used to update a context
|
||||||
name string
|
type UpdateOptions struct {
|
||||||
description string
|
Name string
|
||||||
defaultStackOrchestrator string
|
Description string
|
||||||
docker map[string]string
|
DefaultStackOrchestrator string
|
||||||
kubernetes map[string]string
|
Docker map[string]string
|
||||||
|
Kubernetes map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func longUpdateDescription() string {
|
func longUpdateDescription() string {
|
||||||
|
@ -43,34 +44,35 @@ func longUpdateDescription() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newUpdateCommand(dockerCli command.Cli) *cobra.Command {
|
func newUpdateCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
opts := &updateOptions{}
|
opts := &UpdateOptions{}
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "update [OPTIONS] CONTEXT",
|
Use: "update [OPTIONS] CONTEXT",
|
||||||
Short: "Update a context",
|
Short: "Update a context",
|
||||||
Args: cli.ExactArgs(1),
|
Args: cli.ExactArgs(1),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
opts.name = args[0]
|
opts.Name = args[0]
|
||||||
return runUpdate(dockerCli, opts)
|
return RunUpdate(dockerCli, opts)
|
||||||
},
|
},
|
||||||
Long: longUpdateDescription(),
|
Long: longUpdateDescription(),
|
||||||
}
|
}
|
||||||
flags := cmd.Flags()
|
flags := cmd.Flags()
|
||||||
flags.StringVar(&opts.description, "description", "", "Description of the context")
|
flags.StringVar(&opts.Description, "description", "", "Description of the context")
|
||||||
flags.StringVar(
|
flags.StringVar(
|
||||||
&opts.defaultStackOrchestrator,
|
&opts.DefaultStackOrchestrator,
|
||||||
"default-stack-orchestrator", "",
|
"default-stack-orchestrator", "",
|
||||||
"Default orchestrator for stack operations to use with this context (swarm|kubernetes|all)")
|
"Default orchestrator for stack operations to use with this context (swarm|kubernetes|all)")
|
||||||
flags.StringToStringVar(&opts.docker, "docker", nil, "set the docker endpoint")
|
flags.StringToStringVar(&opts.Docker, "docker", nil, "set the docker endpoint")
|
||||||
flags.StringToStringVar(&opts.kubernetes, "kubernetes", nil, "set the kubernetes endpoint")
|
flags.StringToStringVar(&opts.Kubernetes, "kubernetes", nil, "set the kubernetes endpoint")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runUpdate(cli command.Cli, o *updateOptions) error {
|
// RunUpdate updates a Docker context
|
||||||
if err := validateContextName(o.name); err != nil {
|
func RunUpdate(cli command.Cli, o *UpdateOptions) error {
|
||||||
|
if err := validateContextName(o.Name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s := cli.ContextStore()
|
s := cli.ContextStore()
|
||||||
c, err := s.GetContextMetadata(o.name)
|
c, err := s.GetContextMetadata(o.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -78,31 +80,31 @@ func runUpdate(cli command.Cli, o *updateOptions) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if o.defaultStackOrchestrator != "" {
|
if o.DefaultStackOrchestrator != "" {
|
||||||
stackOrchestrator, err := command.NormalizeOrchestrator(o.defaultStackOrchestrator)
|
stackOrchestrator, err := command.NormalizeOrchestrator(o.DefaultStackOrchestrator)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "unable to parse default-stack-orchestrator")
|
return errors.Wrap(err, "unable to parse default-stack-orchestrator")
|
||||||
}
|
}
|
||||||
dockerContext.StackOrchestrator = stackOrchestrator
|
dockerContext.StackOrchestrator = stackOrchestrator
|
||||||
}
|
}
|
||||||
if o.description != "" {
|
if o.Description != "" {
|
||||||
dockerContext.Description = o.description
|
dockerContext.Description = o.Description
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Metadata = dockerContext
|
c.Metadata = dockerContext
|
||||||
|
|
||||||
tlsDataToReset := make(map[string]*store.EndpointTLSData)
|
tlsDataToReset := make(map[string]*store.EndpointTLSData)
|
||||||
|
|
||||||
if o.docker != nil {
|
if o.Docker != nil {
|
||||||
dockerEP, dockerTLS, err := getDockerEndpointMetadataAndTLS(cli, o.docker)
|
dockerEP, dockerTLS, err := getDockerEndpointMetadataAndTLS(cli, o.Docker)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "unable to create docker endpoint config")
|
return errors.Wrap(err, "unable to create docker endpoint config")
|
||||||
}
|
}
|
||||||
c.Endpoints[docker.DockerEndpoint] = dockerEP
|
c.Endpoints[docker.DockerEndpoint] = dockerEP
|
||||||
tlsDataToReset[docker.DockerEndpoint] = dockerTLS
|
tlsDataToReset[docker.DockerEndpoint] = dockerTLS
|
||||||
}
|
}
|
||||||
if o.kubernetes != nil {
|
if o.Kubernetes != nil {
|
||||||
kubernetesEP, kubernetesTLS, err := getKubernetesEndpointMetadataAndTLS(cli, o.kubernetes)
|
kubernetesEP, kubernetesTLS, err := getKubernetesEndpointMetadataAndTLS(cli, o.Kubernetes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "unable to create kubernetes endpoint config")
|
return errors.Wrap(err, "unable to create kubernetes endpoint config")
|
||||||
}
|
}
|
||||||
|
@ -120,13 +122,13 @@ func runUpdate(cli command.Cli, o *updateOptions) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for ep, tlsData := range tlsDataToReset {
|
for ep, tlsData := range tlsDataToReset {
|
||||||
if err := s.ResetContextEndpointTLSMaterial(o.name, ep, tlsData); err != nil {
|
if err := s.ResetContextEndpointTLSMaterial(o.Name, ep, tlsData); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintln(cli.Out(), o.name)
|
fmt.Fprintln(cli.Out(), o.Name)
|
||||||
fmt.Fprintf(cli.Err(), "Successfully updated context %q\n", o.name)
|
fmt.Fprintf(cli.Err(), "Successfully updated context %q\n", o.Name)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,17 +13,17 @@ import (
|
||||||
func TestUpdateDescriptionOnly(t *testing.T) {
|
func TestUpdateDescriptionOnly(t *testing.T) {
|
||||||
cli, cleanup := makeFakeCli(t)
|
cli, cleanup := makeFakeCli(t)
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
err := runCreate(cli, &createOptions{
|
err := RunCreate(cli, &CreateOptions{
|
||||||
name: "test",
|
Name: "test",
|
||||||
defaultStackOrchestrator: "swarm",
|
DefaultStackOrchestrator: "swarm",
|
||||||
docker: map[string]string{},
|
Docker: map[string]string{},
|
||||||
})
|
})
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
cli.OutBuffer().Reset()
|
cli.OutBuffer().Reset()
|
||||||
cli.ErrBuffer().Reset()
|
cli.ErrBuffer().Reset()
|
||||||
assert.NilError(t, runUpdate(cli, &updateOptions{
|
assert.NilError(t, RunUpdate(cli, &UpdateOptions{
|
||||||
name: "test",
|
Name: "test",
|
||||||
description: "description",
|
Description: "description",
|
||||||
}))
|
}))
|
||||||
c, err := cli.ContextStore().GetContextMetadata("test")
|
c, err := cli.ContextStore().GetContextMetadata("test")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
@ -40,9 +40,9 @@ func TestUpdateDockerOnly(t *testing.T) {
|
||||||
cli, cleanup := makeFakeCli(t)
|
cli, cleanup := makeFakeCli(t)
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
createTestContextWithKubeAndSwarm(t, cli, "test", "swarm")
|
createTestContextWithKubeAndSwarm(t, cli, "test", "swarm")
|
||||||
assert.NilError(t, runUpdate(cli, &updateOptions{
|
assert.NilError(t, RunUpdate(cli, &UpdateOptions{
|
||||||
name: "test",
|
Name: "test",
|
||||||
docker: map[string]string{
|
Docker: map[string]string{
|
||||||
keyHost: "tcp://some-host",
|
keyHost: "tcp://some-host",
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
@ -60,15 +60,15 @@ func TestUpdateDockerOnly(t *testing.T) {
|
||||||
func TestUpdateStackOrchestratorStrategy(t *testing.T) {
|
func TestUpdateStackOrchestratorStrategy(t *testing.T) {
|
||||||
cli, cleanup := makeFakeCli(t)
|
cli, cleanup := makeFakeCli(t)
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
err := runCreate(cli, &createOptions{
|
err := RunCreate(cli, &CreateOptions{
|
||||||
name: "test",
|
Name: "test",
|
||||||
defaultStackOrchestrator: "swarm",
|
DefaultStackOrchestrator: "swarm",
|
||||||
docker: map[string]string{},
|
Docker: map[string]string{},
|
||||||
})
|
})
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
err = runUpdate(cli, &updateOptions{
|
err = RunUpdate(cli, &UpdateOptions{
|
||||||
name: "test",
|
Name: "test",
|
||||||
defaultStackOrchestrator: "kubernetes",
|
DefaultStackOrchestrator: "kubernetes",
|
||||||
})
|
})
|
||||||
assert.ErrorContains(t, err, `cannot specify orchestrator "kubernetes" without configuring a Kubernetes endpoint`)
|
assert.ErrorContains(t, err, `cannot specify orchestrator "kubernetes" without configuring a Kubernetes endpoint`)
|
||||||
}
|
}
|
||||||
|
@ -77,9 +77,9 @@ func TestUpdateStackOrchestratorStrategyRemoveKubeEndpoint(t *testing.T) {
|
||||||
cli, cleanup := makeFakeCli(t)
|
cli, cleanup := makeFakeCli(t)
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
createTestContextWithKubeAndSwarm(t, cli, "test", "kubernetes")
|
createTestContextWithKubeAndSwarm(t, cli, "test", "kubernetes")
|
||||||
err := runUpdate(cli, &updateOptions{
|
err := RunUpdate(cli, &UpdateOptions{
|
||||||
name: "test",
|
Name: "test",
|
||||||
kubernetes: map[string]string{},
|
Kubernetes: map[string]string{},
|
||||||
})
|
})
|
||||||
assert.ErrorContains(t, err, `cannot specify orchestrator "kubernetes" without configuring a Kubernetes endpoint`)
|
assert.ErrorContains(t, err, `cannot specify orchestrator "kubernetes" without configuring a Kubernetes endpoint`)
|
||||||
}
|
}
|
||||||
|
@ -87,14 +87,14 @@ func TestUpdateStackOrchestratorStrategyRemoveKubeEndpoint(t *testing.T) {
|
||||||
func TestUpdateInvalidDockerHost(t *testing.T) {
|
func TestUpdateInvalidDockerHost(t *testing.T) {
|
||||||
cli, cleanup := makeFakeCli(t)
|
cli, cleanup := makeFakeCli(t)
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
err := runCreate(cli, &createOptions{
|
err := RunCreate(cli, &CreateOptions{
|
||||||
name: "test",
|
Name: "test",
|
||||||
docker: map[string]string{},
|
Docker: map[string]string{},
|
||||||
})
|
})
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
err = runUpdate(cli, &updateOptions{
|
err = RunUpdate(cli, &UpdateOptions{
|
||||||
name: "test",
|
Name: "test",
|
||||||
docker: map[string]string{
|
Docker: map[string]string{
|
||||||
keyHost: "some///invalid/host",
|
keyHost: "some///invalid/host",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -14,26 +14,30 @@ func newUseCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
name := args[0]
|
name := args[0]
|
||||||
|
return RunUse(dockerCli, name)
|
||||||
if err := validateContextName(name); err != nil && name != "default" {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := dockerCli.ContextStore().GetContextMetadata(name); err != nil && name != "default" {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
configValue := name
|
|
||||||
if configValue == "default" {
|
|
||||||
configValue = ""
|
|
||||||
}
|
|
||||||
dockerConfig := dockerCli.ConfigFile()
|
|
||||||
dockerConfig.CurrentContext = configValue
|
|
||||||
if err := dockerConfig.Save(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Fprintln(dockerCli.Out(), name)
|
|
||||||
fmt.Fprintf(dockerCli.Err(), "Current context is now %q\n", name)
|
|
||||||
return nil
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RunUse set the current Docker context
|
||||||
|
func RunUse(dockerCli command.Cli, name string) error {
|
||||||
|
if err := validateContextName(name); err != nil && name != "default" {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := dockerCli.ContextStore().GetContextMetadata(name); err != nil && name != "default" {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
configValue := name
|
||||||
|
if configValue == "default" {
|
||||||
|
configValue = ""
|
||||||
|
}
|
||||||
|
dockerConfig := dockerCli.ConfigFile()
|
||||||
|
dockerConfig.CurrentContext = configValue
|
||||||
|
if err := dockerConfig.Save(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Fprintln(dockerCli.Out(), name)
|
||||||
|
fmt.Fprintf(dockerCli.Err(), "Current context is now %q\n", name)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -20,9 +20,9 @@ func TestUse(t *testing.T) {
|
||||||
testCfg := configfile.New(configFilePath)
|
testCfg := configfile.New(configFilePath)
|
||||||
cli, cleanup := makeFakeCli(t, withCliConfig(testCfg))
|
cli, cleanup := makeFakeCli(t, withCliConfig(testCfg))
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
err = runCreate(cli, &createOptions{
|
err = RunCreate(cli, &CreateOptions{
|
||||||
name: "test",
|
Name: "test",
|
||||||
docker: map[string]string{},
|
Docker: map[string]string{},
|
||||||
})
|
})
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.NilError(t, newUseCommand(cli).RunE(nil, []string{"test"}))
|
assert.NilError(t, newUseCommand(cli).RunE(nil, []string{"test"}))
|
||||||
|
|
|
@ -25,6 +25,11 @@ type Config struct {
|
||||||
endpointTypes map[string]TypeGetter
|
endpointTypes map[string]TypeGetter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetEndpoint set an endpoint typing information
|
||||||
|
func (c Config) SetEndpoint(name string, getter TypeGetter) {
|
||||||
|
c.endpointTypes[name] = getter
|
||||||
|
}
|
||||||
|
|
||||||
// NewConfig creates a config object
|
// NewConfig creates a config object
|
||||||
func NewConfig(contextType TypeGetter, endpoints ...NamedTypeGetter) Config {
|
func NewConfig(contextType TypeGetter, endpoints ...NamedTypeGetter) Config {
|
||||||
res := Config{
|
res := Config{
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gotest.tools/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type testCtx struct{}
|
||||||
|
type testEP1 struct{}
|
||||||
|
type testEP2 struct{}
|
||||||
|
type testEP3 struct{}
|
||||||
|
|
||||||
|
func TestConfigModification(t *testing.T) {
|
||||||
|
cfg := NewConfig(func() interface{} { return &testCtx{} }, EndpointTypeGetter("ep1", func() interface{} { return &testEP1{} }))
|
||||||
|
assert.Equal(t, &testCtx{}, cfg.contextType())
|
||||||
|
assert.Equal(t, &testEP1{}, cfg.endpointTypes["ep1"]())
|
||||||
|
cfgCopy := cfg
|
||||||
|
|
||||||
|
// modify existing endpoint
|
||||||
|
cfg.SetEndpoint("ep1", func() interface{} { return &testEP2{} })
|
||||||
|
// add endpoint
|
||||||
|
cfg.SetEndpoint("ep2", func() interface{} { return &testEP3{} })
|
||||||
|
assert.Equal(t, &testCtx{}, cfg.contextType())
|
||||||
|
assert.Equal(t, &testEP2{}, cfg.endpointTypes["ep1"]())
|
||||||
|
assert.Equal(t, &testEP3{}, cfg.endpointTypes["ep2"]())
|
||||||
|
// check it applied on already initialized store
|
||||||
|
assert.Equal(t, &testCtx{}, cfgCopy.contextType())
|
||||||
|
assert.Equal(t, &testEP2{}, cfgCopy.endpointTypes["ep1"]())
|
||||||
|
assert.Equal(t, &testEP3{}, cfgCopy.endpointTypes["ep2"]())
|
||||||
|
}
|
Loading…
Reference in New Issue