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  	}, &region)
    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  }