diff --git a/pkg/cloudprovider/suite_aksmachineapi_offerings_test.go b/pkg/cloudprovider/suite_aksmachineapi_offerings_test.go index 697e67610a..0a3980e689 100644 --- a/pkg/cloudprovider/suite_aksmachineapi_offerings_test.go +++ b/pkg/cloudprovider/suite_aksmachineapi_offerings_test.go @@ -401,13 +401,50 @@ var _ = Describe("CloudProvider", func() { ExpectApplied(ctx, env.Client, nodePool, nodeClass) pod := coretest.UnschedulablePod() ExpectProvisionedAndWaitForPromises(ctx, env.Client, clusterNonZonal, cloudProviderNonZonal, coreProvisionerNonZonal, azureEnvNonZonal, pod) - ExpectScheduled(ctx, env.Client, pod) + node := ExpectScheduled(ctx, env.Client, pod) + Expect(node.Labels).To(HaveKeyWithValue(v1.LabelTopologyZone, zones.Regional)) + Expect(node.Labels).To(HaveKeyWithValue(v1beta1.LabelPlacementScope, v1beta1.PlacementScopeRegional)) + + Expect(azureEnvNonZonal.AKSMachinesAPI.AKSMachineCreateOrUpdateBehavior.CalledWithInput.Len()).To(Equal(1)) + aksMachine := azureEnvNonZonal.AKSMachinesAPI.AKSMachineCreateOrUpdateBehavior.CalledWithInput.Pop().AKSMachine + Expect(aksMachine.Zones).To(BeEmpty()) + }) + + It("should support regional placement scope in non-zonal regions", func() { + coretest.ReplaceRequirements(nodePool, karpv1.NodeSelectorRequirementWithMinValues{ + Key: v1beta1.LabelPlacementScope, + Operator: v1.NodeSelectorOpIn, + Values: []string{v1beta1.PlacementScopeRegional}, + }) + ExpectApplied(ctx, env.Client, nodePool, nodeClass) + + pod := coretest.UnschedulablePod() + ExpectProvisionedAndWaitForPromises(ctx, env.Client, clusterNonZonal, cloudProviderNonZonal, coreProvisionerNonZonal, azureEnvNonZonal, pod) + + node := ExpectScheduled(ctx, env.Client, pod) + Expect(node.Labels).To(HaveKeyWithValue(v1.LabelTopologyZone, zones.Regional)) + Expect(node.Labels).To(HaveKeyWithValue(v1beta1.LabelPlacementScope, v1beta1.PlacementScopeRegional)) Expect(azureEnvNonZonal.AKSMachinesAPI.AKSMachineCreateOrUpdateBehavior.CalledWithInput.Len()).To(Equal(1)) aksMachine := azureEnvNonZonal.AKSMachinesAPI.AKSMachineCreateOrUpdateBehavior.CalledWithInput.Pop().AKSMachine Expect(aksMachine.Zones).To(BeEmpty()) }) + It("should not provision in non-zonal regions when placement scope requires zonal", func() { + coretest.ReplaceRequirements(nodePool, karpv1.NodeSelectorRequirementWithMinValues{ + Key: v1beta1.LabelPlacementScope, + Operator: v1.NodeSelectorOpIn, + Values: []string{v1beta1.PlacementScopeZonal}, + }) + ExpectApplied(ctx, env.Client, nodePool, nodeClass) + + pod := coretest.UnschedulablePod() + ExpectProvisionedAndWaitForPromises(ctx, env.Client, clusterNonZonal, cloudProviderNonZonal, coreProvisionerNonZonal, azureEnvNonZonal, pod) + + ExpectNotScheduled(ctx, env.Client, pod) + Expect(azureEnvNonZonal.AKSMachinesAPI.AKSMachineCreateOrUpdateBehavior.CalledWithInput.Len()).To(Equal(0)) + }) + // Ported from VM test: "should support provisioning non-zonal instance types in zonal regions" It("should support provisioning non-zonal instance types in zonal regions", func() { coretest.ReplaceRequirements(nodePool, karpv1.NodeSelectorRequirementWithMinValues{ diff --git a/pkg/providers/allocationstrategy/allocation_strategy_test.go b/pkg/providers/allocationstrategy/allocation_strategy_test.go index 4f34f8b20e..3f67b4750c 100644 --- a/pkg/providers/allocationstrategy/allocation_strategy_test.go +++ b/pkg/providers/allocationstrategy/allocation_strategy_test.go @@ -338,6 +338,27 @@ func TestFilterInstanceOfferings_ZonalOfferingsBeforeRegionalAtSamePriceAndCapac g.Expect(filtered[0].Offerings[0].Requirements.Get(corev1.LabelTopologyZone).Any()).To(Equal("westus-1")) } +func TestFilterInstanceOfferings_ZonalPlacementScopeRejectsRegionalOfferings(t *testing.T) { + g := NewWithT(t) + provider := allocationstrategy.NewProvider() + requirements := scheduling.NewRequirements( + scheduling.NewRequirement(v1beta1.LabelPlacementScope, corev1.NodeSelectorOpIn, v1beta1.PlacementScopeZonal), + ) + + instanceTypes := []*corecloudprovider.InstanceType{ + { + Name: "Standard_Regional", + Offerings: corecloudprovider.Offerings{ + newOfferingWithZone(0.1, karpv1.CapacityTypeOnDemand, zones.Regional), + newOfferingWithZone(0.1, karpv1.CapacityTypeSpot, zones.Regional), + }, + }, + } + + filtered := provider.FilterInstanceOfferings(context.Background(), allocationstrategy.NewInstanceOfferings(instanceTypes), requirements) + g.Expect(filtered).To(BeEmpty()) +} + func TestFilterInstanceOfferings_SpotRegionalOfferingBeforeOnDemandZonalAtSamePrice(t *testing.T) { g := NewWithT(t) provider := allocationstrategy.NewProvider() diff --git a/pkg/providers/instancetype/suite_test.go b/pkg/providers/instancetype/suite_test.go index 4b5591fb5d..a7d5edcc9b 100644 --- a/pkg/providers/instancetype/suite_test.go +++ b/pkg/providers/instancetype/suite_test.go @@ -1860,12 +1860,47 @@ var _ = Describe("InstanceType Provider", func() { ExpectApplied(ctx, env.Client, nodePool, nodeClass) pod := coretest.UnschedulablePod() ExpectProvisionedAndWaitForPromises(ctx, env.Client, clusterNonZonal, cloudProviderNonZonal, coreProvisionerNonZonal, azureEnvNonZonal, pod) - ExpectScheduled(ctx, env.Client, pod) + node := ExpectScheduled(ctx, env.Client, pod) + Expect(node.Labels).To(HaveKeyWithValue(v1.LabelTopologyZone, zones.Regional)) + Expect(node.Labels).To(HaveKeyWithValue(v1beta1.LabelPlacementScope, v1beta1.PlacementScopeRegional)) + + Expect(azureEnvNonZonal.VirtualMachinesAPI.VirtualMachineCreateOrUpdateBehavior.CalledWithInput.Len()).To(Equal(1)) + vm := azureEnvNonZonal.VirtualMachinesAPI.VirtualMachineCreateOrUpdateBehavior.CalledWithInput.Pop().VM + Expect(vm.Zones).To(BeEmpty()) + }) + It("should support regional placement scope in non-zonal regions", func() { + coretest.ReplaceRequirements(nodePool, karpv1.NodeSelectorRequirementWithMinValues{ + Key: v1beta1.LabelPlacementScope, + Operator: v1.NodeSelectorOpIn, + Values: []string{v1beta1.PlacementScopeRegional}, + }) + ExpectApplied(ctx, env.Client, nodePool, nodeClass) + + pod := coretest.UnschedulablePod() + ExpectProvisionedAndWaitForPromises(ctx, env.Client, clusterNonZonal, cloudProviderNonZonal, coreProvisionerNonZonal, azureEnvNonZonal, pod) + + node := ExpectScheduled(ctx, env.Client, pod) + Expect(node.Labels).To(HaveKeyWithValue(v1.LabelTopologyZone, zones.Regional)) + Expect(node.Labels).To(HaveKeyWithValue(v1beta1.LabelPlacementScope, v1beta1.PlacementScopeRegional)) Expect(azureEnvNonZonal.VirtualMachinesAPI.VirtualMachineCreateOrUpdateBehavior.CalledWithInput.Len()).To(Equal(1)) vm := azureEnvNonZonal.VirtualMachinesAPI.VirtualMachineCreateOrUpdateBehavior.CalledWithInput.Pop().VM Expect(vm.Zones).To(BeEmpty()) }) + It("should not provision in non-zonal regions when placement scope requires zonal", func() { + coretest.ReplaceRequirements(nodePool, karpv1.NodeSelectorRequirementWithMinValues{ + Key: v1beta1.LabelPlacementScope, + Operator: v1.NodeSelectorOpIn, + Values: []string{v1beta1.PlacementScopeZonal}, + }) + ExpectApplied(ctx, env.Client, nodePool, nodeClass) + + pod := coretest.UnschedulablePod() + ExpectProvisionedAndWaitForPromises(ctx, env.Client, clusterNonZonal, cloudProviderNonZonal, coreProvisionerNonZonal, azureEnvNonZonal, pod) + + ExpectNotScheduled(ctx, env.Client, pod) + Expect(azureEnvNonZonal.VirtualMachinesAPI.VirtualMachineCreateOrUpdateBehavior.CalledWithInput.Len()).To(Equal(0)) + }) It("should provision non-zonal instance types in zonal regions with zone label 0", func() { coretest.ReplaceRequirements(nodePool, karpv1.NodeSelectorRequirementWithMinValues{ Key: v1.LabelInstanceTypeStable,