Skip to content

Commit 8a07b4f

Browse files
author
Quentin Perez
authored
Merge pull request #425 from QuentinPerez/patch-4
Prepare multi-zone
2 parents b734ff5 + 5bafed4 commit 8a07b4f

File tree

10 files changed

+139
-64
lines changed

10 files changed

+139
-64
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ Options:
182182
-q, --quiet=false Enable quiet mode
183183
--sensitive=false Show sensitive data in outputs, i.e. API Token/Organization
184184
-v, --version=false Print version information and quit
185-
--region=par1 Change the default region
185+
--region=par1 Change the default region (e.g. ams1)
186186

187187
Commands:
188188
help help of the scw command line
@@ -1203,6 +1203,10 @@ $ scw inspect myserver | jq '.[0].public_ip.address'
12031203

12041204
### master (unreleased)
12051205

1206+
* new Compute URL `api.scaleway.com` -> `cp-par1.scaleway.com`
1207+
* new TTY URL `tty.scaleway.com/v2` -> `https://tty-par1.scaleway.com/v2`
1208+
* Region: add `ams1`, you can start a server at Amsterdam with `scw --region="ams1" run yakkety`
1209+
* API: Support multi-zone
12061210
* API: Add ZoneID field in server location
12071211
* `scw image -a -f type=volume` fix unmarshal error on size field
12081212
* `scw ps` do not display empty server with --filter

pkg/api/api.go

Lines changed: 81 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,11 @@ var (
3535
AccountAPI = "https://account.scaleway.com/"
3636
MetadataAPI = "http://169.254.42.42/"
3737
MarketplaceAPI = "https://api-marketplace.scaleway.com"
38-
URLPublicDNS = ".pub.cloud.scaleway.com"
39-
URLPrivateDNS = ".priv.cloud.scaleway.com"
38+
ComputeAPIPar1 = "https://cp-par1.scaleway.com/"
39+
ComputeAPIAms1 = "https://cp-ams1.scaleway.com"
40+
41+
URLPublicDNS = ".pub.cloud.scaleway.com"
42+
URLPrivateDNS = ".priv.cloud.scaleway.com"
4043
)
4144

4245
func init() {
@@ -74,6 +77,8 @@ type ScalewayAPI struct {
7477
client *http.Client
7578
verbose bool
7679
computeAPI string
80+
81+
Region string
7782
//
7883
Logger
7984
}
@@ -885,10 +890,13 @@ func NewScalewayAPI(organization, token, userAgent, region string, options ...fu
885890
}
886891
switch region {
887892
case "par1", "":
888-
s.computeAPI = "https://api.scaleway.com/"
893+
s.computeAPI = ComputeAPIPar1
894+
case "ams1":
895+
s.computeAPI = ComputeAPIAms1
889896
default:
890897
return nil, fmt.Errorf("%s isn't a valid region", region)
891898
}
899+
s.Region = region
892900
if url := os.Getenv("SCW_COMPUTE_API"); url != "" {
893901
s.computeAPI = url
894902
}
@@ -1098,6 +1106,30 @@ func (s *ScalewayAPI) handleHTTPError(goodStatusCode []int, resp *http.Response)
10981106
return body, nil
10991107
}
11001108

1109+
func (s *ScalewayAPI) fetchServers(api string, query url.Values, out chan<- ScalewayServers) func() error {
1110+
return func() error {
1111+
resp, err := s.GetResponsePaginate(api, "servers", query)
1112+
if resp != nil {
1113+
defer resp.Body.Close()
1114+
}
1115+
if err != nil {
1116+
return err
1117+
}
1118+
1119+
body, err := s.handleHTTPError([]int{http.StatusOK}, resp)
1120+
if err != nil {
1121+
return err
1122+
}
1123+
var servers ScalewayServers
1124+
1125+
if err = json.Unmarshal(body, &servers); err != nil {
1126+
return err
1127+
}
1128+
out <- servers
1129+
return nil
1130+
}
1131+
}
1132+
11011133
// GetServers gets the list of servers from the ScalewayAPI
11021134
func (s *ScalewayAPI) GetServers(all bool, limit int) (*[]ScalewayServer, error) {
11031135
query := url.Values{}
@@ -1112,32 +1144,34 @@ func (s *ScalewayAPI) GetServers(all bool, limit int) (*[]ScalewayServer, error)
11121144
if all && limit == 0 {
11131145
s.Cache.ClearServers()
11141146
}
1115-
resp, err := s.GetResponsePaginate(s.computeAPI, "servers", query)
1116-
if resp != nil {
1117-
defer resp.Body.Close()
1118-
}
1119-
if err != nil {
1120-
return nil, err
1147+
var (
1148+
g errgroup.Group
1149+
apis = []string{
1150+
ComputeAPIPar1,
1151+
ComputeAPIAms1,
1152+
}
1153+
)
1154+
1155+
serverChan := make(chan ScalewayServers, 2)
1156+
for _, api := range apis {
1157+
g.Go(s.fetchServers(api, query, serverChan))
11211158
}
11221159

1123-
body, err := s.handleHTTPError([]int{http.StatusOK}, resp)
1124-
if err != nil {
1160+
if err := g.Wait(); err != nil {
11251161
return nil, err
11261162
}
1163+
close(serverChan)
11271164
var servers ScalewayServers
1128-
if err = json.Unmarshal(body, &servers); err != nil {
1129-
return nil, err
1165+
1166+
for server := range serverChan {
1167+
servers.Servers = append(servers.Servers, server.Servers...)
11301168
}
1169+
11311170
for i, server := range servers.Servers {
1132-
// FIXME arch, owner, title
11331171
servers.Servers[i].DNSPublic = server.Identifier + URLPublicDNS
11341172
servers.Servers[i].DNSPrivate = server.Identifier + URLPrivateDNS
11351173
s.Cache.InsertServer(server.Identifier, server.Location.ZoneID, server.Arch, server.Organization, server.Name)
11361174
}
1137-
// FIXME: when API limit is ready, remove the following code
1138-
if limit > 0 && limit < len(servers.Servers) {
1139-
servers.Servers = servers.Servers[0:limit]
1140-
}
11411175
return &servers.Servers, nil
11421176
}
11431177

@@ -2081,11 +2115,12 @@ func showResolverResults(needle string, results ScalewayResolverResults) error {
20812115
w := tabwriter.NewWriter(os.Stderr, 20, 1, 3, ' ', 0)
20822116
defer w.Flush()
20832117
sort.Sort(results)
2118+
fmt.Fprintf(w, " IMAGEID\tFROM\tNAME\tZONE\tARCH\n")
20842119
for _, result := range results {
20852120
if result.Arch == "" {
20862121
result.Arch = "n/a"
20872122
}
2088-
fmt.Fprintf(w, "- %s\t%s\t%s\t%s\n", result.TruncIdentifier(), result.CodeName(), result.Name, result.Arch)
2123+
fmt.Fprintf(w, "- %s\t%s\t%s\t%s\t%s\n", result.TruncIdentifier(), result.CodeName(), result.Name, result.Region, result.Arch)
20892124
}
20902125
return fmt.Errorf("Too many candidates for %s (%d)", needle, len(results))
20912126
}
@@ -2139,6 +2174,19 @@ func FilterImagesByArch(res ScalewayResolverResults, arch string) (ret ScalewayR
21392174
return
21402175
}
21412176

2177+
// FilterImagesByRegion removes entry that doesn't match with region
2178+
func FilterImagesByRegion(res ScalewayResolverResults, region string) (ret ScalewayResolverResults) {
2179+
if region == "*" {
2180+
return res
2181+
}
2182+
for _, result := range res {
2183+
if result.Region == region {
2184+
ret = append(ret, result)
2185+
}
2186+
}
2187+
return
2188+
}
2189+
21422190
// GetImageID returns exactly one image matching
21432191
func (s *ScalewayAPI) GetImageID(needle, arch string) (*ScalewayImageIdentifier, error) {
21442192
// Parses optional type prefix, i.e: "image:name" -> "name"
@@ -2149,17 +2197,18 @@ func (s *ScalewayAPI) GetImageID(needle, arch string) (*ScalewayImageIdentifier,
21492197
return nil, fmt.Errorf("Unable to resolve image %s: %s", needle, err)
21502198
}
21512199
images = FilterImagesByArch(images, arch)
2200+
images = FilterImagesByRegion(images, s.Region)
21522201
if len(images) == 1 {
21532202
return &ScalewayImageIdentifier{
21542203
Identifier: images[0].Identifier,
21552204
Arch: images[0].Arch,
21562205
// FIXME region, owner hardcoded
2157-
Region: "",
2206+
Region: images[0].Region,
21582207
Owner: "",
21592208
}, nil
21602209
}
21612210
if len(images) == 0 {
2162-
return nil, fmt.Errorf("No such image: %s", needle)
2211+
return nil, fmt.Errorf("No such image (zone %s, arch %s) : %s", s.Region, arch, needle)
21632212
}
21642213
return nil, showResolverResults(needle, images)
21652214
}
@@ -2817,3 +2866,14 @@ func (s *ScalewayAPI) DeleteMarketPlaceLocalImage(uuidImage, uuidVersion, uuidLo
28172866
_, err = s.handleHTTPError([]int{http.StatusNoContent}, resp)
28182867
return err
28192868
}
2869+
2870+
// ResolveTTYUrl return an URL to get a tty
2871+
func (s *ScalewayAPI) ResolveTTYUrl() string {
2872+
switch s.Region {
2873+
case "par1", "":
2874+
return "https://tty-par1.scaleway.com/v2/"
2875+
case "ams1":
2876+
return "https://tty-ams1.scaleway.com"
2877+
}
2878+
return ""
2879+
}

0 commit comments

Comments
 (0)