github.com/openshift/installer@v1.4.17/pkg/asset/machines/gcp/zones.go (about)

     1  package gcp
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"sort"
     7  	"time"
     8  
     9  	"github.com/pkg/errors"
    10  	compute "google.golang.org/api/compute/v1"
    11  	"google.golang.org/api/option"
    12  	"k8s.io/apimachinery/pkg/util/sets"
    13  
    14  	gcpconfig "github.com/openshift/installer/pkg/asset/installconfig/gcp"
    15  )
    16  
    17  // AvailabilityZones retrieves a list of availability zones for the given project and region.
    18  func AvailabilityZones(project, region string) ([]string, error) {
    19  	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
    20  	defer cancel()
    21  
    22  	ssn, err := gcpconfig.GetSession(ctx)
    23  	if err != nil {
    24  		return nil, errors.Wrap(err, "failed to get session")
    25  	}
    26  
    27  	svc, err := compute.NewService(ctx, option.WithCredentials(ssn.Credentials))
    28  	if err != nil {
    29  		return nil, errors.Wrap(err, "failed to create compute service")
    30  	}
    31  
    32  	regionURL := fmt.Sprintf("https://www.googleapis.com/compute/v1/projects/%s/regions/%s",
    33  		project, region)
    34  	filter := fmt.Sprintf("(region eq %s) (status eq UP)", regionURL)
    35  	zones, err := gcpconfig.GetZones(ctx, svc, project, filter)
    36  	if err != nil {
    37  		return nil, errors.New("no zone was found")
    38  	}
    39  
    40  	zoneNames := make([]string, 0, len(zones))
    41  	for _, z := range zones {
    42  		zoneNames = append(zoneNames, z.Name)
    43  	}
    44  
    45  	sort.Strings(zoneNames)
    46  	return zoneNames, nil
    47  }
    48  
    49  // ZonesForInstanceType retrieves a filtered list of availability zones where
    50  // the particular instance type is available. This is mainly necessary for
    51  // arm64, since the instance t2a-standard-* is not available in all
    52  // availability zones.
    53  func ZonesForInstanceType(project, region, instanceType string) ([]string, error) {
    54  	ssn, err := gcpconfig.GetSession(context.Background())
    55  	if err != nil {
    56  		return nil, fmt.Errorf("failed to get session: %w", err)
    57  	}
    58  
    59  	svc, err := compute.NewService(context.Background(), option.WithCredentials(ssn.Credentials))
    60  	if err != nil {
    61  		return nil, fmt.Errorf("failed to create compute service: %w", err)
    62  	}
    63  
    64  	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
    65  	defer cancel()
    66  
    67  	pZones, err := gcpconfig.GetZones(ctx, svc, project, fmt.Sprintf("(region eq .*%s) (status eq UP)", region))
    68  	if err != nil {
    69  		return nil, fmt.Errorf("failed to get zones for project: %w", err)
    70  	}
    71  	pZoneNames := sets.New[string]()
    72  	for _, z := range pZones {
    73  		pZoneNames.Insert(z.Name)
    74  	}
    75  
    76  	machines, err := gcpconfig.GetMachineTypeList(ctx, svc, project, region, instanceType, "items/*/machineTypes(zone),nextPageToken")
    77  	if err != nil {
    78  		return nil, fmt.Errorf("failed to get zones for instance type: %w", err)
    79  	}
    80  	// Custom machine types do not show up in the list. Let's fallback to the project zones
    81  	if len(machines) == 0 {
    82  		return sets.List(pZoneNames), nil
    83  	}
    84  
    85  	zones := sets.New[string]()
    86  	for _, machine := range machines {
    87  		zones.Insert(machine.Zone)
    88  	}
    89  
    90  	// Not all instance zones might be available in the project
    91  	return sets.List(zones.Intersection(pZoneNames)), nil
    92  }