diff --git a/cmd/root.go b/cmd/root.go index af8b85680..a83551f3f 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -11,18 +11,15 @@ import ( "github.com/ian-howell/airshipctl/pkg/log" ) - // NewRootCmd creates the root `airshipctl` command. All other commands are // subcommands branching from this one -func NewRootCmd(out io.Writer, args []string) (*cobra.Command, error) { +func NewRootCmd(out io.Writer, settings *environment.AirshipCTLSettings, args []string) (*cobra.Command, error) { rootCmd := &cobra.Command{ Use: "airshipctl", Short: "airshipctl is a unified entrypoint to various airship components", } rootCmd.SetOutput(out) - // Settings flags - This section should probably be moved to pkg/environment - settings := &environment.AirshipCTLSettings{} settings.InitFlags(rootCmd) rootCmd.AddCommand(NewVersionCommand(out)) @@ -31,15 +28,15 @@ func NewRootCmd(out io.Writer, args []string) (*cobra.Command, error) { rootCmd.PersistentFlags().Parse(args) + settings.InitDefaults() log.Init(settings, out) - return rootCmd, nil } // Execute runs the base airshipctl command func Execute(out io.Writer) { - rootCmd, err := NewRootCmd(out, os.Args[1:]) + rootCmd, err := NewRootCmd(out, &environment.AirshipCTLSettings{}, os.Args[1:]) if err != nil { fmt.Fprintln(out, err) os.Exit(1) diff --git a/cmd/workflow/workflow_init.go b/cmd/workflow/workflow_init.go index b60976400..f5e4c9c50 100644 --- a/cmd/workflow/workflow_init.go +++ b/cmd/workflow/workflow_init.go @@ -5,16 +5,15 @@ import ( "io" "github.com/spf13/cobra" + v1beta2 "k8s.io/api/apps/v1beta2" v1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" apixv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" apixv1beta1client "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1beta1" - v1beta2 "k8s.io/api/apps/v1beta2" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" "github.com/ian-howell/airshipctl/pkg/environment" ) @@ -30,37 +29,22 @@ var ( type workflowInitCmd struct { out io.Writer config *rest.Config - kubeclient *kubernetes.Clientset + kubeclient kubernetes.Interface } // NewWorkflowInitCommand is a command for bootstrapping a kubernetes cluster with the necessary components for Argo workflows func NewWorkflowInitCommand(out io.Writer, settings *environment.AirshipCTLSettings, args []string) *cobra.Command { workflowInit := &workflowInitCmd{ - out: out, + out: out, + config: settings.KubeConfig, + kubeclient: settings.KubeClient, } workflowInitCommand := &cobra.Command{ Use: "init [flags]", Short: "bootstraps the kubernetes cluster with the Workflow CRDs and controller", Run: func(cmd *cobra.Command, args []string) { - if settings.KubeConfigFilePath == "" { - settings.KubeConfigFilePath = clientcmd.RecommendedHomeFile - } - config, err := clientcmd.BuildConfigFromFlags("", settings.KubeConfigFilePath) - if err != nil { - fmt.Fprintf(out, "Could not create kubernetes config: %s\n", err.Error()) - return - } - workflowInit.config = config - - kubeclient, err := kubernetes.NewForConfig(config) - if err != nil { - fmt.Fprintf(out, "Could not create kubernetes clientset: %s\n", err.Error()) - return - } - workflowInit.kubeclient = kubeclient - fmt.Fprintf(out, "Creating namespace \"%s\"\n", argoNamespace) - _, err = kubeclient.CoreV1().Namespaces().Create(&v1.Namespace{ + _, err := workflowInit.kubeclient.CoreV1().Namespaces().Create(&v1.Namespace{ ObjectMeta: metav1.ObjectMeta{Name: "argo"}, }) if err != nil { @@ -383,13 +367,13 @@ func (wfInit *workflowInitCmd) createArgoClusterRoleBinding() error { ObjectMeta: metav1.ObjectMeta{Name: "argo-binding"}, RoleRef: rbacv1.RoleRef{ APIGroup: "rbac.authorization.k8s.io", - Kind: "ClusterRole", - Name: "argo-cluster-role", + Kind: "ClusterRole", + Name: "argo-cluster-role", }, Subjects: []rbacv1.Subject{ { - Kind: "ServiceAccount", - Name: "argo", + Kind: "ServiceAccount", + Name: "argo", Namespace: argoNamespace, }, }, @@ -401,7 +385,7 @@ func (wfInit *workflowInitCmd) createArgoClusterRoleBinding() error { func (wfInit *workflowInitCmd) createArgoConfigMap() error { _, err := wfInit.kubeclient.CoreV1().ConfigMaps(argoNamespace).Create(&v1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ - Name: "workflow-controller-configmap", + Name: "workflow-controller-configmap", Namespace: argoNamespace, }, }) @@ -411,7 +395,7 @@ func (wfInit *workflowInitCmd) createArgoConfigMap() error { func (wfInit *workflowInitCmd) createArgoDeployment() error { _, err := wfInit.kubeclient.AppsV1beta2().Deployments(argoNamespace).Create(&v1beta2.Deployment{ ObjectMeta: metav1.ObjectMeta{ - Name: "workflow-controller", + Name: "workflow-controller", Namespace: argoNamespace, }, Spec: v1beta2.DeploymentSpec{ @@ -436,10 +420,10 @@ func (wfInit *workflowInitCmd) createArgoDeployment() error { "--configmap", "workflow-controller-configmap", "--executor-image", - "argoproj/argoexec:v2.2.1", // TODO(howell): Remove this hardcoded value + "argoproj/argoexec:v2.2.1", // TODO(howell): Remove this hardcoded value }, - Image: "argoproj/argoexec:v2.2.1", // TODO(howell): Remove this hardcoded value - Name: "workflow-controller", + Image: "argoproj/argoexec:v2.2.1", // TODO(howell): Remove this hardcoded value + Name: "workflow-controller", }, }, ServiceAccountName: "argo", diff --git a/cmd/workflow/workflow_list.go b/cmd/workflow/workflow_list.go index 827e7a86a..97eaf4719 100644 --- a/cmd/workflow/workflow_list.go +++ b/cmd/workflow/workflow_list.go @@ -8,7 +8,6 @@ import ( "github.com/argoproj/argo/pkg/client/clientset/versioned/typed/workflow/v1alpha1" "github.com/spf13/cobra" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/tools/clientcmd" "github.com/ian-howell/airshipctl/pkg/environment" ) @@ -20,15 +19,7 @@ func NewWorkflowListCommand(out io.Writer, settings *environment.AirshipCTLSetti Short: "list workflows", Aliases: []string{"ls"}, Run: func(cmd *cobra.Command, args []string) { - if settings.KubeConfigFilePath == "" { - settings.KubeConfigFilePath = clientcmd.RecommendedHomeFile - } - config, err := clientcmd.BuildConfigFromFlags("", settings.KubeConfigFilePath) - if err != nil { - panic(err.Error()) - } - - clientSet, err := v1alpha1.NewForConfig(config) + clientSet, err := v1alpha1.NewForConfig(settings.KubeConfig) if err != nil { panic(err.Error()) } diff --git a/go.sum b/go.sum index 6250a0f8a..4b1db7586 100644 --- a/go.sum +++ b/go.sum @@ -22,8 +22,10 @@ github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfc github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v0.0.0-20160705203006-01aeca54ebda/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0 h1:w3NnFcKR5241cfmQU5ZZAsf0xcpId6mWOupTvJlUX2U= github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= @@ -33,6 +35,7 @@ github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550 h1:mV9jbLoSW/8m github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v0.0.0-20180820084758-c7ce16629ff4 h1:bRzFpEzvausOAt4va+I/22BZ1vXDtERngp0BNYDKej0= github.com/ghodss/yaml v0.0.0-20180820084758-c7ce16629ff4/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= @@ -68,10 +71,12 @@ github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5 github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 h1:LbsanbbD6LieFkXbj9YNNBupiGHJgFeLpO0j0Fza1h8= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/btree v0.0.0-20160524151835-7d79101e329e h1:JHB7F/4TJCrYBW8+GZO8VkWDj1jxcWuCl6uxKODiyi4= github.com/google/btree v0.0.0-20160524151835-7d79101e329e/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -84,10 +89,12 @@ github.com/googleapis/gnostic v0.2.0 h1:l6N3VoaVzTncYYW+9yOz2LJJammFZGBO13sqgEhp github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/gophercloud/gophercloud v0.0.0-20190126172459-c818fa66e4c8/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7 h1:6TSoaYExHper8PYsJu23GWVNOyYRCSnIFyxKgLSZ54w= github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v0.0.0-20170330212424-2500245aa611/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.3.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -218,6 +225,7 @@ gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/natefinch/lumberjack.v2 v2.0.0-20150622162204-20b71e5b60d7/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/square/go-jose.v2 v2.0.0-20180411045311-89060dee6a84 h1:ELQJ5WuT+ydETLCpWvAuw8iGBQRGoJq+A3RAbbAcZUY= gopkg.in/square/go-jose.v2 v2.0.0-20180411045311-89060dee6a84/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= @@ -231,10 +239,12 @@ k8s.io/apiextensions-apiserver v0.0.0-20190515024537-2fd0e9006049 h1:nVYyNZl5lEe k8s.io/apiextensions-apiserver v0.0.0-20190515024537-2fd0e9006049/go.mod h1:yMQkVi5Qu0vmH4rNmnVu6v5kf1GnPj8+6TJG+he4+kw= k8s.io/apimachinery v0.0.0-20190515023456-b74e4c97951f h1:cBrF1gFrJrvimOHZzyEHrvtlfqPV+KM7QZt3M0mepEg= k8s.io/apimachinery v0.0.0-20190515023456-b74e4c97951f/go.mod h1:Ew3b/24/JSgJdn4RsnrLskv3LvMZDlZ1Fl1xopsJftY= +k8s.io/apiserver v0.0.0-20190515024203-a3c8296cef8c h1:JGoLJ099gxINHqgaFsMe+r2jM0fUOoz0GFPehb8QhGc= k8s.io/apiserver v0.0.0-20190515024203-a3c8296cef8c/go.mod h1:c9qwKQexUHQq1ALDC7vAgSXOVXAFkGil5ZQWdqr3RhI= k8s.io/client-go v0.0.0-20190515023709-78e94f51a042 h1:CkYQkY7TSQK/rDLm8Bit9fvvJJl3p1C5Dk+swSRz1m0= k8s.io/client-go v0.0.0-20190515023709-78e94f51a042/go.mod h1:Ucfy225uJpWBtWGDwTtqUZmmgR/AzYM0vge2iB/bTQ4= k8s.io/code-generator v0.0.0-20190511023357-639c964206c2/go.mod h1:YMQ7Lt97nW/I6nHACDccgS/sPAyrHQNans96RwPaSb8= +k8s.io/component-base v0.0.0-20190515024022-2354f2393ad4 h1:TOebDR8jh/AcqOEWnotJ+DYVUNcMA1GT86TR4Bg70KQ= k8s.io/component-base v0.0.0-20190515024022-2354f2393ad4/go.mod h1:pKRi1i5IQdJDpK1LItot8oy27Bc3zL/hQiy9T171rvE= k8s.io/gengo v0.0.0-20190116091435-f8a0810f38af/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog v0.3.0 h1:0VPpR+sizsiivjIfIAQH/rl8tan6jvWkS7lU+0di3lE= diff --git a/pkg/environment/settings.go b/pkg/environment/settings.go index f5cecbf8d..370560982 100644 --- a/pkg/environment/settings.go +++ b/pkg/environment/settings.go @@ -1,9 +1,10 @@ package environment import ( - restclient "k8s.io/client-go/rest" - "github.com/spf13/cobra" + "k8s.io/client-go/kubernetes" + restclient "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" ) // AirshipCTLSettings is a container for all of the settings needed by airshipctl @@ -17,6 +18,9 @@ type AirshipCTLSettings struct { // with the cluster KubeConfig *restclient.Config + // KubeClient contains a kubernetes clientset + KubeClient kubernetes.Interface + // Namespace is the kubernetes namespace to be used during the context of this action Namespace string @@ -31,3 +35,26 @@ func (a *AirshipCTLSettings) InitFlags(cmd *cobra.Command) { flags.StringVar(&a.KubeConfigFilePath, "kubeconfig", "", "path to kubeconfig") flags.StringVar(&a.Namespace, "namespace", "default", "kubernetes namespace to use for the context of this command") } + +// InitDefaults assigns default values for any value that has not been previously set +func (a *AirshipCTLSettings) InitDefaults() error { + if a.KubeConfigFilePath == "" { + a.KubeConfigFilePath = clientcmd.RecommendedHomeFile + } + + var err error + if a.KubeConfig == nil { + a.KubeConfig, err = clientcmd.BuildConfigFromFlags("", a.KubeConfigFilePath) + if err != nil { + return err + } + } + + if a.KubeClient == nil { + a.KubeClient, err = kubernetes.NewForConfig(a.KubeConfig) + if err != nil { + return err + } + } + return nil +} diff --git a/pkg/kube/clientset.go b/pkg/kube/clientset.go deleted file mode 100644 index 9e20490d3..000000000 --- a/pkg/kube/clientset.go +++ /dev/null @@ -1,45 +0,0 @@ -package kube - -import ( - "errors" - "os" - "path/filepath" - - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/tools/clientcmd" - - "github.com/ian-howell/airshipctl/pkg/util" -) - -// Client is a device which communicates with the Kubernetes API -type Client struct { - kubernetes.Interface -} - -// NewForConfig creates a kubernetes client using the config at $HOME/.kube/config -func NewForConfig(kubeconfigFilepath string) (*Client, error) { - if kubeconfigFilepath == "" { - home, err := os.UserHomeDir() - if err != nil { - return nil, errors.New("could not find kubernetes config file: " + err.Error()) - } - kubeconfigFilepath = filepath.Join(home, ".kube", "config") - } - - if err := util.IsReadable(kubeconfigFilepath); err != nil { - return nil, errors.New("could not open " + kubeconfigFilepath + ": " + err.Error()) - } - - // use the current context in kubeconfigFilepath - config, err := clientcmd.BuildConfigFromFlags("", kubeconfigFilepath) - if err != nil { - return nil, errors.New("could not build kubernetes config: " + err.Error()) - } - - // create the clientset - clientset, err := kubernetes.NewForConfig(config) - if err != nil { - return nil, err - } - return &Client{clientset}, nil -}