Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: cloud add aws eks #718

Merged
merged 2 commits into from
Jun 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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