2018-11-09 09:10:41 -05:00
|
|
|
package context
|
|
|
|
|
|
|
|
import (
|
2019-05-13 11:22:02 -04:00
|
|
|
"fmt"
|
2018-11-09 09:10:41 -05:00
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/docker/cli/cli/command"
|
|
|
|
"github.com/docker/cli/cli/config/configfile"
|
|
|
|
"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/internal/test"
|
|
|
|
"gotest.tools/assert"
|
|
|
|
"gotest.tools/env"
|
|
|
|
)
|
|
|
|
|
|
|
|
func makeFakeCli(t *testing.T, opts ...func(*test.FakeCli)) (*test.FakeCli, func()) {
|
|
|
|
dir, err := ioutil.TempDir("", t.Name())
|
|
|
|
assert.NilError(t, err)
|
|
|
|
storeConfig := store.NewConfig(
|
|
|
|
func() interface{} { return &command.DockerContext{} },
|
|
|
|
store.EndpointTypeGetter(docker.DockerEndpoint, func() interface{} { return &docker.EndpointMeta{} }),
|
|
|
|
store.EndpointTypeGetter(kubernetes.KubernetesEndpoint, func() interface{} { return &kubernetes.EndpointMeta{} }),
|
|
|
|
)
|
2019-03-06 09:01:12 -05:00
|
|
|
store := &command.ContextStoreWithDefault{
|
|
|
|
Store: store.New(dir, storeConfig),
|
|
|
|
Resolver: func() (*command.DefaultContext, error) {
|
|
|
|
return &command.DefaultContext{
|
2019-04-18 09:12:30 -04:00
|
|
|
Meta: store.Metadata{
|
2019-03-06 09:01:12 -05:00
|
|
|
Endpoints: map[string]interface{}{
|
|
|
|
docker.DockerEndpoint: docker.EndpointMeta{
|
|
|
|
Host: "unix:///var/run/docker.sock",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Metadata: command.DockerContext{
|
|
|
|
Description: "",
|
|
|
|
StackOrchestrator: command.OrchestratorSwarm,
|
|
|
|
},
|
|
|
|
Name: command.DefaultContextName,
|
|
|
|
},
|
|
|
|
TLS: store.ContextTLSData{},
|
|
|
|
}, nil
|
|
|
|
},
|
|
|
|
}
|
2018-11-09 09:10:41 -05:00
|
|
|
cleanup := func() {
|
|
|
|
os.RemoveAll(dir)
|
|
|
|
}
|
|
|
|
result := test.NewFakeCli(nil, opts...)
|
|
|
|
for _, o := range opts {
|
|
|
|
o(result)
|
|
|
|
}
|
|
|
|
result.SetContextStore(store)
|
|
|
|
return result, cleanup
|
|
|
|
}
|
|
|
|
|
|
|
|
func withCliConfig(configFile *configfile.ConfigFile) func(*test.FakeCli) {
|
|
|
|
return func(m *test.FakeCli) {
|
|
|
|
m.SetConfigFile(configFile)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCreateInvalids(t *testing.T) {
|
|
|
|
cli, cleanup := makeFakeCli(t)
|
|
|
|
defer cleanup()
|
2019-04-18 09:12:30 -04:00
|
|
|
assert.NilError(t, cli.ContextStore().CreateOrUpdate(store.Metadata{Name: "existing-context"}))
|
2018-11-09 09:10:41 -05:00
|
|
|
tests := []struct {
|
2019-01-21 03:37:20 -05:00
|
|
|
options CreateOptions
|
2018-11-09 09:10:41 -05:00
|
|
|
expecterErr string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
expecterErr: `context name cannot be empty`,
|
|
|
|
},
|
2019-03-06 09:01:12 -05:00
|
|
|
{
|
|
|
|
options: CreateOptions{
|
|
|
|
Name: "default",
|
|
|
|
},
|
|
|
|
expecterErr: `"default" is a reserved context name`,
|
|
|
|
},
|
2018-11-09 09:10:41 -05:00
|
|
|
{
|
2019-01-21 03:37:20 -05:00
|
|
|
options: CreateOptions{
|
|
|
|
Name: " ",
|
2018-11-09 09:10:41 -05:00
|
|
|
},
|
|
|
|
expecterErr: `context name " " is invalid`,
|
|
|
|
},
|
|
|
|
{
|
2019-01-21 03:37:20 -05:00
|
|
|
options: CreateOptions{
|
|
|
|
Name: "existing-context",
|
2018-11-09 09:10:41 -05:00
|
|
|
},
|
|
|
|
expecterErr: `context "existing-context" already exists`,
|
|
|
|
},
|
|
|
|
{
|
2019-01-21 03:37:20 -05:00
|
|
|
options: CreateOptions{
|
|
|
|
Name: "invalid-docker-host",
|
|
|
|
Docker: map[string]string{
|
2018-11-09 09:10:41 -05:00
|
|
|
keyHost: "some///invalid/host",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expecterErr: `unable to parse docker host`,
|
|
|
|
},
|
|
|
|
{
|
2019-01-21 03:37:20 -05:00
|
|
|
options: CreateOptions{
|
|
|
|
Name: "invalid-orchestrator",
|
|
|
|
DefaultStackOrchestrator: "invalid",
|
2018-11-09 09:10:41 -05:00
|
|
|
},
|
|
|
|
expecterErr: `specified orchestrator "invalid" is invalid, please use either kubernetes, swarm or all`,
|
|
|
|
},
|
|
|
|
{
|
2019-01-21 03:37:20 -05:00
|
|
|
options: CreateOptions{
|
|
|
|
Name: "orchestrator-kubernetes-no-endpoint",
|
|
|
|
DefaultStackOrchestrator: "kubernetes",
|
|
|
|
Docker: map[string]string{},
|
2018-11-09 09:10:41 -05:00
|
|
|
},
|
|
|
|
expecterErr: `cannot specify orchestrator "kubernetes" without configuring a Kubernetes endpoint`,
|
|
|
|
},
|
|
|
|
{
|
2019-01-21 03:37:20 -05:00
|
|
|
options: CreateOptions{
|
|
|
|
Name: "orchestrator-all-no-endpoint",
|
|
|
|
DefaultStackOrchestrator: "all",
|
|
|
|
Docker: map[string]string{},
|
2018-11-09 09:10:41 -05:00
|
|
|
},
|
|
|
|
expecterErr: `cannot specify orchestrator "all" without configuring a Kubernetes endpoint`,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
|
|
tc := tc
|
2019-01-21 03:37:20 -05:00
|
|
|
t.Run(tc.options.Name, func(t *testing.T) {
|
|
|
|
err := RunCreate(cli, &tc.options)
|
2018-11-09 09:10:41 -05:00
|
|
|
assert.ErrorContains(t, err, tc.expecterErr)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-13 11:22:02 -04:00
|
|
|
func assertContextCreateLogging(t *testing.T, cli *test.FakeCli, n string) {
|
|
|
|
assert.Equal(t, n+"\n", cli.OutBuffer().String())
|
|
|
|
assert.Equal(t, fmt.Sprintf("Successfully created context %q\n", n), cli.ErrBuffer().String())
|
|
|
|
}
|
|
|
|
|
2018-11-09 09:10:41 -05:00
|
|
|
func TestCreateOrchestratorSwarm(t *testing.T) {
|
|
|
|
cli, cleanup := makeFakeCli(t)
|
|
|
|
defer cleanup()
|
|
|
|
|
2019-01-21 03:37:20 -05:00
|
|
|
err := RunCreate(cli, &CreateOptions{
|
|
|
|
Name: "test",
|
|
|
|
DefaultStackOrchestrator: "swarm",
|
|
|
|
Docker: map[string]string{},
|
2018-11-09 09:10:41 -05:00
|
|
|
})
|
|
|
|
assert.NilError(t, err)
|
2019-05-13 11:22:02 -04:00
|
|
|
assertContextCreateLogging(t, cli, "test")
|
2018-11-09 09:10:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestCreateOrchestratorEmpty(t *testing.T) {
|
|
|
|
cli, cleanup := makeFakeCli(t)
|
|
|
|
defer cleanup()
|
|
|
|
|
2019-01-21 03:37:20 -05:00
|
|
|
err := RunCreate(cli, &CreateOptions{
|
|
|
|
Name: "test",
|
|
|
|
Docker: map[string]string{},
|
2018-11-09 09:10:41 -05:00
|
|
|
})
|
|
|
|
assert.NilError(t, err)
|
2019-05-13 11:22:02 -04:00
|
|
|
assertContextCreateLogging(t, cli, "test")
|
2018-11-09 09:10:41 -05:00
|
|
|
}
|
|
|
|
|
2019-04-15 06:03:03 -04:00
|
|
|
func validateTestKubeEndpoint(t *testing.T, s store.Reader, name string) {
|
2018-11-09 09:10:41 -05:00
|
|
|
t.Helper()
|
2019-04-18 09:12:30 -04:00
|
|
|
ctxMetadata, err := s.GetMetadata(name)
|
2018-11-09 09:10:41 -05:00
|
|
|
assert.NilError(t, err)
|
|
|
|
kubeMeta := ctxMetadata.Endpoints[kubernetes.KubernetesEndpoint].(kubernetes.EndpointMeta)
|
|
|
|
kubeEP, err := kubeMeta.WithTLSData(s, name)
|
|
|
|
assert.NilError(t, err)
|
|
|
|
assert.Equal(t, "https://someserver", kubeEP.Host)
|
|
|
|
assert.Equal(t, "the-ca", string(kubeEP.TLSData.CA))
|
|
|
|
assert.Equal(t, "the-cert", string(kubeEP.TLSData.Cert))
|
|
|
|
assert.Equal(t, "the-key", string(kubeEP.TLSData.Key))
|
|
|
|
}
|
|
|
|
|
|
|
|
func createTestContextWithKube(t *testing.T, cli command.Cli) {
|
|
|
|
t.Helper()
|
|
|
|
revert := env.Patch(t, "KUBECONFIG", "./testdata/test-kubeconfig")
|
|
|
|
defer revert()
|
|
|
|
|
2019-01-21 03:37:20 -05:00
|
|
|
err := RunCreate(cli, &CreateOptions{
|
|
|
|
Name: "test",
|
|
|
|
DefaultStackOrchestrator: "all",
|
|
|
|
Kubernetes: map[string]string{
|
2019-03-22 10:20:40 -04:00
|
|
|
keyFrom: "default",
|
2018-11-09 09:10:41 -05:00
|
|
|
},
|
2019-01-21 03:37:20 -05:00
|
|
|
Docker: map[string]string{},
|
2018-11-09 09:10:41 -05:00
|
|
|
})
|
|
|
|
assert.NilError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCreateOrchestratorAllKubernetesEndpointFromCurrent(t *testing.T) {
|
|
|
|
cli, cleanup := makeFakeCli(t)
|
|
|
|
defer cleanup()
|
|
|
|
createTestContextWithKube(t, cli)
|
2019-05-13 11:22:02 -04:00
|
|
|
assertContextCreateLogging(t, cli, "test")
|
2018-11-09 09:10:41 -05:00
|
|
|
validateTestKubeEndpoint(t, cli.ContextStore(), "test")
|
|
|
|
}
|
2019-03-22 10:20:40 -04:00
|
|
|
|
|
|
|
func TestCreateFromContext(t *testing.T) {
|
|
|
|
cases := []struct {
|
|
|
|
name string
|
|
|
|
description string
|
|
|
|
orchestrator string
|
|
|
|
expectedDescription string
|
|
|
|
docker map[string]string
|
|
|
|
kubernetes map[string]string
|
|
|
|
expectedOrchestrator command.Orchestrator
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "no-override",
|
|
|
|
expectedDescription: "original description",
|
|
|
|
expectedOrchestrator: command.OrchestratorSwarm,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "override-description",
|
|
|
|
description: "new description",
|
|
|
|
expectedDescription: "new description",
|
|
|
|
expectedOrchestrator: command.OrchestratorSwarm,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "override-orchestrator",
|
|
|
|
orchestrator: "kubernetes",
|
|
|
|
expectedDescription: "original description",
|
|
|
|
expectedOrchestrator: command.OrchestratorKubernetes,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
cli, cleanup := makeFakeCli(t)
|
|
|
|
defer cleanup()
|
|
|
|
revert := env.Patch(t, "KUBECONFIG", "./testdata/test-kubeconfig")
|
|
|
|
defer revert()
|
2019-05-13 11:22:02 -04:00
|
|
|
cli.ResetOutputBuffers()
|
2019-03-22 10:20:40 -04:00
|
|
|
assert.NilError(t, RunCreate(cli, &CreateOptions{
|
|
|
|
Name: "original",
|
|
|
|
Description: "original description",
|
|
|
|
Docker: map[string]string{
|
|
|
|
keyHost: "tcp://42.42.42.42:2375",
|
|
|
|
},
|
|
|
|
Kubernetes: map[string]string{
|
|
|
|
keyFrom: "default",
|
|
|
|
},
|
|
|
|
DefaultStackOrchestrator: "swarm",
|
|
|
|
}))
|
2019-05-13 11:22:02 -04:00
|
|
|
assertContextCreateLogging(t, cli, "original")
|
|
|
|
|
|
|
|
cli.ResetOutputBuffers()
|
2019-03-22 10:20:40 -04:00
|
|
|
assert.NilError(t, RunCreate(cli, &CreateOptions{
|
|
|
|
Name: "dummy",
|
|
|
|
Description: "dummy description",
|
|
|
|
Docker: map[string]string{
|
|
|
|
keyHost: "tcp://24.24.24.24:2375",
|
|
|
|
},
|
|
|
|
Kubernetes: map[string]string{
|
|
|
|
keyFrom: "default",
|
|
|
|
},
|
|
|
|
DefaultStackOrchestrator: "swarm",
|
|
|
|
}))
|
2019-05-13 11:22:02 -04:00
|
|
|
assertContextCreateLogging(t, cli, "dummy")
|
2019-03-22 10:20:40 -04:00
|
|
|
|
|
|
|
cli.SetCurrentContext("dummy")
|
|
|
|
|
|
|
|
for _, c := range cases {
|
|
|
|
t.Run(c.name, func(t *testing.T) {
|
2019-05-13 11:22:02 -04:00
|
|
|
cli.ResetOutputBuffers()
|
2019-03-22 10:20:40 -04:00
|
|
|
err := RunCreate(cli, &CreateOptions{
|
|
|
|
From: "original",
|
|
|
|
Name: c.name,
|
|
|
|
Description: c.description,
|
|
|
|
DefaultStackOrchestrator: c.orchestrator,
|
|
|
|
Docker: c.docker,
|
|
|
|
Kubernetes: c.kubernetes,
|
|
|
|
})
|
|
|
|
assert.NilError(t, err)
|
2019-05-13 11:22:02 -04:00
|
|
|
assertContextCreateLogging(t, cli, c.name)
|
2019-04-18 09:12:30 -04:00
|
|
|
newContext, err := cli.ContextStore().GetMetadata(c.name)
|
2019-03-22 10:20:40 -04:00
|
|
|
assert.NilError(t, err)
|
|
|
|
newContextTyped, err := command.GetDockerContext(newContext)
|
|
|
|
assert.NilError(t, err)
|
|
|
|
dockerEndpoint, err := docker.EndpointFromContext(newContext)
|
|
|
|
assert.NilError(t, err)
|
|
|
|
kubeEndpoint := kubernetes.EndpointFromContext(newContext)
|
|
|
|
assert.Check(t, kubeEndpoint != nil)
|
|
|
|
assert.Equal(t, newContextTyped.Description, c.expectedDescription)
|
|
|
|
assert.Equal(t, newContextTyped.StackOrchestrator, c.expectedOrchestrator)
|
|
|
|
assert.Equal(t, dockerEndpoint.Host, "tcp://42.42.42.42:2375")
|
|
|
|
assert.Equal(t, kubeEndpoint.Host, "https://someserver")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCreateFromCurrent(t *testing.T) {
|
|
|
|
cases := []struct {
|
|
|
|
name string
|
|
|
|
description string
|
|
|
|
orchestrator string
|
|
|
|
expectedDescription string
|
|
|
|
expectedOrchestrator command.Orchestrator
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "no-override",
|
|
|
|
expectedDescription: "original description",
|
|
|
|
expectedOrchestrator: command.OrchestratorSwarm,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "override-description",
|
|
|
|
description: "new description",
|
|
|
|
expectedDescription: "new description",
|
|
|
|
expectedOrchestrator: command.OrchestratorSwarm,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "override-orchestrator",
|
|
|
|
orchestrator: "kubernetes",
|
|
|
|
expectedDescription: "original description",
|
|
|
|
expectedOrchestrator: command.OrchestratorKubernetes,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
cli, cleanup := makeFakeCli(t)
|
|
|
|
defer cleanup()
|
|
|
|
revert := env.Patch(t, "KUBECONFIG", "./testdata/test-kubeconfig")
|
|
|
|
defer revert()
|
2019-05-13 11:22:02 -04:00
|
|
|
cli.ResetOutputBuffers()
|
2019-03-22 10:20:40 -04:00
|
|
|
assert.NilError(t, RunCreate(cli, &CreateOptions{
|
|
|
|
Name: "original",
|
|
|
|
Description: "original description",
|
|
|
|
Docker: map[string]string{
|
|
|
|
keyHost: "tcp://42.42.42.42:2375",
|
|
|
|
},
|
|
|
|
Kubernetes: map[string]string{
|
|
|
|
keyFrom: "default",
|
|
|
|
},
|
|
|
|
DefaultStackOrchestrator: "swarm",
|
|
|
|
}))
|
2019-05-13 11:22:02 -04:00
|
|
|
assertContextCreateLogging(t, cli, "original")
|
2019-03-22 10:20:40 -04:00
|
|
|
|
|
|
|
cli.SetCurrentContext("original")
|
|
|
|
|
|
|
|
for _, c := range cases {
|
|
|
|
t.Run(c.name, func(t *testing.T) {
|
2019-05-13 11:22:02 -04:00
|
|
|
cli.ResetOutputBuffers()
|
2019-03-22 10:20:40 -04:00
|
|
|
err := RunCreate(cli, &CreateOptions{
|
|
|
|
Name: c.name,
|
|
|
|
Description: c.description,
|
|
|
|
DefaultStackOrchestrator: c.orchestrator,
|
|
|
|
})
|
|
|
|
assert.NilError(t, err)
|
2019-05-13 11:22:02 -04:00
|
|
|
assertContextCreateLogging(t, cli, c.name)
|
2019-04-18 09:12:30 -04:00
|
|
|
newContext, err := cli.ContextStore().GetMetadata(c.name)
|
2019-03-22 10:20:40 -04:00
|
|
|
assert.NilError(t, err)
|
|
|
|
newContextTyped, err := command.GetDockerContext(newContext)
|
|
|
|
assert.NilError(t, err)
|
|
|
|
dockerEndpoint, err := docker.EndpointFromContext(newContext)
|
|
|
|
assert.NilError(t, err)
|
|
|
|
kubeEndpoint := kubernetes.EndpointFromContext(newContext)
|
|
|
|
assert.Check(t, kubeEndpoint != nil)
|
|
|
|
assert.Equal(t, newContextTyped.Description, c.expectedDescription)
|
|
|
|
assert.Equal(t, newContextTyped.StackOrchestrator, c.expectedOrchestrator)
|
|
|
|
assert.Equal(t, dockerEndpoint.Host, "tcp://42.42.42.42:2375")
|
|
|
|
assert.Equal(t, kubeEndpoint.Host, "https://someserver")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|