diff --git a/cmd/generate.go b/cmd/generate.go index 0502bfa..11dcbf2 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -5,10 +5,10 @@ import ( "os" "github.com/spf13/cobra" - "github.com/thecasualcoder/kube-tmuxp/pkg/commander" - "github.com/thecasualcoder/kube-tmuxp/pkg/filesystem" - "github.com/thecasualcoder/kube-tmuxp/pkg/kubeconfig" - "github.com/thecasualcoder/kube-tmuxp/pkg/kubetmuxp" + "github.com/jfreeland/kube-tmuxp/pkg/commander" + "github.com/jfreeland/kube-tmuxp/pkg/filesystem" + "github.com/jfreeland/kube-tmuxp/pkg/kubeconfig" + "github.com/jfreeland/kube-tmuxp/pkg/kubetmuxp" ) var generateCmd = &cobra.Command{ diff --git a/config.sample.yaml b/config.sample.yaml index 98c6956..adbafc8 100644 --- a/config.sample.yaml +++ b/config.sample.yaml @@ -1,10 +1,24 @@ projects: - name: gcp-project-id + provider: gke clusters: - name: gke-cluster-name zone: zone # for zonal GKE clusters region: region # for regional GKE clusters context: name-to-be-used-for-this-context - envs: + tmux_envs: + ENV_VARIABLE: value + provider_envs: + ENV_VARIABLE: value + - name: aws-project-id + provider: eks + clusters: + - name: eks-cluster-name + region: region + context: name-to-be-used-for-this-context + tmux_envs: + AWS_PROFILE: profile-to-use-in-tmux + ENV_VARIABLE: value + provider_envs: + AWS_PROFILE: profile-to-use-to-config-kubectl ENV_VARIABLE: value - diff --git a/go.mod b/go.mod index f001d5c..3c1eee2 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/thecasualcoder/kube-tmuxp +module github.com/jfreeland/kube-tmuxp go 1.13 @@ -8,5 +8,6 @@ require ( github.com/spf13/cobra v0.0.5 github.com/spf13/viper v1.5.0 github.com/stretchr/testify v1.2.2 + github.com/thecasualcoder/kube-tmuxp v0.2.6 // indirect gopkg.in/yaml.v2 v2.2.7 ) diff --git a/go.sum b/go.sum index c36ecfb..98fc240 100644 --- a/go.sum +++ b/go.sum @@ -100,6 +100,8 @@ github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/thecasualcoder/kube-tmuxp v0.2.6 h1:6mdNJ5aCoo2m/nkNcTCpEHaPqv5aHCo/ruiqWH1iQ7s= +github.com/thecasualcoder/kube-tmuxp v0.2.6/go.mod h1:zdbqLwPvGa0KQU+55ccIbW1T1SxpQWdrZHXyR1xg9nQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= diff --git a/main.go b/main.go index c6c67c8..b06909a 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,6 @@ package main -import "github.com/thecasualcoder/kube-tmuxp/cmd" +import "github.com/jfreeland/kube-tmuxp/cmd" var version string diff --git a/pkg/commander/commander_test.go b/pkg/commander/commander_test.go index 2445de3..c7d23f3 100644 --- a/pkg/commander/commander_test.go +++ b/pkg/commander/commander_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/thecasualcoder/kube-tmuxp/pkg/commander" + "github.com/jfreeland/kube-tmuxp/pkg/commander" ) func TestExecute(t *testing.T) { diff --git a/pkg/kubeconfig/kubeconfig.go b/pkg/kubeconfig/kubeconfig.go index 89b00c9..cba933b 100644 --- a/pkg/kubeconfig/kubeconfig.go +++ b/pkg/kubeconfig/kubeconfig.go @@ -5,8 +5,8 @@ import ( "os" "path" - "github.com/thecasualcoder/kube-tmuxp/pkg/commander" - "github.com/thecasualcoder/kube-tmuxp/pkg/filesystem" + "github.com/jfreeland/kube-tmuxp/pkg/commander" + "github.com/jfreeland/kube-tmuxp/pkg/filesystem" ) // KubeConfig exposes methods to perform actions on kubeconfig @@ -25,11 +25,54 @@ func (k *KubeConfig) Delete(kubeCfgFile string) error { return nil } -// AddRegionalCluster imports Kubernetes context for +// AddRegionalEKSCluster imports Kubernetes context for a regional EKS cluster +func (k *KubeConfig) AddRegionalEKSCluster(cluster string, region string, role string, env map[string]string, kubeCfgFile string) error { + var args []string + if len(role) > 0 { + args = []string{ + "eks", + "update-kubeconfig", + "--name", + cluster, + "--kubeconfig", + kubeCfgFile, + "--region", + region, + "--role-arn", + role, + } + } else { + args = []string{ + "eks", + "update-kubeconfig", + "--name", + cluster, + "--kubeconfig", + kubeCfgFile, + "--region", + region, + } + } + + envs := []string{} + for k, v := range env { + envs = append(envs, k+"="+v) + } + if _, err := k.commander.Execute("aws", args, envs); err != nil { + return err + } + + return nil +} + +// AddRegionalGKECluster imports Kubernetes context for // a regional Kubernetes cluster -func (k *KubeConfig) AddRegionalCluster(project string, cluster string, region string, kubeCfgFile string) error { +func (k *KubeConfig) AddRegionalGKECluster(project string, cluster string, region string, kubeCfgFile string) error { args := []string{ "beta", + // Is beta needed here? You can run into an issue where if + // you haven't updated gcloud lately, beta will stop and + // report that it needs updated, but gcloud itself will not. "container", "clusters", "get-credentials", @@ -47,9 +90,9 @@ func (k *KubeConfig) AddRegionalCluster(project string, cluster string, region s return nil } -// AddZonalCluster imports Kubernetes context for +// AddZonalGKECluster imports Kubernetes context for // a zonal Kubernetes cluster -func (k *KubeConfig) AddZonalCluster(project string, cluster string, zone string, kubeCfgFile string) error { +func (k *KubeConfig) AddZonalGKECluster(project string, cluster string, zone string, kubeCfgFile string) error { args := []string{ "container", "clusters", diff --git a/pkg/kubeconfig/kubeconfig_test.go b/pkg/kubeconfig/kubeconfig_test.go index 9705489..1124f06 100644 --- a/pkg/kubeconfig/kubeconfig_test.go +++ b/pkg/kubeconfig/kubeconfig_test.go @@ -7,8 +7,8 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" - "github.com/thecasualcoder/kube-tmuxp/pkg/internal/mock" - "github.com/thecasualcoder/kube-tmuxp/pkg/kubeconfig" + "github.com/jfreeland/kube-tmuxp/pkg/internal/mock" + "github.com/jfreeland/kube-tmuxp/pkg/kubeconfig" ) func TestNew(t *testing.T) { @@ -86,7 +86,7 @@ func TestDelete(t *testing.T) { }) } -func TestAddRegionalCluster(t *testing.T) { +func TestAddRegionalGKECluster(t *testing.T) { t.Run("should invoke command for adding regional cluster", func(*testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() @@ -110,7 +110,7 @@ func TestAddRegionalCluster(t *testing.T) { mockCmdr.EXPECT().Execute("gcloud", args, envs).Return("Context added successfully", nil) kubeCfg, _ := kubeconfig.New(mockFS, mockCmdr) - err := kubeCfg.AddRegionalCluster("test-project", "test-cluster", "test-region", "/Users/test/.kube/configs/test-context") + err := kubeCfg.AddRegionalGKECluster("test-project", "test-cluster", "test-region", "/Users/test/.kube/configs/test-context") assert.Nil(t, err) }) @@ -138,13 +138,13 @@ func TestAddRegionalCluster(t *testing.T) { mockCmdr.EXPECT().Execute("gcloud", args, envs).Return("", fmt.Errorf("some error")) kubeCfg, _ := kubeconfig.New(mockFS, mockCmdr) - err := kubeCfg.AddRegionalCluster("test-project", "test-cluster", "test-region", "/Users/test/.kube/configs/test-context") + err := kubeCfg.AddRegionalGKECluster("test-project", "test-cluster", "test-region", "/Users/test/.kube/configs/test-context") assert.EqualError(t, err, "some error") }) } -func TestAddZonalCluster(t *testing.T) { +func TestAddZonalGKECluster(t *testing.T) { t.Run("should invoke command for adding zonal cluster", func(*testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() @@ -167,7 +167,7 @@ func TestAddZonalCluster(t *testing.T) { mockCmdr.EXPECT().Execute("gcloud", args, envs).Return("Context added successfully", nil) kubeCfg, _ := kubeconfig.New(mockFS, mockCmdr) - err := kubeCfg.AddZonalCluster("test-project", "test-cluster", "test-zone", "/Users/test/.kube/configs/test-context") + err := kubeCfg.AddZonalGKECluster("test-project", "test-cluster", "test-zone", "/Users/test/.kube/configs/test-context") assert.Nil(t, err) }) @@ -194,7 +194,7 @@ func TestAddZonalCluster(t *testing.T) { mockCmdr.EXPECT().Execute("gcloud", args, envs).Return("", fmt.Errorf("some error")) kubeCfg, _ := kubeconfig.New(mockFS, mockCmdr) - err := kubeCfg.AddZonalCluster("test-project", "test-cluster", "test-zone", "/Users/test/.kube/configs/test-context") + err := kubeCfg.AddZonalGKECluster("test-project", "test-cluster", "test-zone", "/Users/test/.kube/configs/test-context") assert.EqualError(t, err, "some error") }) diff --git a/pkg/kubetmuxp/kubetmuxp.go b/pkg/kubetmuxp/kubetmuxp.go index 296f3a0..f5d46ed 100644 --- a/pkg/kubetmuxp/kubetmuxp.go +++ b/pkg/kubetmuxp/kubetmuxp.go @@ -5,26 +5,39 @@ import ( "io/ioutil" "path" - "github.com/thecasualcoder/kube-tmuxp/pkg/filesystem" - "github.com/thecasualcoder/kube-tmuxp/pkg/kubeconfig" - "github.com/thecasualcoder/kube-tmuxp/pkg/tmuxp" + "github.com/jfreeland/kube-tmuxp/pkg/filesystem" + "github.com/jfreeland/kube-tmuxp/pkg/kubeconfig" + "github.com/jfreeland/kube-tmuxp/pkg/tmuxp" yamlV2 "gopkg.in/yaml.v2" ) -// Envs reprensents environemnt variables -type Envs map[string]string +// Role represents a Role ARN required to connect to an EKS cluster +type Role string + +// ProviderEnvs represents environment variables for the provider +type ProviderEnvs map[string]string + +// Envs reprensents environemnt variables for Tmux +type TmuxEnvs map[string]string //Cluster represents a Kubernetes cluster type Cluster struct { - Name string `yaml:"name"` - Zone string `yaml:"zone"` - Region string `yaml:"region"` - Context string `yaml:"context"` - Envs `yaml:"envs"` + Name string `yaml:"name"` + Zone string `yaml:"zone"` + Region string `yaml:"region"` + Context string `yaml:"context"` + Role string `yaml:"role"` + TmuxEnvs `yaml:"tmux_envs"` + ProviderEnvs `yaml:"provider_envs"` +} + +// DefaultEKSContextName returns default context name for EKS +func (c *Cluster) DefaultEKSContextName(project string) (string, error) { + return fmt.Sprintf("arn:aws:eks:%s:%s:cluster/%s", c.Region, project, c.Name), nil } -// DefaultContextName returns default context name -func (c *Cluster) DefaultContextName(project string) (string, error) { +// DefaultGKEContextName returns default context name for GKE +func (c *Cluster) DefaultGKEContextName(project string) (string, error) { if regional, err := c.IsRegional(); err != nil { return "", err } else if regional { @@ -52,6 +65,7 @@ type Clusters []Cluster //Project represents a cloud project type Project struct { + Provider string `yaml:"provider"` Name string `yaml:"name"` Clusters `yaml:"clusters"` } @@ -88,7 +102,7 @@ func (c *Config) load(cfgFile string) error { func (c *Config) saveTmuxpConfig(kubeCfgFile string, cluster Cluster) error { windows := tmuxp.Windows{{Name: "default"}} env := tmuxp.Environment{"KUBECONFIG": kubeCfgFile} - for k, v := range cluster.Envs { + for k, v := range cluster.TmuxEnvs { env[k] = v } @@ -111,6 +125,10 @@ func (c *Config) Process() error { for _, cluster := range project.Clusters { kubeCfgFile := path.Join(kubeCfgsDir, cluster.Context) + if project.Provider == "" { + project.Provider = "gke" + } + fmt.Printf("Provider: %s\n", project.Provider) fmt.Printf("Cluster: %s\n", cluster.Name) fmt.Println("Deleting exisiting context...") if err := c.kubeCfg.Delete(kubeCfgFile); err != nil { @@ -118,24 +136,44 @@ func (c *Config) Process() error { } fmt.Println("Adding context...") - if regional, err := cluster.IsRegional(); err != nil { - return err - } else if regional { - if err := c.kubeCfg.AddRegionalCluster(project.Name, cluster.Name, cluster.Region, kubeCfgFile); err != nil { + if project.Provider == "gke" { + if regional, err := cluster.IsRegional(); err != nil { return err + } else if regional { + if err := c.kubeCfg.AddRegionalGKECluster(project.Name, cluster.Name, cluster.Region, kubeCfgFile); err != nil { + return err + } + } else { + if err := c.kubeCfg.AddZonalGKECluster(project.Name, cluster.Name, cluster.Zone, kubeCfgFile); err != nil { + return err + } } - } else { - if err := c.kubeCfg.AddZonalCluster(project.Name, cluster.Name, cluster.Zone, kubeCfgFile); err != nil { + } else if project.Provider == "eks" { + if regional, err := cluster.IsRegional(); err != nil { return err + } else if regional { + if err := c.kubeCfg.AddRegionalEKSCluster(cluster.Name, cluster.Region, cluster.Role, cluster.ProviderEnvs, kubeCfgFile); err != nil { + return err + } } + } else { + return fmt.Errorf("Provider must be gke or eks") } fmt.Println("Renaming context...") - defaultCtxName, err := cluster.DefaultContextName(project.Name) - if err != nil { - return err + if project.Provider == "gke" { + defaultCtxName, err := cluster.DefaultGKEContextName(project.Name) + if err != nil { + return err + } + c.kubeCfg.RenameContext(defaultCtxName, cluster.Context, kubeCfgFile) + } else if project.Provider == "eks" { + defaultCtxName, err := cluster.DefaultEKSContextName(project.Name) + if err != nil { + return err + } + c.kubeCfg.RenameContext(defaultCtxName, cluster.Context, kubeCfgFile) } - c.kubeCfg.RenameContext(defaultCtxName, cluster.Context, kubeCfgFile) fmt.Println("Creating tmuxp config...") c.saveTmuxpConfig(kubeCfgFile, cluster) diff --git a/pkg/kubetmuxp/kubetmuxp_test.go b/pkg/kubetmuxp/kubetmuxp_test.go index d3ccd0d..eab480b 100644 --- a/pkg/kubetmuxp/kubetmuxp_test.go +++ b/pkg/kubetmuxp/kubetmuxp_test.go @@ -7,9 +7,9 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" - "github.com/thecasualcoder/kube-tmuxp/pkg/internal/mock" - "github.com/thecasualcoder/kube-tmuxp/pkg/kubeconfig" - "github.com/thecasualcoder/kube-tmuxp/pkg/kubetmuxp" + "github.com/jfreeland/kube-tmuxp/pkg/internal/mock" + "github.com/jfreeland/kube-tmuxp/pkg/kubeconfig" + "github.com/jfreeland/kube-tmuxp/pkg/kubetmuxp" ) func getKubeCfg(ctrl *gomock.Controller) kubeconfig.KubeConfig { @@ -60,7 +60,7 @@ projects: zone: test-zone region: test-region context: test-ctx - envs: + tmux_envs: TEST_ENV: test-value` reader := strings.NewReader(content) mockFS.EXPECT().Open("kube-tmuxp-config.yaml").Return(reader, nil) @@ -75,7 +75,7 @@ projects: Zone: "test-zone", Region: "test-region", Context: "test-ctx", - Envs: kubetmuxp.Envs{ + TmuxEnvs: kubetmuxp.TmuxEnvs{ "TEST_ENV": "test-value", }, }, @@ -144,7 +144,7 @@ func TestGeneratedContextName(t *testing.T) { Region: "test-region", } - name, err := cluster.DefaultContextName("test-project") + name, err := cluster.DefaultGKEContextName("test-project") assert.Nil(t, err) assert.Equal(t, "gke_test-project_test-region_test-cluster", name) @@ -156,7 +156,7 @@ func TestGeneratedContextName(t *testing.T) { Zone: "test-zone", } - name, err := cluster.DefaultContextName("test-project") + name, err := cluster.DefaultGKEContextName("test-project") assert.Nil(t, err) assert.Equal(t, "gke_test-project_test-zone_test-cluster", name) @@ -169,7 +169,7 @@ func TestGeneratedContextName(t *testing.T) { Zone: "test-zone", } - _, err := cluster.DefaultContextName("test-project") + _, err := cluster.DefaultGKEContextName("test-project") assert.EqualError(t, err, "Only one of region or zone should be given") }) diff --git a/pkg/tmuxp/tmuxp.go b/pkg/tmuxp/tmuxp.go index 593b384..10c5841 100644 --- a/pkg/tmuxp/tmuxp.go +++ b/pkg/tmuxp/tmuxp.go @@ -3,7 +3,7 @@ package tmuxp import ( "path" - "github.com/thecasualcoder/kube-tmuxp/pkg/filesystem" + "github.com/jfreeland/kube-tmuxp/pkg/filesystem" yaml "gopkg.in/yaml.v2" ) diff --git a/pkg/tmuxp/tmuxp_test.go b/pkg/tmuxp/tmuxp_test.go index 53bfd9d..d931bbb 100644 --- a/pkg/tmuxp/tmuxp_test.go +++ b/pkg/tmuxp/tmuxp_test.go @@ -7,8 +7,8 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" - "github.com/thecasualcoder/kube-tmuxp/pkg/internal/mock" - "github.com/thecasualcoder/kube-tmuxp/pkg/tmuxp" + "github.com/jfreeland/kube-tmuxp/pkg/internal/mock" + "github.com/jfreeland/kube-tmuxp/pkg/tmuxp" ) func TestNewConfig(t *testing.T) {