-
Notifications
You must be signed in to change notification settings - Fork 786
/
common.go
144 lines (119 loc) · 4.51 KB
/
common.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package session
import (
"os"
"regexp"
"runtime"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/eks"
"github.com/jenkins-x/jx/v2/pkg/kube"
"github.com/pkg/errors"
)
const DefaultRegion = "us-west-2"
func NewAwsSession(profileOption string, regionOption string) (*session.Session, error) {
config := aws.Config{}
if regionOption != "" {
config.Region = aws.String(regionOption)
}
sessionOptions := session.Options{
SharedConfigState: session.SharedConfigEnable,
Config: config,
}
if profileOption != "" {
sessionOptions.Profile = profileOption
}
awsSession, err := session.NewSessionWithOptions(sessionOptions)
if err != nil {
return nil, err
}
if *awsSession.Config.Region == "" {
awsSession.Config.Region = aws.String(DefaultRegion)
}
return awsSession, nil
}
func NewAwsSessionWithoutOptions() (*session.Session, error) {
return NewAwsSession("", "")
}
func ResolveRegion(profileOption string, regionOption string) (string, error) {
session, err := NewAwsSession(profileOption, regionOption)
if err != nil {
return "", err
}
return *session.Config.Region, nil
}
func ResolveRegionWithoutOptions() (string, error) {
return ResolveRegion("", "")
}
// GetClusterNameAndRegionFromAWS uses the AWS SDK to parse through each EKS cluster until it finds one that matches the endpoint in
// the kubeconfig. From there it will retrieve the cluster name
func GetClusterNameAndRegionFromAWS(profileOption string, regionOption string, kubeEndpoint string) (string, string, error) {
session, err := NewAwsSession(profileOption, regionOption)
if err != nil {
return "", "", errors.Wrapf(err, "Error creating AWS Session")
}
svc := eks.New(session)
input := &eks.ListClustersInput{}
result, err := svc.ListClusters(input)
if err != nil {
return "", "", errors.Wrapf(err, "Error calling Eks List Clusters")
}
for _, cluster := range result.Clusters {
input := &eks.DescribeClusterInput{
Name: aws.String(*cluster),
}
result, err := svc.DescribeCluster(input)
if err != nil {
return "", "", errors.Wrapf(err, "Error calling Describe Cluster on "+*cluster)
}
if *result.Cluster.Endpoint == kubeEndpoint {
return *result.Cluster.Name, *session.Config.Region, nil
}
}
return "", "", errors.Errorf("Unable to get cluster name from AWS")
}
// ParseContext parses the EKS cluster context to extract the cluster name and the region
func ParseContext(context string) (string, string, error) {
// First check if context name matches <cluster-name>.<region>.*
reg := regexp.MustCompile(`([a-zA-Z][-a-zA-Z0-9]*)\.((us(-gov)?|ap|ca|cn|eu|sa)-(central|(north|south)?(east|west)?)-\d)\.*`)
result := reg.FindStringSubmatch(context)
if len(result) >= 3 {
return result[1], result[2], nil
}
// or else if the context name matchesAWS ARN format as defined:
// https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html
reg = regexp.MustCompile(`arn:aws:eks:((?:us(?:-gov)?|ap|ca|cn|eu|sa)-(?:central|(?:north|south)?(?:east|west)?)-\d):[0-9]*:cluster\/([a-zA-Z][-a-zA-Z0-9]*)`)
result = reg.FindStringSubmatch(context)
if len(result) >= 3 {
return result[2], result[1], nil
}
return "", "", errors.Errorf("unable to parse %s as <cluster_name>.<region>.* or arn:aws:<region>:account-id:cluster/<cluster_name>", context)
}
// GetCurrentlyConnectedRegionAndClusterName gets the current context for the connected cluster and parses it
// to extract both the Region and the ClusterName
func GetCurrentlyConnectedRegionAndClusterName() (string, string, error) {
kubeConfig, _, err := kube.NewKubeConfig().LoadConfig()
if err != nil {
return "", "", errors.Wrapf(err, "loading kubeconfig")
}
context := kube.Cluster(kubeConfig)
server := kube.CurrentServer(kubeConfig)
currentClusterName, currentRegion, err := GetClusterNameAndRegionFromAWS("", "", server)
if err != nil {
currentClusterName, currentRegion, err := ParseContext(context)
if err != nil {
return "", "", errors.Wrapf(err, "parsing the current Kubernetes context %s", context)
}
return currentClusterName, currentRegion, nil
}
return currentClusterName, currentRegion, nil
}
// UserHomeDir returns the home directory for the user the process is running under.
// This is a copy of shareddefaults.UserHomeDir in the internal AWS package.
// We can't user user.Current().HomeDir as we want to override this during testing. :-|
func UserHomeDir() string {
if runtime.GOOS == "windows" { // Windows
return os.Getenv("USERPROFILE")
}
// *nix
return os.Getenv("HOME")
}