DockerCLI/cli/command/stack/cmd.go

121 lines
3.4 KiB
Go

package stack
import (
"errors"
"fmt"
"strings"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
var errUnsupportedAllOrchestrator = fmt.Errorf(`no orchestrator specified: use either "kubernetes" or "swarm"`)
type commonOptions struct {
orchestrator command.Orchestrator
}
func (o *commonOptions) Orchestrator() command.Orchestrator {
if o == nil {
return command.OrchestratorSwarm
}
return o.orchestrator
}
// NewStackCommand returns a cobra command for `stack` subcommands
func NewStackCommand(dockerCli command.Cli) *cobra.Command {
var opts commonOptions
cmd := &cobra.Command{
Use: "stack [OPTIONS]",
Short: "Manage Docker stacks",
Args: cli.NoArgs,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
orchestrator, err := getOrchestrator(dockerCli, cmd)
if err != nil {
return err
}
opts.orchestrator = orchestrator
hideOrchestrationFlags(cmd, orchestrator)
return checkSupportedFlag(cmd, orchestrator)
},
RunE: command.ShowHelp(dockerCli.Err()),
Annotations: map[string]string{
"version": "1.25",
},
}
defaultHelpFunc := cmd.HelpFunc()
cmd.SetHelpFunc(func(c *cobra.Command, args []string) {
if err := cmd.Root().PersistentPreRunE(c, args); err != nil {
fmt.Fprintln(dockerCli.Err(), err)
return
}
if err := cmd.PersistentPreRunE(c, args); err != nil {
fmt.Fprintln(dockerCli.Err(), err)
return
}
hideOrchestrationFlags(c, opts.orchestrator)
defaultHelpFunc(c, args)
})
cmd.AddCommand(
newDeployCommand(dockerCli, &opts),
newListCommand(dockerCli, &opts),
newPsCommand(dockerCli, &opts),
newRemoveCommand(dockerCli, &opts),
newServicesCommand(dockerCli, &opts),
)
flags := cmd.PersistentFlags()
flags.String("kubeconfig", "", "Kubernetes config file")
flags.SetAnnotation("kubeconfig", "kubernetes", nil)
flags.String("orchestrator", "", "Orchestrator to use (swarm|kubernetes|all)")
return cmd
}
func getOrchestrator(dockerCli command.Cli, cmd *cobra.Command) (command.Orchestrator, error) {
var orchestratorFlag string
if o, err := cmd.Flags().GetString("orchestrator"); err == nil {
orchestratorFlag = o
}
return dockerCli.StackOrchestrator(orchestratorFlag)
}
func hideOrchestrationFlags(cmd *cobra.Command, orchestrator command.Orchestrator) {
cmd.Flags().VisitAll(func(f *pflag.Flag) {
if _, ok := f.Annotations["kubernetes"]; ok && !orchestrator.HasKubernetes() {
f.Hidden = true
}
if _, ok := f.Annotations["swarm"]; ok && !orchestrator.HasSwarm() {
f.Hidden = true
}
})
for _, subcmd := range cmd.Commands() {
hideOrchestrationFlags(subcmd, orchestrator)
}
}
func checkSupportedFlag(cmd *cobra.Command, orchestrator command.Orchestrator) error {
errs := []string{}
cmd.Flags().VisitAll(func(f *pflag.Flag) {
if !f.Changed {
return
}
if _, ok := f.Annotations["kubernetes"]; ok && !orchestrator.HasKubernetes() {
errs = append(errs, fmt.Sprintf(`"--%s" is only supported on a Docker cli with kubernetes features enabled`, f.Name))
}
if _, ok := f.Annotations["swarm"]; ok && !orchestrator.HasSwarm() {
errs = append(errs, fmt.Sprintf(`"--%s" is only supported on a Docker cli with swarm features enabled`, f.Name))
}
})
for _, subcmd := range cmd.Commands() {
if err := checkSupportedFlag(subcmd, orchestrator); err != nil {
errs = append(errs, err.Error())
}
}
if len(errs) > 0 {
return errors.New(strings.Join(errs, "\n"))
}
return nil
}