Skip to content

Commit

Permalink
fix: support non-zonal regions (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
tallaxes authored Dec 1, 2023
1 parent 01acc1c commit 45a0eb5
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 16 deletions.
3 changes: 3 additions & 0 deletions pkg/cloudprovider/cloudprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,5 +360,8 @@ func GenerateNodeClaimName(vmName string) string {

// makeZone returns the zone value in format of <region>-<zone-id>.
func makeZone(location string, zoneID string) string {
if zoneID == "" {
return ""
}
return fmt.Sprintf("%s-%s", strings.ToLower(location), zoneID)
}
16 changes: 10 additions & 6 deletions pkg/controllers/nodeclaim/garbagecollection/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/Azure/karpenter/pkg/cloudprovider"
"github.com/Azure/karpenter/pkg/controllers/nodeclaim/garbagecollection"
link "github.com/Azure/karpenter/pkg/controllers/nodeclaim/link"
"github.com/Azure/karpenter/pkg/fake"
"github.com/Azure/karpenter/pkg/providers/instance"
"github.com/Azure/karpenter/pkg/utils"
. "github.com/onsi/ginkgo/v2"
Expand Down Expand Up @@ -126,8 +127,9 @@ var _ = Describe("NodeClaimGarbageCollection", func() {
BeforeEach(func() {
id := utils.MkVMID(azureEnv.AzureResourceGraphAPI.ResourceGroup, "vm-a")
vm = armcompute.VirtualMachine{
ID: lo.ToPtr(id),
Name: lo.ToPtr("vm-a"),
ID: lo.ToPtr(id),
Name: lo.ToPtr("vm-a"),
Location: lo.ToPtr(fake.Region),
Tags: map[string]*string{
instance.NodePoolTagKey: lo.ToPtr("default"),
},
Expand Down Expand Up @@ -191,8 +193,9 @@ var _ = Describe("NodeClaimGarbageCollection", func() {
azureEnv.VirtualMachinesAPI.Instances.Store(
vmID,
armcompute.VirtualMachine{
ID: lo.ToPtr(utils.MkVMID(azureEnv.AzureResourceGraphAPI.ResourceGroup, vmName)),
Name: lo.ToPtr(vmName),
ID: lo.ToPtr(utils.MkVMID(azureEnv.AzureResourceGraphAPI.ResourceGroup, vmName)),
Name: lo.ToPtr(vmName),
Location: lo.ToPtr(fake.Region),
Properties: &armcompute.VirtualMachineProperties{
TimeCreated: lo.ToPtr(time.Now().Add(-time.Minute * 10)),
},
Expand Down Expand Up @@ -230,8 +233,9 @@ var _ = Describe("NodeClaimGarbageCollection", func() {
azureEnv.VirtualMachinesAPI.Instances.Store(
vmID,
armcompute.VirtualMachine{
ID: lo.ToPtr(utils.MkVMID(azureEnv.AzureResourceGraphAPI.ResourceGroup, vmName)),
Name: lo.ToPtr(vmName),
ID: lo.ToPtr(utils.MkVMID(azureEnv.AzureResourceGraphAPI.ResourceGroup, vmName)),
Name: lo.ToPtr(vmName),
Location: lo.ToPtr(fake.Region),
Properties: &armcompute.VirtualMachineProperties{
TimeCreated: lo.ToPtr(time.Now().Add(-time.Minute * 10)),
},
Expand Down
15 changes: 9 additions & 6 deletions pkg/providers/instance/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ func newVMObject(
CapacityTypeToPriority[capacityType]),
),
},
Zones: []*string{&zone},
Zones: lo.Ternary(len(zone) > 0, []*string{&zone}, []*string{}),
Tags: launchTemplate.Tags,
}
setVMPropertiesStorageProfile(vm.Properties, instanceType, nodeClass)
Expand Down Expand Up @@ -560,9 +560,11 @@ func (p *Provider) pickSkuSizePriorityAndZone(ctx context.Context, nodeClaim *co
})
zonesWithPriority := lo.Map(priorityOfferings, func(o corecloudprovider.Offering, _ int) string { return o.Zone })
if zone, ok := sets.New(zonesWithPriority...).PopAny(); ok {
// Zones in Offerings have <region>-<number> format; the zone returned from here will be used for VM instantiation,
// which expects just the zone number, without region
zone = string(zone[len(zone)-1])
if len(zone) > 0 {
// Zones in zonal Offerings have <region>-<number> format; the zone returned from here will be used for VM instantiation,
// which expects just the zone number, without region
zone = string(zone[len(zone)-1])
}
return instanceType, priority, zone
}
return nil, "", ""
Expand Down Expand Up @@ -637,6 +639,7 @@ func (p *Provider) getAKSIdentifyingExtension() *armcompute.VirtualMachineExtens
return vmExtension
}

// GetZoneID returns the zone ID for the given virtual machine, or an empty string if there is no zone specified
func GetZoneID(vm *armcompute.VirtualMachine) (string, error) {
if vm == nil {
return "", fmt.Errorf("cannot pass in a nil virtual machine")
Expand All @@ -645,15 +648,15 @@ func GetZoneID(vm *armcompute.VirtualMachine) (string, error) {
return "", fmt.Errorf("virtual machine is missing name")
}
if vm.Zones == nil {
return "", fmt.Errorf("virtual machine %v zones are nil", *vm.Name)
return "", nil
}
if len(vm.Zones) == 1 {
return *(vm.Zones)[0], nil
}
if len(vm.Zones) > 1 {
return "", fmt.Errorf("virtual machine %v has multiple zones", *vm.Name)
}
return "", fmt.Errorf("virtual machine %v does not have any zones specified", *vm.Name)
return "", nil
}

func GetListQueryBuilder(rg string) *kql.Builder {
Expand Down
58 changes: 54 additions & 4 deletions pkg/providers/instancetype/instancetypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,13 @@ func instanceTypeZones(sku *skewer.SKU, region string) sets.Set[string] {
// skewer returns numerical zones, like "1" (as keys in the map);
// prefix each zone with "<region>-", to have them match the labels placed on Node (e.g. "westus2-1")
// Note this data comes from LocationInfo, then skewer is used to get the SKU info
return sets.New(lo.Map(lo.Keys(sku.AvailabilityZones(region)), func(zone string, _ int) string {
return fmt.Sprintf("%s-%s", region, zone)
})...)
if hasZonalSupport(region) {
return sets.New(lo.Map(lo.Keys(sku.AvailabilityZones(region)), func(zone string, _ int) string {
return fmt.Sprintf("%s-%s", region, zone)
})...)
}

return sets.New("") // empty string means non-zonal offering
}

func (p *Provider) createOfferings(sku *skewer.SKU, zones sets.Set[string]) []cloudprovider.Offering {
Expand Down Expand Up @@ -156,7 +160,7 @@ func (p *Provider) getInstanceTypes(ctx context.Context) (map[string]*skewer.SKU
continue
}

if p.isSupported(&skus[i], vmsize) {
if !skus[i].HasLocationRestriction(p.region) && p.isSupported(&skus[i], vmsize) {
instanceTypes[skus[i].GetName()] = &skus[i]
}
}
Expand Down Expand Up @@ -233,3 +237,49 @@ func MaxEphemeralOSDiskSizeGB(sku *skewer.SKU) float64 {
// convert bytes to GB
return maxDiskBytes / float64(units.Gigabyte)
}

var (
// https://learn.microsoft.com/en-us/azure/reliability/availability-zones-service-support#azure-regions-with-availability-zone-support
// (could also be obtained programmatically)
zonalRegions = sets.New(
// Americas
"brazilsouth",
"canadacentral",
"centralus",
"eastus",
"eastus2",
"southcentralus",
"usgovvirginia",
"westus2",
"westus3",
// Europe
"francecentral",
"italynorth",
"germanywestcentral",
"norwayeast",
"northeurope",
"uksouth",
"westeurope",
"swedencentral",
"switzerlandnorth",
"polandcentral",
// Middle East
"qatarcentral",
"uaenorth",
"israelcentral",
// Africa
"southafricanorth",
// Asia Pacific
"australiaeast",
"centralindia",
"japaneast",
"koreacentral",
"southeastasia",
"eastasia",
"chinanorth3",
)
)

func hasZonalSupport(region string) bool {
return zonalRegions.Has(region)
}

0 comments on commit 45a0eb5

Please sign in to comment.