locality.go raw

   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