1 package scw
2 3 import (
4 "encoding/json"
5 "fmt"
6 "strings"
7 8 "github.com/scaleway/scaleway-sdk-go/errors"
9 "github.com/scaleway/scaleway-sdk-go/logger"
10 "github.com/scaleway/scaleway-sdk-go/validation"
11 )
12 13 // localityPartsSeparator is the separator used in Zone and Region
14 const localityPartsSeparator = "-"
15 16 // Zone is an availability zone
17 type Zone string
18 19 const (
20 // ZoneFrPar1 represents the fr-par-1 zone
21 ZoneFrPar1 = Zone("fr-par-1")
22 // ZoneFrPar2 represents the fr-par-2 zone
23 ZoneFrPar2 = Zone("fr-par-2")
24 // ZoneFrPar3 represents the fr-par-3 zone
25 ZoneFrPar3 = Zone("fr-par-3")
26 // ZoneNlAms1 represents the nl-ams-1 zone
27 ZoneNlAms1 = Zone("nl-ams-1")
28 // ZoneNlAms2 represents the nl-ams-2 zone
29 ZoneNlAms2 = Zone("nl-ams-2")
30 // ZoneNlAms3 represents the nl-ams-3 zone
31 ZoneNlAms3 = Zone("nl-ams-3")
32 // ZonePlWaw1 represents the pl-waw-1 zone
33 ZonePlWaw1 = Zone("pl-waw-1")
34 // ZonePlWaw2 represents the pl-waw-2 zone
35 ZonePlWaw2 = Zone("pl-waw-2")
36 // ZonePlWaw3 represents the pl-waw-3 zone
37 ZonePlWaw3 = Zone("pl-waw-3")
38 )
39 40 // AllZones is an array that list all zones
41 var AllZones = []Zone{
42 ZoneFrPar1,
43 ZoneFrPar2,
44 ZoneFrPar3,
45 ZoneNlAms1,
46 ZoneNlAms2,
47 ZoneNlAms3,
48 ZonePlWaw1,
49 ZonePlWaw2,
50 ZonePlWaw3,
51 }
52 53 // Exists checks whether a zone exists
54 func (zone Zone) Exists() bool {
55 for _, z := range AllZones {
56 if z == zone {
57 return true
58 }
59 }
60 return false
61 }
62 63 // String returns a Zone as a string
64 func (zone Zone) String() string {
65 return string(zone)
66 }
67 68 // Region returns the parent Region for the Zone.
69 // Manipulates the string directly to allow unlisted zones formatted as xx-yyy-z.
70 func (zone Zone) Region() (Region, error) {
71 zoneStr := zone.String()
72 if !validation.IsZone(zoneStr) {
73 return "", fmt.Errorf("invalid zone '%v'", zoneStr)
74 }
75 zoneParts := strings.Split(zoneStr, localityPartsSeparator)
76 return Region(strings.Join(zoneParts[:2], localityPartsSeparator)), nil
77 }
78 79 // Region is a geographical location
80 type Region string
81 82 const (
83 // RegionFrPar represents the fr-par region
84 RegionFrPar = Region("fr-par")
85 // RegionNlAms represents the nl-ams region
86 RegionNlAms = Region("nl-ams")
87 // RegionPlWaw represents the pl-waw region
88 RegionPlWaw = Region("pl-waw")
89 )
90 91 // AllRegions is an array that list all regions
92 var AllRegions = []Region{
93 RegionFrPar,
94 RegionNlAms,
95 RegionPlWaw,
96 }
97 98 // Exists checks whether a region exists
99 func (region Region) Exists() bool {
100 for _, r := range AllRegions {
101 if r == region {
102 return true
103 }
104 }
105 return false
106 }
107 108 // GetZones is a function that returns the zones for the specified region
109 func (region Region) GetZones() []Zone {
110 switch region {
111 case RegionFrPar:
112 return []Zone{ZoneFrPar1, ZoneFrPar2, ZoneFrPar3}
113 case RegionNlAms:
114 return []Zone{ZoneNlAms1, ZoneNlAms2, ZoneNlAms3}
115 case RegionPlWaw:
116 return []Zone{ZonePlWaw1, ZonePlWaw2, ZonePlWaw3}
117 default:
118 return []Zone{}
119 }
120 }
121 122 // ParseZone parses a string value into a Zone and returns an error if it has a bad format.
123 func ParseZone(zone string) (Zone, error) {
124 switch zone {
125 case "par1":
126 // would be triggered by API market place
127 // logger.Warningf("par1 is a deprecated name for zone, use fr-par-1 instead")
128 return ZoneFrPar1, nil
129 case "ams1":
130 // would be triggered by API market place
131 // logger.Warningf("ams1 is a deprecated name for zone, use nl-ams-1 instead")
132 return ZoneNlAms1, nil
133 default:
134 if !validation.IsZone(zone) {
135 zones := []string(nil)
136 for _, z := range AllZones {
137 zones = append(zones, string(z))
138 }
139 return "", errors.New("bad zone format, available zones are: %s", strings.Join(zones, ", "))
140 }
141 142 newZone := Zone(zone)
143 if !newZone.Exists() {
144 logger.Infof("%s is an unknown zone\n", newZone)
145 }
146 return newZone, nil
147 }
148 }
149 150 // UnmarshalJSON implements the Unmarshaler interface for a Zone.
151 // this to call ParseZone on the string input and return the correct Zone object.
152 func (zone *Zone) UnmarshalJSON(input []byte) error {
153 // parse input value as string
154 var stringValue string
155 err := json.Unmarshal(input, &stringValue)
156 if err != nil {
157 return err
158 }
159 160 // parse string as Zone
161 *zone, err = ParseZone(stringValue)
162 if err != nil {
163 return err
164 }
165 return nil
166 }
167 168 // ParseRegion parses a string value into a Region and returns an error if it has a bad format.
169 func ParseRegion(region string) (Region, error) {
170 switch region {
171 case "par1":
172 // would be triggered by API market place
173 // logger.Warningf("par1 is a deprecated name for region, use fr-par instead")
174 return RegionFrPar, nil
175 case "ams1":
176 // would be triggered by API market place
177 // logger.Warningf("ams1 is a deprecated name for region, use nl-ams instead")
178 return RegionNlAms, nil
179 default:
180 if !validation.IsRegion(region) {
181 regions := []string(nil)
182 for _, r := range AllRegions {
183 regions = append(regions, string(r))
184 }
185 return "", errors.New("bad region format, available regions are: %s", strings.Join(regions, ", "))
186 }
187 188 newRegion := Region(region)
189 if !newRegion.Exists() {
190 logger.Infof("%s is an unknown region\n", newRegion)
191 }
192 return newRegion, nil
193 }
194 }
195 196 // UnmarshalJSON implements the Unmarshaler interface for a Region.
197 // this to call ParseRegion on the string input and return the correct Region object.
198 func (region *Region) UnmarshalJSON(input []byte) error {
199 // parse input value as string
200 var stringValue string
201 err := json.Unmarshal(input, &stringValue)
202 if err != nil {
203 return err
204 }
205 206 // parse string as Region
207 *region, err = ParseRegion(stringValue)
208 if err != nil {
209 return err
210 }
211 return nil
212 }
213 214 // String returns a Region as a string
215 func (region Region) String() string {
216 return string(region)
217 }
218