Merge pull request #991 from silvin-lubecki/kubernetes-namespace

Better namespace experience with Kubernetes
This commit is contained in:
Sebastiaan van Stijn 2018-05-09 21:18:50 +02:00 committed by GitHub
commit 552ee502f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 141 additions and 108 deletions

View File

@ -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
}

View File

@ -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("")

View File

@ -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")

View 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")
}
} }

View File

@ -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")
}
}

View File

@ -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,
} }
} }

View File

@ -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
} }

View File

@ -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

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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

View File

@ -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
} }

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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.

View File

@ -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{})
} }