Skip to content

Commit

Permalink
feat: cloud add aws eks (#718)
Browse files Browse the repository at this point in the history
* feat: cloud add aws eks

* fix and update
  • Loading branch information
sunny0826 authored Jun 30, 2023
1 parent e24efa0 commit aa8d2af
Show file tree
Hide file tree
Showing 7 changed files with 280 additions and 10 deletions.
39 changes: 37 additions & 2 deletions cmd/cloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ var Clouds = []CloudInfo{
HomePage: "https://rancher.com",
Service: "Rancher",
},
{
Name: "AWS",
Alias: []string{"aws", "eks"},
HomePage: "https://console.aws.amazon.com/eks/home",
Service: "EKS",
},
}

// Init CloudCommand
Expand All @@ -66,8 +72,8 @@ func getClusters(provider, regionID string, num int) ([]cloud.ClusterInfo, error
switch num {
case -1:
var allAlias []string
for _, cloud := range Clouds {
allAlias = append(allAlias, cloud.Alias...)
for _, cloudInfo := range Clouds {
allAlias = append(allAlias, cloudInfo.Alias...)
}
return nil, fmt.Errorf("'%s' is not supported, supported cloud alias are %v", provider, allAlias)
case 0:
Expand Down Expand Up @@ -111,6 +117,27 @@ func getClusters(provider, regionID string, num int) ([]cloud.ClusterInfo, error
if err != nil {
return nil, err
}
case 3:
fmt.Println("⛅ Selected: AWS")
accessKeyID, accessKeySecret := checkEnvForSecret(3)
aws := cloud.AWS{
AccessKeyID: accessKeyID,
AccessKeySecret: accessKeySecret,
}
if regionID == "" {
regionList, err := cloud.GetRegionID()
if err != nil {
return nil, err
}
regionNum := selectRegion(regionList, "Select Region ID")
aws.RegionID = regionList[regionNum]
} else {
aws.RegionID = regionID
}
clusters, err = aws.ListCluster()
if err != nil {
return nil, err
}
}
return clusters, err
}
Expand Down Expand Up @@ -141,6 +168,14 @@ func checkEnvForSecret(num int) (string, string) {
apiKey = PromptUI("Rancher API key", "")
}
return serverURL, apiKey
case 3:
accessKeyID, id := os.LookupEnv("AWS_ACCESS_KEY_ID")
accessKeySecret, key := os.LookupEnv("AWS_SECRET_ACCESS_KEY")
if !id || !key {
accessKeyID = PromptUI("AWS Access Key ID", "")
accessKeySecret = PromptUI("AWS Access Key Secret", "")
}
return accessKeyID, accessKeySecret
}
return "", ""
}
Expand Down
52 changes: 46 additions & 6 deletions cmd/cloud_add.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,26 +183,66 @@ func (ca *CloudAddCommand) runCloudAdd(cmd *cobra.Command, args []string) error
return err
}
}
case 3:
fmt.Println("⛅ Selected: AWS")
accessKeyID, accessKeySecret := checkEnvForSecret(3)
aws := cloud.AWS{
AccessKeyID: accessKeyID,
AccessKeySecret: accessKeySecret,
}
if regionID == "" {
regionList, err := cloud.GetRegionID()
if err != nil {
return err
}
regionNum := selectRegion(regionList, "Select Region ID")
aws.RegionID = regionList[regionNum]
} else {
aws.RegionID = regionID
}
if clusterID == "" {
clusters, err := aws.ListCluster()
if err != nil {
return err
}
if len(clusters) == 0 {
return errors.New("no clusters found")
}
clusterNum := selectCluster(clusters, "Select Cluster")
clusterID = clusters[clusterNum].ID
}
newConfig, err := aws.GetKubeConfigObj(clusterID)
if err != nil {
return err
}
return AddToLocal(newConfig, fmt.Sprintf("aws-%s", clusterID), "", cover)
}
return nil
}

func cloudAddExample() string {
return `
# Supports Ali Cloud and Tencent Cloud
# Supports AWS, Ali Cloud, Tencent Cloud and Rancher
# The AK/AS of the cloud platform will be retrieved directly
# if it exists in the environment variable,
# otherwise a prompt box will appear asking for it.
# Set env AliCloud secret key
export ACCESS_KEY_ID=xxx
export ACCESS_KEY_SECRET=xxx
export ACCESS_KEY_ID=YOUR_AKID
export ACCESS_KEY_SECRET=YOUR_SECRET_KEY
# Set env Tencent secret key
export TENCENTCLOUD_SECRET_ID=xxx
export TENCENTCLOUD_SECRET_KEY=xxx
export TENCENTCLOUD_SECRET_ID=YOUR_SECRET_ID
export TENCENTCLOUD_SECRET_KEY=YOUR_SECRET_KEY
# Set env Rancher secret key
export RANCHER_SERVER_URL=https://xxx
export RANCHER_API_KEY=xxx
export RANCHER_API_KEY=YOUR_API_KEY
# Set env AWS secret key
export AWS_ACCESS_KEY_ID=YOUR_AKID
export AWS_SECRET_ACCESS_KEY=YOUR_SECRET_KEY
# Interaction: select kubeconfig from the cloud
kubecm cloud add
# Add kubeconfig from cloud
Expand Down
2 changes: 1 addition & 1 deletion codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ coverage:
status:
project:
default:
threshold: 0.1
threshold: 1
patch: off
6 changes: 5 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ require (
k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect
)

require github.com/stretchr/testify v1.8.4
require (
github.com/aws/aws-sdk-go v1.44.292
github.com/stretchr/testify v1.8.4
)

require (
atomicgo.dev/cursor v0.1.1 // indirect
Expand Down Expand Up @@ -61,6 +64,7 @@ require (
github.com/gordonklaus/ineffassign v0.0.0-20180909121442-1003c8bd00dc // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a // indirect
Expand Down
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk=
github.com/aws/aws-sdk-go v1.44.292 h1:sPDmWCIv69lunIh18zDkCBNXCbHoqTx9O4uYNHNrSKo=
github.com/aws/aws-sdk-go v1.44.292/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
Expand Down Expand Up @@ -392,6 +394,10 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
Expand Down Expand Up @@ -771,6 +777,7 @@ golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
Expand Down Expand Up @@ -848,13 +855,15 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
Expand All @@ -867,6 +876,7 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
Expand Down
152 changes: 152 additions & 0 deletions pkg/cloud/aws.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package cloud

import (
"encoding/base64"
"fmt"

clientcmdapi "k8s.io/client-go/tools/clientcmd/api"

"github.com/aws/aws-sdk-go/aws/credentials"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/endpoints"
"github.com/aws/aws-sdk-go/service/eks"

"github.com/aws/aws-sdk-go/aws/session"
)

// AWS struct of aws cloud
type AWS struct {
AccessKeyID string
AccessKeySecret string
RegionID string
}

// getSession get session of aws cloud
func (a *AWS) getSession() (*session.Session, error) {
sess, err := session.NewSession(&aws.Config{
Region: aws.String(a.RegionID),
Credentials: credentials.NewStaticCredentials(a.AccessKeyID, a.AccessKeySecret, ""),
})
return sess, err
}

// GetRegionID get region id of aws
func GetRegionID() ([]string, error) {
partitions := endpoints.DefaultPartitions()
var regionList []string
for _, p := range partitions {
for id := range p.Regions() {
//fmt.Printf("%s\n", id)
regionList = append(regionList, id)
}
}
return regionList, nil
}

// ListCluster list cluster info of aws
func (a *AWS) ListCluster() (clusters []ClusterInfo, err error) {
sess, err := a.getSession()
if err != nil {
return nil, err
}
var clusterList []ClusterInfo
svc := eks.New(sess)
input := &eks.ListClustersInput{}

result, err := svc.ListClusters(input)
if err != nil {
return nil, err
}

for _, clusterName := range result.Clusters {
clusterInfo, err := a.getClusterInfo(*clusterName)
if err != nil {
return nil, err
}
clusterList = append(clusterList, clusterInfo)
}
return clusterList, nil
}

// GetClusterInfo get cluster info of aws eks
func (a *AWS) getClusterInfo(clusterName string) (clusterInfo ClusterInfo, err error) {
sess, err := a.getSession()
if err != nil {
return ClusterInfo{}, err
}
svc := eks.New(sess)
input := &eks.DescribeClusterInput{
Name: &clusterName,
}
cluster, err := svc.DescribeCluster(input)
if err != nil {
return ClusterInfo{}, err
}
return ClusterInfo{
ID: *cluster.Cluster.Name,
Name: *cluster.Cluster.Name,
RegionID: a.RegionID,
K8sVersion: *cluster.Cluster.Version,
ConsoleURL: fmt.Sprintf("https://%s.console.aws.amazon.com/eks/home?region=%s#/clusters/%s", a.RegionID, a.RegionID, *cluster.Cluster.Name),
}, err

}

// GetKubeConfigObj get aws eks kubeConfig file
func (a *AWS) GetKubeConfigObj(clusterID string) (*clientcmdapi.Config, error) {
sess, err := a.getSession()
if err != nil {
return nil, err
}

svc := eks.New(sess)
input := &eks.DescribeClusterInput{
Name: &clusterID,
}
cluster, err := svc.DescribeCluster(input)
if err != nil {
return nil, err
}

decodePem, err := base64.StdEncoding.DecodeString(*cluster.Cluster.CertificateAuthority.Data)
if err != nil {
return nil, err
}

kubeconfig := &clientcmdapi.Config{
Clusters: map[string]*clientcmdapi.Cluster{
*cluster.Cluster.Name: {
Server: *cluster.Cluster.Endpoint,
CertificateAuthorityData: decodePem,
},
},
AuthInfos: map[string]*clientcmdapi.AuthInfo{
*cluster.Cluster.Name: {
Exec: &clientcmdapi.ExecConfig{
APIVersion: "client.authentication.k8s.io/v1beta1",
Command: "aws",
Args: []string{
"eks",
"get-token",
"--cluster-name",
*cluster.Cluster.Name,
"--region",
a.RegionID,
"--output",
"json",
},
},
},
},
Contexts: map[string]*clientcmdapi.Context{
*cluster.Cluster.Name: {
Cluster: *cluster.Cluster.Name,
AuthInfo: *cluster.Cluster.Name,
},
},
CurrentContext: *cluster.Cluster.Name,
}

return kubeconfig, nil
}
Loading

0 comments on commit aa8d2af

Please sign in to comment.