github.com/AliyunContainerService/cli@v0.0.0-20181009023821-814ced4b30d0/cli/command/stack/kubernetes/cli.go (about)

     1  package kubernetes
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"net/url"
     7  	"os"
     8  
     9  	"github.com/docker/cli/cli/command"
    10  	"github.com/docker/cli/kubernetes"
    11  	cliv1beta1 "github.com/docker/cli/kubernetes/client/clientset/typed/compose/v1beta1"
    12  	"github.com/pkg/errors"
    13  	flag "github.com/spf13/pflag"
    14  	kubeclient "k8s.io/client-go/kubernetes"
    15  	restclient "k8s.io/client-go/rest"
    16  )
    17  
    18  // KubeCli holds kubernetes specifics (client, namespace) with the command.Cli
    19  type KubeCli struct {
    20  	command.Cli
    21  	kubeConfig    *restclient.Config
    22  	kubeNamespace string
    23  	clientSet     *kubeclient.Clientset
    24  }
    25  
    26  // Options contains resolved parameters to initialize kubernetes clients
    27  type Options struct {
    28  	Namespace    string
    29  	Config       string
    30  	Orchestrator command.Orchestrator
    31  }
    32  
    33  // NewOptions returns an Options initialized with command line flags
    34  func NewOptions(flags *flag.FlagSet, orchestrator command.Orchestrator) Options {
    35  	opts := Options{
    36  		Orchestrator: orchestrator,
    37  	}
    38  	if namespace, err := flags.GetString("namespace"); err == nil {
    39  		opts.Namespace = namespace
    40  	}
    41  	if kubeConfig, err := flags.GetString("kubeconfig"); err == nil {
    42  		opts.Config = kubeConfig
    43  	}
    44  	return opts
    45  }
    46  
    47  // AddNamespaceFlag adds the namespace flag to the given flag set
    48  func AddNamespaceFlag(flags *flag.FlagSet) {
    49  	flags.String("namespace", "", "Kubernetes namespace to use")
    50  	flags.SetAnnotation("namespace", "kubernetes", nil)
    51  }
    52  
    53  // WrapCli wraps command.Cli with kubernetes specifics
    54  func WrapCli(dockerCli command.Cli, opts Options) (*KubeCli, error) {
    55  	cli := &KubeCli{
    56  		Cli: dockerCli,
    57  	}
    58  	clientConfig := kubernetes.NewKubernetesConfig(opts.Config)
    59  
    60  	cli.kubeNamespace = opts.Namespace
    61  	if opts.Namespace == "" {
    62  		configNamespace, _, err := clientConfig.Namespace()
    63  		switch {
    64  		case os.IsNotExist(err), os.IsPermission(err):
    65  			return nil, errors.Wrap(err, "unable to load configuration file")
    66  		case err != nil:
    67  			return nil, err
    68  		}
    69  		cli.kubeNamespace = configNamespace
    70  	}
    71  
    72  	config, err := clientConfig.ClientConfig()
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  	cli.kubeConfig = config
    77  
    78  	clientSet, err := kubeclient.NewForConfig(config)
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  	cli.clientSet = clientSet
    83  
    84  	if opts.Orchestrator.HasAll() {
    85  		if err := cli.checkHostsMatch(); err != nil {
    86  			return nil, err
    87  		}
    88  	}
    89  	return cli, nil
    90  }
    91  
    92  func (c *KubeCli) composeClient() (*Factory, error) {
    93  	return NewFactory(c.kubeNamespace, c.kubeConfig, c.clientSet)
    94  }
    95  
    96  func (c *KubeCli) checkHostsMatch() error {
    97  	daemonEndpoint, err := url.Parse(c.Client().DaemonHost())
    98  	if err != nil {
    99  		return err
   100  	}
   101  	kubeEndpoint, err := url.Parse(c.kubeConfig.Host)
   102  	if err != nil {
   103  		return err
   104  	}
   105  	if daemonEndpoint.Hostname() == kubeEndpoint.Hostname() {
   106  		return nil
   107  	}
   108  	// The daemon can be local in Docker for Desktop, e.g. "npipe", "unix", ...
   109  	if daemonEndpoint.Scheme != "tcp" {
   110  		ips, err := net.LookupIP(kubeEndpoint.Hostname())
   111  		if err != nil {
   112  			return err
   113  		}
   114  		for _, ip := range ips {
   115  			if ip.IsLoopback() {
   116  				return nil
   117  			}
   118  		}
   119  	}
   120  	fmt.Fprintf(c.Err(), "WARNING: Swarm and Kubernetes hosts do not match (docker host=%s, kubernetes host=%s).\n"+
   121  		"         Update $DOCKER_HOST (or pass -H), or use 'kubectl config use-context' to match.\n", daemonEndpoint.Hostname(), kubeEndpoint.Hostname())
   122  	return nil
   123  }
   124  
   125  func (c *KubeCli) stacksv1beta1() (cliv1beta1.StackInterface, error) {
   126  	raw, err := newStackV1Beta1(c.kubeConfig, c.kubeNamespace)
   127  	if err != nil {
   128  		return nil, err
   129  	}
   130  	return raw.stacks, nil
   131  }