Skip to content

Commit e708c90

Browse files
author
Vincent Demeester
authored
Merge pull request docker#721 from silvin-lubecki/kube
Add kubernetes support to docker/cli
2 parents 1a64b1b + 18c44e0 commit e708c90

924 files changed

Lines changed: 304855 additions & 3151 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cli/command/cli.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ type Cli interface {
4444
ServerInfo() ServerInfo
4545
ClientInfo() ClientInfo
4646
NotaryClient(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (notaryclient.Repository, error)
47+
DefaultVersion() string
4748
}
4849

4950
// DockerCli is an instance the docker command line client.
@@ -135,9 +136,11 @@ func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions) error {
135136
if err != nil {
136137
return errors.Wrap(err, "Experimental field")
137138
}
139+
orchestrator := GetOrchestrator(hasExperimental, opts.Common.Orchestrator, cli.configFile.Orchestrator)
138140
cli.clientInfo = ClientInfo{
139141
DefaultVersion: cli.client.ClientVersion(),
140142
HasExperimental: hasExperimental,
143+
Orchestrator: orchestrator,
141144
}
142145
cli.initializeFromClient()
143146
return nil
@@ -203,6 +206,12 @@ type ServerInfo struct {
203206
type ClientInfo struct {
204207
HasExperimental bool
205208
DefaultVersion string
209+
Orchestrator Orchestrator
210+
}
211+
212+
// HasKubernetes checks if kubernetes orchestrator is enabled
213+
func (c ClientInfo) HasKubernetes() bool {
214+
return c.HasExperimental && c.Orchestrator == OrchestratorKubernetes
206215
}
207216

208217
// NewDockerCli returns a DockerCli instance with IO output and error streams set by in, out and err.

cli/command/cli_test.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,110 @@ func TestExperimentalCLI(t *testing.T) {
170170
}
171171
}
172172

173+
func TestOrchestratorSwitch(t *testing.T) {
174+
defaultVersion := "v0.00"
175+
176+
var testcases = []struct {
177+
doc string
178+
configfile string
179+
envOrchestrator string
180+
flagOrchestrator string
181+
expectedOrchestrator string
182+
expectedKubernetes bool
183+
}{
184+
{
185+
doc: "default",
186+
configfile: `{
187+
"experimental": "enabled"
188+
}`,
189+
expectedOrchestrator: "swarm",
190+
expectedKubernetes: false,
191+
},
192+
{
193+
doc: "kubernetesIsExperimental",
194+
configfile: `{
195+
"experimental": "disabled",
196+
"orchestrator": "kubernetes"
197+
}`,
198+
envOrchestrator: "kubernetes",
199+
flagOrchestrator: "kubernetes",
200+
expectedOrchestrator: "swarm",
201+
expectedKubernetes: false,
202+
},
203+
{
204+
doc: "kubernetesConfigFile",
205+
configfile: `{
206+
"experimental": "enabled",
207+
"orchestrator": "kubernetes"
208+
}`,
209+
expectedOrchestrator: "kubernetes",
210+
expectedKubernetes: true,
211+
},
212+
{
213+
doc: "kubernetesEnv",
214+
configfile: `{
215+
"experimental": "enabled"
216+
}`,
217+
envOrchestrator: "kubernetes",
218+
expectedOrchestrator: "kubernetes",
219+
expectedKubernetes: true,
220+
},
221+
{
222+
doc: "kubernetesFlag",
223+
configfile: `{
224+
"experimental": "enabled"
225+
}`,
226+
flagOrchestrator: "kubernetes",
227+
expectedOrchestrator: "kubernetes",
228+
expectedKubernetes: true,
229+
},
230+
{
231+
doc: "envOverridesConfigFile",
232+
configfile: `{
233+
"experimental": "enabled",
234+
"orchestrator": "kubernetes"
235+
}`,
236+
envOrchestrator: "swarm",
237+
expectedOrchestrator: "swarm",
238+
expectedKubernetes: false,
239+
},
240+
{
241+
doc: "flagOverridesEnv",
242+
configfile: `{
243+
"experimental": "enabled"
244+
}`,
245+
envOrchestrator: "kubernetes",
246+
flagOrchestrator: "swarm",
247+
expectedOrchestrator: "swarm",
248+
expectedKubernetes: false,
249+
},
250+
}
251+
252+
for _, testcase := range testcases {
253+
t.Run(testcase.doc, func(t *testing.T) {
254+
dir := fs.NewDir(t, testcase.doc, fs.WithFile("config.json", testcase.configfile))
255+
defer dir.Remove()
256+
apiclient := &fakeClient{
257+
version: defaultVersion,
258+
}
259+
if testcase.envOrchestrator != "" {
260+
defer patchEnvVariable(t, "DOCKER_ORCHESTRATOR", testcase.envOrchestrator)()
261+
}
262+
263+
cli := &DockerCli{client: apiclient, err: os.Stderr}
264+
cliconfig.SetDir(dir.Path())
265+
options := flags.NewClientOptions()
266+
if testcase.flagOrchestrator != "" {
267+
options.Common.Orchestrator = testcase.flagOrchestrator
268+
}
269+
err := cli.Initialize(options)
270+
assert.NoError(t, err)
271+
assert.Equal(t, testcase.expectedKubernetes, cli.ClientInfo().HasKubernetes())
272+
assert.Equal(t, testcase.expectedOrchestrator, string(cli.ClientInfo().Orchestrator))
273+
})
274+
}
275+
}
276+
173277
func TestGetClientWithPassword(t *testing.T) {
174278
expected := "password"
175279

cli/command/config/cmd.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@ import (
1010
// NewConfigCommand returns a cobra command for `config` subcommands
1111
func NewConfigCommand(dockerCli command.Cli) *cobra.Command {
1212
cmd := &cobra.Command{
13-
Use: "config",
14-
Short: "Manage Docker configs",
15-
Args: cli.NoArgs,
16-
RunE: command.ShowHelp(dockerCli.Err()),
17-
Annotations: map[string]string{"version": "1.30"},
13+
Use: "config",
14+
Short: "Manage Docker configs",
15+
Args: cli.NoArgs,
16+
RunE: command.ShowHelp(dockerCli.Err()),
17+
Annotations: map[string]string{
18+
"version": "1.30",
19+
"swarm": "",
20+
},
1821
}
1922
cmd.AddCommand(
2023
newConfigListCommand(dockerCli),

cli/command/node/cmd.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,14 @@ import (
1414
// NewNodeCommand returns a cobra command for `node` subcommands
1515
func NewNodeCommand(dockerCli command.Cli) *cobra.Command {
1616
cmd := &cobra.Command{
17-
Use: "node",
18-
Short: "Manage Swarm nodes",
19-
Args: cli.NoArgs,
20-
RunE: command.ShowHelp(dockerCli.Err()),
21-
Annotations: map[string]string{"version": "1.24"},
17+
Use: "node",
18+
Short: "Manage Swarm nodes",
19+
Args: cli.NoArgs,
20+
RunE: command.ShowHelp(dockerCli.Err()),
21+
Annotations: map[string]string{
22+
"version": "1.24",
23+
"swarm": "",
24+
},
2225
}
2326
cmd.AddCommand(
2427
newDemoteCommand(dockerCli),

cli/command/orchestrator.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package command
2+
3+
import (
4+
"fmt"
5+
"os"
6+
)
7+
8+
// Orchestrator type acts as an enum describing supported orchestrators.
9+
type Orchestrator string
10+
11+
const (
12+
// OrchestratorKubernetes orchestrator
13+
OrchestratorKubernetes = Orchestrator("kubernetes")
14+
// OrchestratorSwarm orchestrator
15+
OrchestratorSwarm = Orchestrator("swarm")
16+
orchestratorUnset = Orchestrator("unset")
17+
18+
defaultOrchestrator = OrchestratorSwarm
19+
envVarDockerOrchestrator = "DOCKER_ORCHESTRATOR"
20+
)
21+
22+
func normalize(flag string) Orchestrator {
23+
switch flag {
24+
case "kubernetes", "k8s":
25+
return OrchestratorKubernetes
26+
case "swarm", "swarmkit":
27+
return OrchestratorSwarm
28+
default:
29+
return orchestratorUnset
30+
}
31+
}
32+
33+
// GetOrchestrator checks DOCKER_ORCHESTRATOR environment variable and configuration file
34+
// orchestrator value and returns user defined Orchestrator.
35+
func GetOrchestrator(isExperimental bool, flagValue, value string) Orchestrator {
36+
// Non experimental CLI has kubernetes disabled
37+
if !isExperimental {
38+
return defaultOrchestrator
39+
}
40+
// Check flag
41+
if o := normalize(flagValue); o != orchestratorUnset {
42+
return o
43+
}
44+
// Check environment variable
45+
env := os.Getenv(envVarDockerOrchestrator)
46+
if o := normalize(env); o != orchestratorUnset {
47+
return o
48+
}
49+
// Check specified orchestrator
50+
if o := normalize(value); o != orchestratorUnset {
51+
return o
52+
}
53+
54+
if value != "" {
55+
fmt.Fprintf(os.Stderr, "Specified orchestrator %q is invalid. Please use either kubernetes or swarm\n", value)
56+
}
57+
// Nothing set, use default orchestrator
58+
return defaultOrchestrator
59+
}

cli/command/secret/cmd.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@ import (
1010
// NewSecretCommand returns a cobra command for `secret` subcommands
1111
func NewSecretCommand(dockerCli command.Cli) *cobra.Command {
1212
cmd := &cobra.Command{
13-
Use: "secret",
14-
Short: "Manage Docker secrets",
15-
Args: cli.NoArgs,
16-
RunE: command.ShowHelp(dockerCli.Err()),
17-
Annotations: map[string]string{"version": "1.25"},
13+
Use: "secret",
14+
Short: "Manage Docker secrets",
15+
Args: cli.NoArgs,
16+
RunE: command.ShowHelp(dockerCli.Err()),
17+
Annotations: map[string]string{
18+
"version": "1.25",
19+
"swarm": "",
20+
},
1821
}
1922
cmd.AddCommand(
2023
newSecretListCommand(dockerCli),

cli/command/service/cmd.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@ import (
1010
// NewServiceCommand returns a cobra command for `service` subcommands
1111
func NewServiceCommand(dockerCli command.Cli) *cobra.Command {
1212
cmd := &cobra.Command{
13-
Use: "service",
14-
Short: "Manage services",
15-
Args: cli.NoArgs,
16-
RunE: command.ShowHelp(dockerCli.Err()),
17-
Annotations: map[string]string{"version": "1.24"},
13+
Use: "service",
14+
Short: "Manage services",
15+
Args: cli.NoArgs,
16+
RunE: command.ShowHelp(dockerCli.Err()),
17+
Annotations: map[string]string{
18+
"version": "1.24",
19+
"swarm": "",
20+
},
1821
}
1922
cmd.AddCommand(
2023
newCreateCommand(dockerCli),

cli/command/stack/cmd.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,17 @@ func NewStackCommand(dockerCli command.Cli) *cobra.Command {
1818
cmd.AddCommand(
1919
newDeployCommand(dockerCli),
2020
newListCommand(dockerCli),
21+
newPsCommand(dockerCli),
2122
newRemoveCommand(dockerCli),
2223
newServicesCommand(dockerCli),
23-
newPsCommand(dockerCli),
2424
)
25+
flags := cmd.PersistentFlags()
26+
flags.String("namespace", "default", "Kubernetes namespace to use")
27+
flags.SetAnnotation("namespace", "kubernetes", nil)
28+
flags.SetAnnotation("namespace", "experimentalCLI", nil)
29+
flags.String("kubeconfig", "", "Kubernetes config file")
30+
flags.SetAnnotation("kubeconfig", "kubernetes", nil)
31+
flags.SetAnnotation("kubeconfig", "experimentalCLI", nil)
2532
return cmd
2633
}
2734

0 commit comments

Comments
 (0)