@@ -18,6 +18,7 @@ package availabilityzones
1818
1919import (
2020 "context"
21+ "fmt"
2122 "sort"
2223 "strings"
2324
@@ -27,7 +28,7 @@ import (
2728
2829// Spec input specification for Get/CreateOrUpdate/Delete calls
2930type Spec struct {
30- VMSize string
31+ VMSize * string
3132}
3233
3334// Get provides information about a availability zones.
@@ -37,26 +38,39 @@ func (s *Service) Get(ctx context.Context, spec interface{}) (interface{}, error
3738 if ! ok {
3839 return zones , errors .New ("invalid availability zones specification" )
3940 }
41+
42+ filter := fmt .Sprintf ("location eq '%s'" , s .Scope .Location ())
43+
4044 // Prefer ListComplete() over List() to automatically traverse pages via iterator.
41- res , err := s .Client .ListComplete (ctx , "" )
45+ res , err := s .Client .ListComplete (ctx , filter )
4246 if err != nil {
4347 return zones , err
4448 }
4549
50+ if skusSpec .VMSize != nil {
51+ return s .filterForVMSizeInLocation (ctx , skusSpec .VMSize , & res )
52+ }
53+
54+ return s .filterUniqueForLocation (ctx , & res )
55+ }
56+
57+ func (s * Service ) filterForVMSizeInLocation (ctx context.Context , vmSize * string , res * compute.ResourceSkusResultIterator ) ([]string , error ) {
58+ var zones []string
59+
4660 for res .NotDone () {
4761 resSku := res .Value ()
48- if strings .EqualFold (* resSku .Name , skusSpec . VMSize ) {
62+ if strings .EqualFold (* resSku .Name , * vmSize ) {
4963 // Use map for easy deletion and iteration
5064 availableZones := make (map [string ]bool )
5165 for _ , locationInfo := range * resSku .LocationInfo {
5266 for _ , zone := range * locationInfo .Zones {
5367 availableZones [zone ] = true
5468 }
55- if strings .EqualFold (* locationInfo .Location , s .Scope .Location ()) {
69+ if strings .EqualFold (* locationInfo .Location , s .Scope .Location ()) { //NOTE: this should always be true due to the filter
5670 for _ , restriction := range * resSku .Restrictions {
5771 // Can't deploy anything in this subscription in this location. Bail out.
5872 if restriction .Type == compute .Location {
59- return []string {}, errors .Errorf ("rejecting sku: %s in location: %s due to susbcription restriction" , skusSpec . VMSize , s .Scope .Location ())
73+ return []string {}, errors .Errorf ("rejecting sku: %s in location: %s due to susbcription restriction" , * vmSize , s .Scope .Location ())
6074 }
6175 // May be able to deploy one or more zones to this location.
6276 for _ , restrictedZone := range * restriction .RestrictionInfo .Zones {
@@ -74,12 +88,41 @@ func (s *Service) Get(ctx context.Context, spec interface{}) (interface{}, error
7488 }
7589 }
7690 }
77- err = res .NextWithContext (ctx )
91+ err := res .NextWithContext (ctx )
92+ if err != nil {
93+ return zones , errors .Wrap (err , "could not iterate availability zones" )
94+ }
95+ }
96+
97+ return zones , nil
98+ }
99+
100+ func (s * Service ) filterUniqueForLocation (ctx context.Context , res * compute.ResourceSkusResultIterator ) ([]string , error ) {
101+ zones := make ([]string , 0 )
102+
103+ for res .NotDone () {
104+ resSku := res .Value ()
105+ // Use map for easy deletion and iteration
106+ availableZones := make (map [string ]bool )
107+ for _ , locationInfo := range * resSku .LocationInfo {
108+ for _ , zone := range * locationInfo .Zones {
109+ availableZones [zone ] = true
110+ }
111+
112+ for availableZone := range availableZones {
113+ if ! contains (zones , availableZone ) {
114+ zones = append (zones , availableZone )
115+ }
116+ }
117+ }
118+ err := res .NextWithContext (ctx )
78119 if err != nil {
79120 return zones , errors .Wrap (err , "could not iterate availability zones" )
80121 }
81122 }
82123
124+ // Lexical sort so comparisons work in tests
125+ sort .Strings (zones )
83126 return zones , nil
84127}
85128
@@ -94,3 +137,12 @@ func (s *Service) Delete(ctx context.Context, spec interface{}) error {
94137 // Not implemented since there is nothing to delete
95138 return nil
96139}
140+
141+ func contains (strSlice []string , val string ) bool {
142+ for _ , c := range strSlice {
143+ if c == val {
144+ return true
145+ }
146+ }
147+ return false
148+ }
0 commit comments