github.com/openshift/installer@v1.4.17/pkg/asset/installconfig/azure/azure.go (about) 1 package azure 2 3 import ( 4 "context" 5 "fmt" 6 "sort" 7 "strings" 8 9 survey "github.com/AlecAivazis/survey/v2" 10 "github.com/AlecAivazis/survey/v2/core" 11 "github.com/Azure/go-autorest/autorest/to" 12 13 "github.com/openshift/installer/pkg/types/azure" 14 ) 15 16 const ( 17 defaultRegion string = "eastus" 18 ) 19 20 // Platform collects azure-specific configuration. 21 func Platform() (*azure.Platform, error) { 22 // Create client using public cloud because install config has not been generated yet. 23 const cloudName = azure.PublicCloud 24 ssn, err := GetSession(cloudName, "") 25 if err != nil { 26 return nil, err 27 } 28 29 client := NewClient(ssn) 30 31 regions, err := getRegions(context.TODO(), client) 32 if err != nil { 33 return nil, fmt.Errorf("failed to get list of regions: %w", err) 34 } 35 36 resourceCapableRegions, err := getResourceCapableRegions(context.TODO(), client) 37 if err != nil { 38 return nil, fmt.Errorf("failed to get list of resources to check available regions: %w", err) 39 } 40 41 longRegions := make([]string, 0, len(regions)) 42 shortRegions := make([]string, 0, len(regions)) 43 for id, location := range regions { 44 for _, resourceCapableRegion := range resourceCapableRegions { 45 // filter our regions not capable of having resources created (we check for resource groups) 46 if resourceCapableRegion == location { 47 longRegions = append(longRegions, fmt.Sprintf("%s (%s)", id, location)) 48 shortRegions = append(shortRegions, id) 49 } 50 } 51 } 52 53 var regionTransform survey.Transformer = func(ans interface{}) interface{} { 54 switch v := ans.(type) { 55 case core.OptionAnswer: 56 return core.OptionAnswer{Value: strings.SplitN(v.Value, " ", 2)[0], Index: v.Index} 57 case string: 58 return strings.SplitN(v, " ", 2)[0] 59 } 60 return "" 61 } 62 63 _, ok := regions[defaultRegion] 64 if !ok { 65 return nil, fmt.Errorf("installer bug: invalid default azure region %q", defaultRegion) 66 } 67 68 sort.Strings(longRegions) 69 sort.Strings(shortRegions) 70 71 var region string 72 err = survey.Ask([]*survey.Question{ 73 { 74 Prompt: &survey.Select{ 75 Message: "Region", 76 Help: "The azure region to be used for installation.", 77 Default: fmt.Sprintf("%s (%s)", defaultRegion, regions[defaultRegion]), 78 Options: longRegions, 79 }, 80 Validate: survey.ComposeValidators(survey.Required, func(ans interface{}) error { 81 choice := regionTransform(ans).(core.OptionAnswer).Value 82 i := sort.SearchStrings(shortRegions, choice) 83 if i == len(shortRegions) || shortRegions[i] != choice { 84 return fmt.Errorf("invalid region %q", choice) 85 } 86 return nil 87 }), 88 Transform: regionTransform, 89 }, 90 }, ®ion) 91 if err != nil { 92 return nil, err 93 } 94 95 return &azure.Platform{ 96 Region: region, 97 CloudName: cloudName, 98 }, nil 99 } 100 101 func getRegions(ctx context.Context, client API) (map[string]string, error) { 102 locations, err := client.ListLocations(ctx) 103 if err != nil { 104 return nil, err 105 } 106 107 allLocations := map[string]string{} 108 for _, location := range *locations { 109 allLocations[to.String(location.Name)] = to.String(location.DisplayName) 110 } 111 return allLocations, nil 112 } 113 114 func getResourceCapableRegions(ctx context.Context, client API) ([]string, error) { 115 provider, err := client.GetResourcesProvider(ctx, "Microsoft.Resources") 116 if err != nil { 117 return nil, err 118 } 119 120 for _, resType := range *provider.ResourceTypes { 121 if *resType.ResourceType == "resourceGroups" { 122 return *resType.Locations, nil 123 } 124 } 125 126 return []string{}, nil 127 }