-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathregions.go
More file actions
156 lines (131 loc) · 4.69 KB
/
regions.go
File metadata and controls
156 lines (131 loc) · 4.69 KB
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
145
146
147
148
149
150
151
152
153
154
155
156
package utils
import (
// Standard
"context"
"fmt"
"os"
"strings"
// External
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/ec2"
"github.com/aws/aws-sdk-go/aws/endpoints"
"github.com/palantir/witchcraft-go-logging/wlog"
// Import wlog-zap for its side effects, initializing the zap logger
_ "github.com/palantir/witchcraft-go-logging/wlog-zap"
"github.com/palantir/witchcraft-go-logging/wlog/svclog/svc1log"
)
func GetAWSRegions(ctx context.Context, cfg aws.Config, selectedRegions []string) ([]string, error) {
logger := svc1log.New(os.Stderr, wlog.InfoLevel)
ctx = svc1log.WithLogger(ctx, logger)
log := svc1log.FromContext(ctx)
log.Info("Starting GetAWSRegions function")
regionsToCheck := GetRegionsToCheck(ctx, selectedRegions)
return checkRegions(ctx, cfg, regionsToCheck, log)
}
func GetRegionsToCheck(ctx context.Context, selectedRegions []string) []string {
log := svc1log.FromContext(ctx)
if len(selectedRegions) > 0 {
log.Info(fmt.Sprintf("Using selected regions: %v", selectedRegions))
return selectedRegions
}
log.Info("No regions selected, checking all regions")
var allRegions []string
resolver := endpoints.DefaultResolver()
partitions := resolver.(endpoints.EnumPartitions).Partitions()
for _, p := range partitions {
for region := range p.Regions() {
allRegions = append(allRegions, region)
}
}
log.Info(fmt.Sprintf("All regions to check: %v", allRegions))
return allRegions
}
func checkRegions(ctx context.Context, cfg aws.Config, regionsToCheck []string, log svc1log.Logger) ([]string, error) {
invalidTokenErrors := []string{}
for _, region := range regionsToCheck {
log.Info(fmt.Sprintf("Attempting DescribeRegions for region: %s", region))
validRegions, err := describeRegionsForRegion(ctx, cfg, region, regionsToCheck)
if err == nil {
return validRegions, nil
}
if handleRegionError(err, region, log, &invalidTokenErrors) {
return nil, err
}
}
if len(invalidTokenErrors) > 0 {
return nil, fmt.Errorf("invalid AWS token for one or more regions: %s", strings.Join(invalidTokenErrors, "; "))
}
return nil, fmt.Errorf("no accessible regions found among the specified regions")
}
func describeRegionsForRegion(ctx context.Context, cfg aws.Config, region string, regionsToCheck []string) ([]string, error) {
testCfg := cfg.Copy()
testCfg.Region = region
ec2Client := ec2.NewFromConfig(testCfg)
describeRegionsOutput, err := ec2Client.DescribeRegions(ctx, &ec2.DescribeRegionsInput{
AllRegions: aws.Bool(false),
})
if err != nil {
return nil, err
}
enabledRegions := make(map[string]bool)
for _, r := range describeRegionsOutput.Regions {
enabledRegions[*r.RegionName] = true
}
var validRegions []string
for _, r := range regionsToCheck {
if enabledRegions[r] {
validRegions = append(validRegions, r)
}
}
if len(validRegions) == 0 {
return nil, fmt.Errorf("no enabled regions found among the specified regions")
}
return validRegions, nil
}
func handleRegionError(err error, region string, log svc1log.Logger, invalidTokenErrors *[]string) bool {
errMsg := err.Error()
if strings.Contains(errMsg, "ExpiredToken") || strings.Contains(errMsg, "RequestExpired") {
log.Error(fmt.Sprintf("AWS token has expired: %s", errMsg))
return true
} else if strings.Contains(errMsg, "InvalidClientTokenId") || strings.Contains(errMsg, "AuthFailure") {
*invalidTokenErrors = append(*invalidTokenErrors, fmt.Sprintf("Region %s: %s", region, errMsg))
log.Warn(fmt.Sprintf("Token is invalid for region %s: %v", region, err))
} else if strings.Contains(errMsg, "no such host") {
log.Warn(fmt.Sprintf("Region %s is not accessible: %v", region, err))
} else {
log.Error(fmt.Sprintf("DescribeRegions failed for region %s: %v", region, err))
}
return false
}
// GetGeneralRegionsList returns a list of known AWS regions.
func GetGeneralRegionsList() []string {
return []string{
"us-east-1", // N. Virginia (default legacy region, can omit region in URLs)
"us-east-2", // Ohio
"us-west-1", // N. California
"us-west-2", // Oregon
"ca-central-1", // Canada (Central)
"eu-west-1", // Ireland
"eu-west-2", // London
"eu-west-3", // Paris
"eu-central-1", // Frankfurt
"eu-north-1", // Stockholm
"eu-south-1", // Milan
"eu-south-2", // Spain
"eu-central-2", // Zurich
"ap-northeast-1", // Tokyo
"ap-northeast-2", // Seoul
"ap-northeast-3", // Osaka
"ap-southeast-1", // Singapore
"ap-southeast-2", // Sydney
"ap-southeast-3", // Jakarta
"ap-southeast-4", // Melbourne
"ap-south-1", // Mumbai
"ap-south-2", // Hyderabad
"ap-east-1", // Hong Kong
"me-south-1", // Bahrain
"me-central-1", // UAE
"sa-east-1", // São Paulo
"af-south-1", // Cape Town
}
}