mirror of https://github.com/docker/cli.git
Merge pull request #991 from silvin-lubecki/kubernetes-namespace
Better namespace experience with Kubernetes
This commit is contained in:
commit
552ee502f7
|
@ -5,10 +5,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
defaultStackTableFormat = "table {{.Name}}\t{{.Services}}\t{{.Orchestrator}}"
|
// KubernetesStackTableFormat is the default Kubernetes stack format
|
||||||
|
KubernetesStackTableFormat = "table {{.Name}}\t{{.Services}}\t{{.Orchestrator}}\t{{.Namespace}}"
|
||||||
|
// SwarmStackTableFormat is the default Swarm stack format
|
||||||
|
SwarmStackTableFormat = "table {{.Name}}\t{{.Services}}\t{{.Orchestrator}}"
|
||||||
|
|
||||||
stackServicesHeader = "SERVICES"
|
stackServicesHeader = "SERVICES"
|
||||||
stackOrchestrastorHeader = "ORCHESTRATOR"
|
stackOrchestrastorHeader = "ORCHESTRATOR"
|
||||||
|
stackNamespaceHeader = "NAMESPACE"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Stack contains deployed stack information.
|
// Stack contains deployed stack information.
|
||||||
|
@ -17,17 +21,10 @@ type Stack struct {
|
||||||
Name string
|
Name string
|
||||||
// Services is the number of the services
|
// Services is the number of the services
|
||||||
Services int
|
Services int
|
||||||
// Orchestratort is the platform on which the stack is deployed
|
// Orchestrator is the platform where the stack is deployed
|
||||||
Orchestrator string
|
Orchestrator string
|
||||||
}
|
// Namespace is the Kubernetes namespace assigned to the stack
|
||||||
|
Namespace string
|
||||||
// NewStackFormat returns a format for use with a stack Context
|
|
||||||
func NewStackFormat(source string) Format {
|
|
||||||
switch source {
|
|
||||||
case TableFormatKey:
|
|
||||||
return defaultStackTableFormat
|
|
||||||
}
|
|
||||||
return Format(source)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// StackWrite writes formatted stacks using the Context
|
// StackWrite writes formatted stacks using the Context
|
||||||
|
@ -54,6 +51,7 @@ func newStackContext() *stackContext {
|
||||||
"Name": nameHeader,
|
"Name": nameHeader,
|
||||||
"Services": stackServicesHeader,
|
"Services": stackServicesHeader,
|
||||||
"Orchestrator": stackOrchestrastorHeader,
|
"Orchestrator": stackOrchestrastorHeader,
|
||||||
|
"Namespace": stackNamespaceHeader,
|
||||||
}
|
}
|
||||||
return &stackCtx
|
return &stackCtx
|
||||||
}
|
}
|
||||||
|
@ -73,3 +71,7 @@ func (s *stackContext) Services() string {
|
||||||
func (s *stackContext) Orchestrator() string {
|
func (s *stackContext) Orchestrator() string {
|
||||||
return s.s.Orchestrator
|
return s.s.Orchestrator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *stackContext) Namespace() string {
|
||||||
|
return s.s.Namespace
|
||||||
|
}
|
||||||
|
|
|
@ -26,14 +26,22 @@ func TestStackContextWrite(t *testing.T) {
|
||||||
},
|
},
|
||||||
// Table format
|
// Table format
|
||||||
{
|
{
|
||||||
Context{Format: NewStackFormat("table")},
|
Context{Format: Format(SwarmStackTableFormat)},
|
||||||
`NAME SERVICES ORCHESTRATOR
|
`NAME SERVICES ORCHESTRATOR
|
||||||
baz 2 orchestrator1
|
baz 2 orchestrator1
|
||||||
bar 1 orchestrator2
|
bar 1 orchestrator2
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
// Kubernetes table format adds Namespace column
|
||||||
{
|
{
|
||||||
Context{Format: NewStackFormat("table {{.Name}}")},
|
Context{Format: Format(KubernetesStackTableFormat)},
|
||||||
|
`NAME SERVICES ORCHESTRATOR NAMESPACE
|
||||||
|
baz 2 orchestrator1 namespace1
|
||||||
|
bar 1 orchestrator2 namespace2
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Context{Format: Format("table {{.Name}}")},
|
||||||
`NAME
|
`NAME
|
||||||
baz
|
baz
|
||||||
bar
|
bar
|
||||||
|
@ -41,7 +49,7 @@ bar
|
||||||
},
|
},
|
||||||
// Custom Format
|
// Custom Format
|
||||||
{
|
{
|
||||||
Context{Format: NewStackFormat("{{.Name}}")},
|
Context{Format: Format("{{.Name}}")},
|
||||||
`baz
|
`baz
|
||||||
bar
|
bar
|
||||||
`,
|
`,
|
||||||
|
@ -49,8 +57,8 @@ bar
|
||||||
}
|
}
|
||||||
|
|
||||||
stacks := []*Stack{
|
stacks := []*Stack{
|
||||||
{Name: "baz", Services: 2, Orchestrator: "orchestrator1"},
|
{Name: "baz", Services: 2, Orchestrator: "orchestrator1", Namespace: "namespace1"},
|
||||||
{Name: "bar", Services: 1, Orchestrator: "orchestrator2"},
|
{Name: "bar", Services: 1, Orchestrator: "orchestrator2", Namespace: "namespace2"},
|
||||||
}
|
}
|
||||||
for _, testcase := range cases {
|
for _, testcase := range cases {
|
||||||
out := bytes.NewBufferString("")
|
out := bytes.NewBufferString("")
|
||||||
|
|
|
@ -27,7 +27,7 @@ func NewStackCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
newServicesCommand(dockerCli),
|
newServicesCommand(dockerCli),
|
||||||
)
|
)
|
||||||
flags := cmd.PersistentFlags()
|
flags := cmd.PersistentFlags()
|
||||||
flags.String("namespace", "default", "Kubernetes namespace to use")
|
flags.String("namespace", "", "Kubernetes namespace to use")
|
||||||
flags.SetAnnotation("namespace", "kubernetes", nil)
|
flags.SetAnnotation("namespace", "kubernetes", nil)
|
||||||
flags.SetAnnotation("namespace", "experimentalCLI", nil)
|
flags.SetAnnotation("namespace", "experimentalCLI", nil)
|
||||||
flags.String("kubeconfig", "", "Kubernetes config file")
|
flags.String("kubeconfig", "", "Kubernetes config file")
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
package kubernetes
|
package kubernetes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/cli/kubernetes"
|
"github.com/docker/cli/kubernetes"
|
||||||
"github.com/docker/docker/pkg/homedir"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
flag "github.com/spf13/pflag"
|
flag "github.com/spf13/pflag"
|
||||||
kubeclient "k8s.io/client-go/kubernetes"
|
kubeclient "k8s.io/client-go/kubernetes"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
|
@ -43,21 +38,20 @@ func NewOptions(flags *flag.FlagSet) Options {
|
||||||
func WrapCli(dockerCli command.Cli, opts Options) (*KubeCli, error) {
|
func WrapCli(dockerCli command.Cli, opts Options) (*KubeCli, error) {
|
||||||
var err error
|
var err error
|
||||||
cli := &KubeCli{
|
cli := &KubeCli{
|
||||||
Cli: dockerCli,
|
Cli: dockerCli,
|
||||||
kubeNamespace: "default",
|
|
||||||
}
|
}
|
||||||
if opts.Namespace != "" {
|
clientConfig := kubernetes.NewKubernetesConfig(opts.Config)
|
||||||
cli.kubeNamespace = opts.Namespace
|
|
||||||
}
|
cli.kubeNamespace = opts.Namespace
|
||||||
kubeConfig := opts.Config
|
if opts.Namespace == "" {
|
||||||
if kubeConfig == "" {
|
configNamespace, _, err := clientConfig.Namespace()
|
||||||
if config := os.Getenv("KUBECONFIG"); config != "" {
|
if err != nil {
|
||||||
kubeConfig = config
|
return nil, err
|
||||||
} else {
|
|
||||||
kubeConfig = filepath.Join(homedir.Get(), ".kube/config")
|
|
||||||
}
|
}
|
||||||
|
cli.kubeNamespace = configNamespace
|
||||||
}
|
}
|
||||||
config, err := kubernetes.NewKubernetesConfig(kubeConfig)
|
|
||||||
|
config, err := clientConfig.ClientConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -73,21 +67,5 @@ func WrapCli(dockerCli command.Cli, opts Options) (*KubeCli, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *KubeCli) composeClient() (*Factory, error) {
|
func (c *KubeCli) composeClient() (*Factory, error) {
|
||||||
return NewFactory(c.kubeNamespace, c.kubeConfig)
|
return NewFactory(c.kubeNamespace, c.kubeConfig, c.clientSet)
|
||||||
}
|
|
||||||
|
|
||||||
func (c *KubeCli) stacks() (stackClient, error) {
|
|
||||||
version, err := kubernetes.GetStackAPIVersion(c.clientSet)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch version {
|
|
||||||
case kubernetes.StackAPIV1Beta1:
|
|
||||||
return newStackV1Beta1(c.kubeConfig, c.kubeNamespace)
|
|
||||||
case kubernetes.StackAPIV1Beta2:
|
|
||||||
return newStackV1Beta2(c.kubeConfig, c.kubeNamespace)
|
|
||||||
default:
|
|
||||||
return nil, errors.Errorf("no supported Stack API version")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
package kubernetes
|
package kubernetes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/docker/cli/kubernetes"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
kubeclient "k8s.io/client-go/kubernetes"
|
||||||
appsv1beta2 "k8s.io/client-go/kubernetes/typed/apps/v1beta2"
|
appsv1beta2 "k8s.io/client-go/kubernetes/typed/apps/v1beta2"
|
||||||
typesappsv1beta2 "k8s.io/client-go/kubernetes/typed/apps/v1beta2"
|
typesappsv1beta2 "k8s.io/client-go/kubernetes/typed/apps/v1beta2"
|
||||||
corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||||
|
@ -13,10 +17,11 @@ type Factory struct {
|
||||||
config *restclient.Config
|
config *restclient.Config
|
||||||
coreClientSet *corev1.CoreV1Client
|
coreClientSet *corev1.CoreV1Client
|
||||||
appsClientSet *appsv1beta2.AppsV1beta2Client
|
appsClientSet *appsv1beta2.AppsV1beta2Client
|
||||||
|
clientSet *kubeclient.Clientset
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFactory creates a kubernetes client factory
|
// NewFactory creates a kubernetes client factory
|
||||||
func NewFactory(namespace string, config *restclient.Config) (*Factory, error) {
|
func NewFactory(namespace string, config *restclient.Config, clientSet *kubeclient.Clientset) (*Factory, error) {
|
||||||
coreClientSet, err := corev1.NewForConfig(config)
|
coreClientSet, err := corev1.NewForConfig(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -32,6 +37,7 @@ func NewFactory(namespace string, config *restclient.Config) (*Factory, error) {
|
||||||
config: config,
|
config: config,
|
||||||
coreClientSet: coreClientSet,
|
coreClientSet: coreClientSet,
|
||||||
appsClientSet: appsClientSet,
|
appsClientSet: appsClientSet,
|
||||||
|
clientSet: clientSet,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +71,28 @@ func (s *Factory) ReplicationControllers() corev1.ReplicationControllerInterface
|
||||||
return s.coreClientSet.ReplicationControllers(s.namespace)
|
return s.coreClientSet.ReplicationControllers(s.namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReplicaSets return a client for kubernetes replace sets
|
// ReplicaSets returns a client for kubernetes replace sets
|
||||||
func (s *Factory) ReplicaSets() typesappsv1beta2.ReplicaSetInterface {
|
func (s *Factory) ReplicaSets() typesappsv1beta2.ReplicaSetInterface {
|
||||||
return s.appsClientSet.ReplicaSets(s.namespace)
|
return s.appsClientSet.ReplicaSets(s.namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stacks returns a client for Docker's Stack on Kubernetes
|
||||||
|
func (s *Factory) Stacks(allNamespaces bool) (StackClient, error) {
|
||||||
|
version, err := kubernetes.GetStackAPIVersion(s.clientSet)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
namespace := s.namespace
|
||||||
|
if allNamespaces {
|
||||||
|
namespace = metav1.NamespaceAll
|
||||||
|
}
|
||||||
|
|
||||||
|
switch version {
|
||||||
|
case kubernetes.StackAPIV1Beta1:
|
||||||
|
return newStackV1Beta1(s.config, namespace)
|
||||||
|
case kubernetes.StackAPIV1Beta2:
|
||||||
|
return newStackV1Beta2(s.config, namespace)
|
||||||
|
default:
|
||||||
|
return nil, errors.Errorf("no supported Stack API version")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ func stackFromV1beta1(in *v1beta1.Stack) (stack, error) {
|
||||||
}
|
}
|
||||||
return stack{
|
return stack{
|
||||||
name: in.ObjectMeta.Name,
|
name: in.ObjectMeta.Name,
|
||||||
|
namespace: in.ObjectMeta.Namespace,
|
||||||
composeFile: in.Spec.ComposeFile,
|
composeFile: in.Spec.ComposeFile,
|
||||||
spec: fromComposeConfig(ioutil.Discard, cfg),
|
spec: fromComposeConfig(ioutil.Discard, cfg),
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -55,8 +56,9 @@ func stackToV1beta1(s stack) *v1beta1.Stack {
|
||||||
|
|
||||||
func stackFromV1beta2(in *v1beta2.Stack) stack {
|
func stackFromV1beta2(in *v1beta2.Stack) stack {
|
||||||
return stack{
|
return stack{
|
||||||
name: in.ObjectMeta.Name,
|
name: in.ObjectMeta.Name,
|
||||||
spec: in.Spec,
|
namespace: in.ObjectMeta.Namespace,
|
||||||
|
spec: in.Spec,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,11 +17,11 @@ func RunDeploy(dockerCli *KubeCli, opts options.Deploy) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize clients
|
// Initialize clients
|
||||||
stacks, err := dockerCli.stacks()
|
composeClient, err := dockerCli.composeClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
composeClient, err := dockerCli.composeClient()
|
stacks, err := composeClient.Stacks(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,17 +11,17 @@ import (
|
||||||
|
|
||||||
// RunList is the kubernetes implementation of docker stack ls
|
// RunList is the kubernetes implementation of docker stack ls
|
||||||
func RunList(dockerCli *KubeCli, opts options.List) error {
|
func RunList(dockerCli *KubeCli, opts options.List) error {
|
||||||
stacks, err := getStacks(dockerCli)
|
stacks, err := getStacks(dockerCli, opts.AllNamespaces)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
format := opts.Format
|
format := opts.Format
|
||||||
if len(format) == 0 {
|
if format == "" || format == formatter.TableFormatKey {
|
||||||
format = formatter.TableFormatKey
|
format = formatter.KubernetesStackTableFormat
|
||||||
}
|
}
|
||||||
stackCtx := formatter.Context{
|
stackCtx := formatter.Context{
|
||||||
Output: dockerCli.Out(),
|
Output: dockerCli.Out(),
|
||||||
Format: formatter.NewStackFormat(format),
|
Format: formatter.Format(format),
|
||||||
}
|
}
|
||||||
sort.Sort(byName(stacks))
|
sort.Sort(byName(stacks))
|
||||||
return formatter.StackWrite(stackCtx, stacks)
|
return formatter.StackWrite(stackCtx, stacks)
|
||||||
|
@ -33,12 +33,15 @@ func (n byName) Len() int { return len(n) }
|
||||||
func (n byName) Swap(i, j int) { n[i], n[j] = n[j], n[i] }
|
func (n byName) Swap(i, j int) { n[i], n[j] = n[j], n[i] }
|
||||||
func (n byName) Less(i, j int) bool { return sortorder.NaturalLess(n[i].Name, n[j].Name) }
|
func (n byName) Less(i, j int) bool { return sortorder.NaturalLess(n[i].Name, n[j].Name) }
|
||||||
|
|
||||||
func getStacks(kubeCli *KubeCli) ([]*formatter.Stack, error) {
|
func getStacks(kubeCli *KubeCli, allNamespaces bool) ([]*formatter.Stack, error) {
|
||||||
stackSvc, err := kubeCli.stacks()
|
composeClient, err := kubeCli.composeClient()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
stackSvc, err := composeClient.Stacks(allNamespaces)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
stacks, err := stackSvc.List(metav1.ListOptions{})
|
stacks, err := stackSvc.List(metav1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -49,6 +52,7 @@ func getStacks(kubeCli *KubeCli) ([]*formatter.Stack, error) {
|
||||||
Name: stack.name,
|
Name: stack.name,
|
||||||
Services: len(stack.getServices()),
|
Services: len(stack.getServices()),
|
||||||
Orchestrator: "Kubernetes",
|
Orchestrator: "Kubernetes",
|
||||||
|
Namespace: stack.namespace,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return formattedStacks, nil
|
return formattedStacks, nil
|
||||||
|
|
|
@ -25,7 +25,7 @@ func RunPS(dockerCli *KubeCli, options options.PS) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
stacks, err := dockerCli.stacks()
|
stacks, err := client.Stacks(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,11 @@ import (
|
||||||
|
|
||||||
// RunRemove is the kubernetes implementation of docker stack remove
|
// RunRemove is the kubernetes implementation of docker stack remove
|
||||||
func RunRemove(dockerCli *KubeCli, opts options.Remove) error {
|
func RunRemove(dockerCli *KubeCli, opts options.Remove) error {
|
||||||
stacks, err := dockerCli.stacks()
|
composeClient, err := dockerCli.composeClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
stacks, err := composeClient.Stacks(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ func RunServices(dockerCli *KubeCli, opts options.Services) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
stacks, err := dockerCli.stacks()
|
stacks, err := client.Stacks(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
// stack is the main type used by stack commands so they remain independent from kubernetes compose component version.
|
// stack is the main type used by stack commands so they remain independent from kubernetes compose component version.
|
||||||
type stack struct {
|
type stack struct {
|
||||||
name string
|
name string
|
||||||
|
namespace string
|
||||||
composeFile string
|
composeFile string
|
||||||
spec *v1beta2.StackSpec
|
spec *v1beta2.StackSpec
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,8 @@ import (
|
||||||
"k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// stackClient talks to a kubernetes compose component.
|
// StackClient talks to a kubernetes compose component.
|
||||||
type stackClient interface {
|
type StackClient interface {
|
||||||
CreateOrUpdate(s stack) error
|
CreateOrUpdate(s stack) error
|
||||||
Delete(name string) error
|
Delete(name string) error
|
||||||
Get(name string) (stack, error)
|
Get(name string) (stack, error)
|
||||||
|
@ -29,7 +29,7 @@ type stackV1Beta1 struct {
|
||||||
stacks composev1beta1.StackInterface
|
stacks composev1beta1.StackInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStackV1Beta1(config *rest.Config, namespace string) (stackClient, error) {
|
func newStackV1Beta1(config *rest.Config, namespace string) (StackClient, error) {
|
||||||
client, err := composev1beta1.NewForConfig(config)
|
client, err := composev1beta1.NewForConfig(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -122,7 +122,7 @@ type stackV1Beta2 struct {
|
||||||
stacks composev1beta2.StackInterface
|
stacks composev1beta2.StackInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStackV1Beta2(config *rest.Config, namespace string) (stackClient, error) {
|
func newStackV1Beta2(config *rest.Config, namespace string) (StackClient, error) {
|
||||||
client, err := composev1beta2.NewForConfig(config)
|
client, err := composev1beta2.NewForConfig(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -31,5 +31,7 @@ func newListCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
|
|
||||||
flags := cmd.Flags()
|
flags := cmd.Flags()
|
||||||
flags.StringVar(&opts.Format, "format", "", "Pretty-print stacks using a Go template")
|
flags.StringVar(&opts.Format, "format", "", "Pretty-print stacks using a Go template")
|
||||||
|
flags.BoolVarP(&opts.AllNamespaces, "all-namespaces", "", false, "List stacks among all Kubernetes namespaces")
|
||||||
|
flags.SetAnnotation("all-namespaces", "kubernetes", nil)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,8 @@ type Deploy struct {
|
||||||
|
|
||||||
// List holds docker stack ls options
|
// List holds docker stack ls options
|
||||||
type List struct {
|
type List struct {
|
||||||
Format string
|
Format string
|
||||||
|
AllNamespaces bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// PS holds docker stack ps options
|
// PS holds docker stack ps options
|
||||||
|
|
|
@ -24,12 +24,12 @@ func RunList(dockerCli command.Cli, opts options.List) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
format := opts.Format
|
format := opts.Format
|
||||||
if len(format) == 0 {
|
if format == "" || format == formatter.TableFormatKey {
|
||||||
format = formatter.TableFormatKey
|
format = formatter.SwarmStackTableFormat
|
||||||
}
|
}
|
||||||
stackCtx := formatter.Context{
|
stackCtx := formatter.Context{
|
||||||
Output: dockerCli.Out(),
|
Output: dockerCli.Out(),
|
||||||
Format: formatter.NewStackFormat(format),
|
Format: formatter.Format(format),
|
||||||
}
|
}
|
||||||
sort.Sort(byName(stacks))
|
sort.Sort(byName(stacks))
|
||||||
return formatter.StackWrite(stackCtx, stacks)
|
return formatter.StackWrite(stackCtx, stacks)
|
||||||
|
|
|
@ -228,7 +228,8 @@ func getKubernetesVersion(dockerCli command.Cli, kubeConfig string) *kubernetesV
|
||||||
Kubernetes: "Unknown",
|
Kubernetes: "Unknown",
|
||||||
StackAPI: "Unknown",
|
StackAPI: "Unknown",
|
||||||
}
|
}
|
||||||
config, err := kubernetes.NewKubernetesConfig(kubeConfig)
|
clientConfig := kubernetes.NewKubernetesConfig(kubeConfig)
|
||||||
|
config, err := clientConfig.ClientConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debugf("failed to get Kubernetes configuration: %s", err)
|
logrus.Debugf("failed to get Kubernetes configuration: %s", err)
|
||||||
return &version
|
return &version
|
||||||
|
|
|
@ -55,6 +55,7 @@ Valid placeholders for the Go template are listed below:
|
||||||
| `.Name` | Stack name |
|
| `.Name` | Stack name |
|
||||||
| `.Services` | Number of services |
|
| `.Services` | Number of services |
|
||||||
| `.Orchestrator` | Orchestrator name |
|
| `.Orchestrator` | Orchestrator name |
|
||||||
|
| `.Namespace` | Namespace |
|
||||||
|
|
||||||
When using the `--format` option, the `stack ls` command either outputs
|
When using the `--format` option, the `stack ls` command either outputs
|
||||||
the data exactly as the template declares or, when using the
|
the data exactly as the template declares or, when using the
|
||||||
|
|
|
@ -3,10 +3,10 @@ package clientset
|
||||||
import (
|
import (
|
||||||
composev1beta1 "github.com/docker/cli/kubernetes/client/clientset/typed/compose/v1beta1"
|
composev1beta1 "github.com/docker/cli/kubernetes/client/clientset/typed/compose/v1beta1"
|
||||||
composev1beta2 "github.com/docker/cli/kubernetes/client/clientset/typed/compose/v1beta2"
|
composev1beta2 "github.com/docker/cli/kubernetes/client/clientset/typed/compose/v1beta2"
|
||||||
glog "github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
discovery "k8s.io/client-go/discovery"
|
"k8s.io/client-go/discovery"
|
||||||
rest "k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
flowcontrol "k8s.io/client-go/util/flowcontrol"
|
"k8s.io/client-go/util/flowcontrol"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Interface defines the methods a compose kube client should have
|
// Interface defines the methods a compose kube client should have
|
||||||
|
|
|
@ -3,10 +3,10 @@ package scheme
|
||||||
import (
|
import (
|
||||||
composev1beta1 "github.com/docker/cli/kubernetes/compose/v1beta1"
|
composev1beta1 "github.com/docker/cli/kubernetes/compose/v1beta1"
|
||||||
composev1beta2 "github.com/docker/cli/kubernetes/compose/v1beta2"
|
composev1beta2 "github.com/docker/cli/kubernetes/compose/v1beta2"
|
||||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Variables required for registration
|
// Variables required for registration
|
||||||
|
|
|
@ -2,9 +2,9 @@ package v1beta1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/docker/cli/kubernetes/client/clientset/scheme"
|
"github.com/docker/cli/kubernetes/client/clientset/scheme"
|
||||||
v1beta1 "github.com/docker/cli/kubernetes/compose/v1beta1"
|
"github.com/docker/cli/kubernetes/compose/v1beta1"
|
||||||
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
rest "k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ComposeV1beta1Interface defines the methods a compose v1beta1 client has
|
// ComposeV1beta1Interface defines the methods a compose v1beta1 client has
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package v1beta1
|
package v1beta1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
scheme "github.com/docker/cli/kubernetes/client/clientset/scheme"
|
"github.com/docker/cli/kubernetes/client/clientset/scheme"
|
||||||
v1beta1 "github.com/docker/cli/kubernetes/compose/v1beta1"
|
"github.com/docker/cli/kubernetes/compose/v1beta1"
|
||||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
types "k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
watch "k8s.io/apimachinery/pkg/watch"
|
"k8s.io/apimachinery/pkg/watch"
|
||||||
rest "k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StacksGetter has a method to return a StackInterface.
|
// StacksGetter has a method to return a StackInterface.
|
||||||
|
|
|
@ -2,9 +2,9 @@ package v1beta2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/docker/cli/kubernetes/client/clientset/scheme"
|
"github.com/docker/cli/kubernetes/client/clientset/scheme"
|
||||||
v1beta2 "github.com/docker/cli/kubernetes/compose/v1beta2"
|
"github.com/docker/cli/kubernetes/compose/v1beta2"
|
||||||
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
rest "k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ComposeV1beta2Interface defines the methods a compose v1beta2 client has
|
// ComposeV1beta2Interface defines the methods a compose v1beta2 client has
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package v1beta2
|
package v1beta2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
scheme "github.com/docker/cli/kubernetes/client/clientset/scheme"
|
"github.com/docker/cli/kubernetes/client/clientset/scheme"
|
||||||
v1beta2 "github.com/docker/cli/kubernetes/compose/v1beta2"
|
"github.com/docker/cli/kubernetes/compose/v1beta2"
|
||||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
types "k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
watch "k8s.io/apimachinery/pkg/watch"
|
"k8s.io/apimachinery/pkg/watch"
|
||||||
rest "k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StacksGetter has a method to return a StackInterface.
|
// StacksGetter has a method to return a StackInterface.
|
||||||
|
|
|
@ -5,14 +5,13 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/docker/docker/pkg/homedir"
|
"github.com/docker/docker/pkg/homedir"
|
||||||
restclient "k8s.io/client-go/rest"
|
|
||||||
"k8s.io/client-go/tools/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewKubernetesConfig resolves the path to the desired Kubernetes configuration file, depending
|
// NewKubernetesConfig resolves the path to the desired Kubernetes configuration file based on
|
||||||
// environment variable and command line flag.
|
// the KUBECONFIG environment variable and command line flags.
|
||||||
func NewKubernetesConfig(configFlag string) (*restclient.Config, error) {
|
func NewKubernetesConfig(configPath string) clientcmd.ClientConfig {
|
||||||
kubeConfig := configFlag
|
kubeConfig := configPath
|
||||||
if kubeConfig == "" {
|
if kubeConfig == "" {
|
||||||
if config := os.Getenv("KUBECONFIG"); config != "" {
|
if config := os.Getenv("KUBECONFIG"); config != "" {
|
||||||
kubeConfig = config
|
kubeConfig = config
|
||||||
|
@ -20,5 +19,8 @@ func NewKubernetesConfig(configFlag string) (*restclient.Config, error) {
|
||||||
kubeConfig = filepath.Join(homedir.Get(), ".kube/config")
|
kubeConfig = filepath.Join(homedir.Get(), ".kube/config")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return clientcmd.BuildConfigFromFlags("", kubeConfig)
|
|
||||||
|
return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
|
||||||
|
&clientcmd.ClientConfigLoadingRules{ExplicitPath: kubeConfig},
|
||||||
|
&clientcmd.ConfigOverrides{})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue