44package common
55
66import (
7+ "encoding/json"
78 "fmt"
9+ "io/ioutil"
10+ "os"
11+ "path"
812 "regexp"
913 "strings"
1014)
@@ -35,6 +39,8 @@ const (
3539 RegionAPSeoul1 Region = "ap-seoul-1"
3640 //RegionAPMumbai1 region for mumbai
3741 RegionAPMumbai1 Region = "ap-mumbai-1"
42+ //RegionAPHyderabad1 region for Hyderabad
43+ RegionAPHyderabad1 Region = "ap-hyderabad-1"
3844 //RegionAPMelbourne1 region for Melbourne
3945 RegionAPMelbourne1 Region = "ap-melbourne-1"
4046 //RegionAPSydney1 region for Sydney
@@ -60,6 +66,25 @@ const (
6066 RegionUSGovPhoenix1 Region = "us-gov-phoenix-1"
6167 //RegionUKGovLondon1 gov region London
6268 RegionUKGovLondon1 Region = "uk-gov-london-1"
69+
70+ //RegionUKGovCardiff1 gov region Cardiff
71+ RegionUKGovCardiff1 Region = "uk-gov-cardiff-1"
72+
73+ //RegionUSTacoma1 region for us-tacoma-1
74+ RegionUSTacoma1 Region = "us-tacoma-1"
75+
76+ // Region Metadata Configuration File
77+ regionMetadataCfgDirName = ".oci"
78+ regionMetadataCfgFileName = "regions-config.json"
79+
80+ // Region Metadata Environment Variable
81+ regionMetadataEnvVarName = "OCI_REGION_METADATA"
82+
83+ // Region Metadata
84+ regionIdentifierPropertyName = "regionIdentifier" // e.g. "ap-sydney-1"
85+ realmKeyPropertyName = "realmKey" // e.g. "oc1"
86+ realmDomainComponentPropertyName = "realmDomainComponent" // e.g. "oraclecloud.com"
87+ regionKeyPropertyName = "regionKey" // e.g. "SYD"
6388)
6489
6590var realm = map [string ]string {
@@ -81,6 +106,7 @@ var regionRealm = map[Region]string{
81106 RegionAPSeoul1 : "oc1" ,
82107 RegionAPSydney1 : "oc1" ,
83108 RegionAPMumbai1 : "oc1" ,
109+ RegionAPHyderabad1 : "oc1" ,
84110 RegionAPMelbourne1 : "oc1" ,
85111 RegionMEJeddah1 : "oc1" ,
86112 RegionEUZurich1 : "oc1" ,
@@ -100,7 +126,7 @@ func (region Region) Endpoint(service string) string {
100126 return fmt .Sprintf ("%s.%s.%s" , service , region , region .secondLevelDomain ())
101127}
102128
103- // EndpointForTemplate returns a endpoint for a service based on template
129+ // EndpointForTemplate returns a endpoint for a service based on template, only unknown region name can fall back to "oc1", but not short code region name.
104130func (region Region ) EndpointForTemplate (service string , serviceEndpointTemplate string ) string {
105131 if serviceEndpointTemplate == "" {
106132 return region .Endpoint (service )
@@ -154,6 +180,8 @@ func StringToRegion(stringRegion string) (r Region) {
154180 r = RegionAPSeoul1
155181 case "bom" , "ap-mumbai-1" :
156182 r = RegionAPMumbai1
183+ case "hyd" , "ap-hyderabad-1" :
184+ r = RegionAPHyderabad1
157185 case "mel" , "ap-melbourne-1" :
158186 r = RegionAPMelbourne1
159187 case "syd" , "ap-sydney-1" :
@@ -179,8 +207,8 @@ func StringToRegion(stringRegion string) (r Region) {
179207 case "ltn" , "uk-gov-london-1" :
180208 r = RegionUKGovLondon1
181209 default :
182- r = Region (stringRegion )
183210 Debugf ("region named: %s, is not recognized" , stringRegion )
211+ r = checkAndAddRegionMetadata (stringRegion )
184212 }
185213 return
186214}
@@ -195,3 +223,121 @@ func canStringBeRegion(stringRegion string) (region string, err error) {
195223 }
196224 return stringRegion , nil
197225}
226+
227+ // check region info from original map
228+ func checkAndAddRegionMetadata (region string ) Region {
229+ switch {
230+ case SetRegionMetadataFromCfgFile (& region ):
231+ case SetRegionMetadataFromEnvVar (& region ):
232+ case SetRegionFromInstanceMetadataService (& region ):
233+ default :
234+ //err := fmt.Errorf("failed to get region metadata information.")
235+ return Region (region )
236+ }
237+ return Region (region )
238+ }
239+
240+ // SetRegionMetadataFromEnvVar checks if region metadata env variable is provided, once it's there, parse and added it to region map
241+ func SetRegionMetadataFromEnvVar (region * string ) bool {
242+ // check from env variable
243+ if jsonStr , existed := os .LookupEnv (regionMetadataEnvVarName ); existed {
244+ Debugf ("Raw content of region metadata env var:" , jsonStr )
245+ var regionSchema map [string ]string
246+ if err := json .Unmarshal ([]byte (jsonStr ), & regionSchema ); err != nil {
247+ Debugf ("Can't unmarshal env var, the error info is" , err )
248+ return false
249+ }
250+ // check if the specified region is in the env var.
251+ if checkSchemaItems (regionSchema ) {
252+ // set mapping table
253+ addRegionSchema (regionSchema )
254+ if regionSchema [regionKeyPropertyName ] == * region ||
255+ regionSchema [regionIdentifierPropertyName ] == * region {
256+ * region = regionSchema [regionIdentifierPropertyName ]
257+ return true
258+ }
259+ }
260+ return false
261+ }
262+ Debugf ("The Region Metadata Schema wasn't set in env variable - OCI_REGION_METADATA." )
263+ return false
264+ }
265+
266+ // SetRegionMetadataFromCfgFile checks if region metadata config file is provided, once it's there, parse and added it to region map
267+ func SetRegionMetadataFromCfgFile (region * string ) bool {
268+ homeFolder := getHomeFolder ()
269+ configFile := path .Join (homeFolder , regionMetadataCfgDirName , regionMetadataCfgFileName )
270+ if jsonArr , ok := readAndParseConfigFile (& configFile ); ok {
271+ added := false
272+ for _ , jsonItem := range jsonArr {
273+ if checkSchemaItems (jsonItem ) {
274+ addRegionSchema (jsonItem )
275+ if jsonItem [regionKeyPropertyName ] == * region ||
276+ jsonItem [regionIdentifierPropertyName ] == * region {
277+ * region = jsonItem [regionIdentifierPropertyName ]
278+ added = true
279+ }
280+ }
281+ }
282+ return added
283+ }
284+ return false
285+ }
286+
287+ func readAndParseConfigFile (configFileName * string ) (fileContent []map [string ]string , ok bool ) {
288+
289+ if content , err := ioutil .ReadFile (* configFileName ); err == nil {
290+ Debugf ("Raw content of region metadata config file content:" , string (content [:]))
291+ if err := json .Unmarshal (content , & fileContent ); err != nil {
292+ Debugf ("Can't unmarshal env var, the error info is" , err )
293+ return
294+ }
295+ ok = true
296+ return
297+ }
298+ Debugf ("No Region Metadata Config File provided." )
299+ return
300+
301+ }
302+
303+ // check map regionRealm's region name, if it's already there, no need to add it.
304+ func addRegionSchema (regionSchema map [string ]string ) {
305+ r := Region (strings .ToLower (regionSchema [regionIdentifierPropertyName ]))
306+ if _ , ok := regionRealm [r ]; ! ok {
307+ // set mapping table
308+ realm [regionSchema [realmKeyPropertyName ]] = regionSchema [realmDomainComponentPropertyName ]
309+ regionRealm [r ] = regionSchema [realmKeyPropertyName ]
310+ return
311+ }
312+ Debugf ("Region {} has already been added, no need to add again." , regionSchema [regionIdentifierPropertyName ])
313+ }
314+
315+ // check region schema content if all the required contents are provided
316+ func checkSchemaItems (regionSchema map [string ]string ) bool {
317+ if checkSchemaItem (regionSchema , regionIdentifierPropertyName ) &&
318+ checkSchemaItem (regionSchema , realmKeyPropertyName ) &&
319+ checkSchemaItem (regionSchema , realmDomainComponentPropertyName ) &&
320+ checkSchemaItem (regionSchema , regionKeyPropertyName ) {
321+ return true
322+ }
323+ return false
324+ }
325+
326+ // check region schema item is valid, if so, convert it to lower case.
327+ func checkSchemaItem (regionSchema map [string ]string , key string ) bool {
328+ if val , ok := regionSchema [key ]; ok {
329+ if val != "" {
330+ regionSchema [key ] = strings .ToLower (val )
331+ return true
332+ }
333+ Debugf ("Region metadata schema {} is provided,but content is empty." , key )
334+ return false
335+ }
336+ Debugf ("Region metadata schema {} is not provided, please update the content" , key )
337+ return false
338+ }
339+
340+ // SetRegionFromInstanceMetadataService checks if region metadata can be provided from InstanceMetadataService.
341+ func SetRegionFromInstanceMetadataService (region * string ) bool {
342+ return false
343+ }
0 commit comments