Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion internal/controllers/compute/machine_scheduler.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,17 @@ func (s *MachineScheduler) matchesLabels(_ context.Context, pool *scheduler.Cont
return machinePoolSelector.Matches(nodeLabels)
}

func (s *MachineScheduler) poolReady(_ context.Context, pool *scheduler.ContainerInfo) bool {
cond := computev1alpha1.FindMachinePoolCondition(pool.Node().Status.Conditions, computev1alpha1.MachinePoolReady)

return cond != nil && cond.Status == corev1.ConditionTrue
}

func (s *MachineScheduler) tolerateTaints(_ context.Context, pool *scheduler.ContainerInfo, machine *computev1alpha1.Machine) bool {
return v1alpha1.TolerateTaints(machine.Spec.Tolerations, pool.Node().Spec.Taints)
}

func (s *MachineScheduler) fitsPool(_ context.Context, pool *scheduler.ContainerInfo, machine *computev1alpha1.Machine) bool {

return pool.MaxAllocatable(machine.Spec.MachineClassRef.Name) > 0
}

Expand All @@ -102,6 +107,10 @@ func (s *MachineScheduler) reconcileExists(ctx context.Context, log logr.Logger,

var filteredNodes []*scheduler.ContainerInfo
for _, node := range nodes {
if !s.poolReady(ctx, node) {
log.Info("node filtered", "reason", "pool not ready")
continue
}
if !s.tolerateTaints(ctx, node, machine) {
log.Info("node filtered", "reason", "taints do not match")
continue
Expand Down
116 changes: 116 additions & 0 deletions internal/controllers/compute/machine_scheduler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ import (
corev1alpha1 "github.com/ironcore-dev/ironcore/api/core/v1alpha1"
)

func setMachinePoolReady(machinePool *computev1alpha1.MachinePool, status corev1.ConditionStatus) {
machinePool.Status.Conditions = computev1alpha1.SetMachinePoolCondition(machinePool.Status.Conditions,
computev1alpha1.MachinePoolCondition{
Type: computev1alpha1.MachinePoolReady,
Status: status,
})
}

var _ = Describe("MachineScheduler", func() {
ns := SetupNamespace(&k8sClient)
machineClass := SetupMachineClass()
Expand All @@ -40,6 +48,7 @@ var _ = Describe("MachineScheduler", func() {
machinePool.Status.Allocatable = corev1alpha1.ResourceList{
corev1alpha1.ClassCountFor(corev1alpha1.ClassTypeMachineClass, machineClass.Name): resource.MustParse("10"),
}
setMachinePoolReady(machinePool, corev1.ConditionTrue)
})).Should(Succeed())

By("creating a machine w/ the requested machine class")
Expand Down Expand Up @@ -94,6 +103,7 @@ var _ = Describe("MachineScheduler", func() {
machinePool.Status.Allocatable = corev1alpha1.ResourceList{
corev1alpha1.ClassCountFor(corev1alpha1.ClassTypeMachineClass, machineClass.Name): resource.MustParse("10"),
}
setMachinePoolReady(machinePool, corev1.ConditionTrue)
})).Should(Succeed())

By("waiting for the machine to be scheduled onto the machine pool")
Expand All @@ -118,6 +128,7 @@ var _ = Describe("MachineScheduler", func() {
machinePoolNoMatchingLabels.Status.Allocatable = corev1alpha1.ResourceList{
corev1alpha1.ClassCountFor(corev1alpha1.ClassTypeMachineClass, machineClass.Name): resource.MustParse("10"),
}
setMachinePoolReady(machinePoolNoMatchingLabels, corev1.ConditionTrue)
})).Should(Succeed())

By("creating a machine pool w/ matching labels")
Expand All @@ -137,6 +148,7 @@ var _ = Describe("MachineScheduler", func() {
machinePoolMatchingLabels.Status.Allocatable = corev1alpha1.ResourceList{
corev1alpha1.ClassCountFor(corev1alpha1.ClassTypeMachineClass, machineClass.Name): resource.MustParse("10"),
}
setMachinePoolReady(machinePoolMatchingLabels, corev1.ConditionTrue)
})).Should(Succeed())

By("creating a machine w/ the requested machine class")
Expand Down Expand Up @@ -191,6 +203,7 @@ var _ = Describe("MachineScheduler", func() {
taintedMachinePool.Status.Allocatable = corev1alpha1.ResourceList{
corev1alpha1.ClassCountFor(corev1alpha1.ClassTypeMachineClass, machineClass.Name): resource.MustParse("10"),
}
setMachinePoolReady(taintedMachinePool, corev1.ConditionTrue)
})).Should(Succeed())

By("creating a machine")
Expand Down Expand Up @@ -236,6 +249,11 @@ var _ = Describe("MachineScheduler", func() {
})
Expect(k8sClient.Patch(ctx, machine, client.MergeFrom(machineBase))).To(Succeed(), "failed to patch the machine's spec")

By("re-asserting the machine pool is ready")
Eventually(UpdateStatus(taintedMachinePool, func() {
setMachinePoolReady(taintedMachinePool, corev1.ConditionTrue)
})).Should(Succeed())

By("observing the machine is scheduled onto the machine pool")
Eventually(Object(machine)).Should(SatisfyAll(
HaveField("Spec.MachinePoolRef", Equal(&corev1.LocalObjectReference{Name: taintedMachinePool.Name})),
Expand All @@ -257,6 +275,7 @@ var _ = Describe("MachineScheduler", func() {
machinePool.Status.Allocatable = corev1alpha1.ResourceList{
corev1alpha1.ClassCountFor(corev1alpha1.ClassTypeMachineClass, machineClass.Name): resource.MustParse("10"),
}
setMachinePoolReady(machinePool, corev1.ConditionTrue)
})).Should(Succeed())

By("creating a second machine pool")
Expand Down Expand Up @@ -289,6 +308,7 @@ var _ = Describe("MachineScheduler", func() {
corev1alpha1.ClassCountFor(corev1alpha1.ClassTypeMachineClass, machineClass.Name): resource.MustParse("5"),
corev1alpha1.ClassCountFor(corev1alpha1.ClassTypeMachineClass, secondMachineClass.Name): resource.MustParse("100"),
}
setMachinePoolReady(secondMachinePool, corev1.ConditionTrue)
})).Should(Succeed())

By("creating a machine")
Expand Down Expand Up @@ -326,6 +346,7 @@ var _ = Describe("MachineScheduler", func() {
machinePool.Status.Allocatable = corev1alpha1.ResourceList{
corev1alpha1.ClassCountFor(corev1alpha1.ClassTypeMachineClass, machineClass.Name): resource.MustParse("50"),
}
setMachinePoolReady(machinePool, corev1.ConditionTrue)
})).Should(Succeed())

By("creating a second machine pool")
Expand All @@ -344,6 +365,7 @@ var _ = Describe("MachineScheduler", func() {
secondMachinePool.Status.Allocatable = corev1alpha1.ResourceList{
corev1alpha1.ClassCountFor(corev1alpha1.ClassTypeMachineClass, machineClass.Name): resource.MustParse("50"),
}
setMachinePoolReady(secondMachinePool, corev1.ConditionTrue)
})).Should(Succeed())

By("creating machines")
Expand Down Expand Up @@ -394,6 +416,7 @@ var _ = Describe("MachineScheduler", func() {
By("patching the machine pool status to contain a machine class")
Eventually(UpdateStatus(machinePool, func() {
machinePool.Status.AvailableMachineClasses = []corev1.LocalObjectReference{{Name: machineClass.Name}}
setMachinePoolReady(machinePool, corev1.ConditionTrue)
})).Should(Succeed())

By("creating a machine")
Expand All @@ -420,6 +443,7 @@ var _ = Describe("MachineScheduler", func() {
machinePool.Status.Allocatable = corev1alpha1.ResourceList{
corev1alpha1.ClassCountFor(corev1alpha1.ClassTypeMachineClass, machineClass.Name): resource.MustParse("10"),
}
setMachinePoolReady(machinePool, corev1.ConditionTrue)
})).Should(Succeed())

By("checking that the machine is scheduled onto the machine pool")
Expand All @@ -443,6 +467,7 @@ var _ = Describe("MachineScheduler", func() {
machinePool.Status.Allocatable = corev1alpha1.ResourceList{
corev1alpha1.ClassCountFor(corev1alpha1.ClassTypeMachineClass, machineClass.Name): resource.MustParse("2"),
}
setMachinePoolReady(machinePool, corev1.ConditionTrue)
})).Should(Succeed())

By("creating the first machine")
Expand Down Expand Up @@ -512,6 +537,7 @@ var _ = Describe("MachineScheduler", func() {
machinePool.Status.Allocatable = corev1alpha1.ResourceList{
corev1alpha1.ClassCountFor(corev1alpha1.ClassTypeMachineClass, machineClass.Name): resource.MustParse("5"),
}
setMachinePoolReady(machinePool, corev1.ConditionTrue)
})).Should(Succeed())

By("creating a second machine pool")
Expand Down Expand Up @@ -545,6 +571,7 @@ var _ = Describe("MachineScheduler", func() {
corev1alpha1.ClassCountFor(corev1alpha1.ClassTypeMachineClass, machineClass.Name): resource.MustParse("5"),
corev1alpha1.ClassCountFor(corev1alpha1.ClassTypeMachineClass, secondMachineClass.Name): resource.MustParse("5"),
}
setMachinePoolReady(secondMachinePool, corev1.ConditionTrue)
})).Should(Succeed())

By("creating a machine")
Expand All @@ -566,4 +593,93 @@ var _ = Describe("MachineScheduler", func() {
HaveField("Spec.MachinePoolRef.Name", Equal(secondMachinePool.Name)),
))
})

It("should not schedule machines onto a machine pool that is not ready", func(ctx SpecContext) {
Comment thread
gonzolino marked this conversation as resolved.
Outdated
By("creating a machine pool")
machinePool := &computev1alpha1.MachinePool{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "test-pool-",
},
}
Expect(k8sClient.Create(ctx, machinePool)).To(Succeed(), "failed to create machine pool")

By("patching the machine pool status to have capacity but no ready condition")
Eventually(UpdateStatus(machinePool, func() {
machinePool.Status.AvailableMachineClasses = []corev1.LocalObjectReference{{Name: machineClass.Name}}
machinePool.Status.Allocatable = corev1alpha1.ResourceList{
corev1alpha1.ClassCountFor(corev1alpha1.ClassTypeMachineClass, machineClass.Name): resource.MustParse("10"),
}
})).Should(Succeed())

By("creating a machine w/ the requested machine class")
machine := &computev1alpha1.Machine{
ObjectMeta: metav1.ObjectMeta{
Namespace: ns.Name,
GenerateName: "test-machine-",
},
Spec: computev1alpha1.MachineSpec{
MachineClassRef: corev1.LocalObjectReference{Name: machineClass.Name},
},
}
Expect(k8sClient.Create(ctx, machine)).To(Succeed(), "failed to create machine")

By("observing the machine isn't scheduled onto the not-ready machine pool")
Consistently(Object(machine)).Should(HaveField("Spec.MachinePoolRef", BeNil()))

By("marking the machine pool ready")
Eventually(UpdateStatus(machinePool, func() {
setMachinePoolReady(machinePool, corev1.ConditionTrue)
})).Should(Succeed())

By("waiting for the machine to be scheduled once the pool is ready")
Eventually(Object(machine)).Should(SatisfyAll(
HaveField("Spec.MachinePoolRef", Equal(&corev1.LocalObjectReference{Name: machinePool.Name})),
HaveField("Status.State", Equal(computev1alpha1.MachineStatePending)),
))
})

It("should not schedule machines onto a machine pool whose ready condition is false", func(ctx SpecContext) {
By("creating a machine pool")
machinePool := &computev1alpha1.MachinePool{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "test-pool-",
},
}
Expect(k8sClient.Create(ctx, machinePool)).To(Succeed(), "failed to create machine pool")

By("patching the machine pool status to have capacity but a ready condition of false")
Eventually(UpdateStatus(machinePool, func() {
machinePool.Status.AvailableMachineClasses = []corev1.LocalObjectReference{{Name: machineClass.Name}}
machinePool.Status.Allocatable = corev1alpha1.ResourceList{
corev1alpha1.ClassCountFor(corev1alpha1.ClassTypeMachineClass, machineClass.Name): resource.MustParse("10"),
}
setMachinePoolReady(machinePool, corev1.ConditionFalse)
})).Should(Succeed())

By("creating a machine w/ the requested machine class")
machine := &computev1alpha1.Machine{
ObjectMeta: metav1.ObjectMeta{
Namespace: ns.Name,
GenerateName: "test-machine-",
},
Spec: computev1alpha1.MachineSpec{
MachineClassRef: corev1.LocalObjectReference{Name: machineClass.Name},
},
}
Expect(k8sClient.Create(ctx, machine)).To(Succeed(), "failed to create machine")

By("observing the machine isn't scheduled onto the not-ready machine pool")
Consistently(Object(machine)).Should(HaveField("Spec.MachinePoolRef", BeNil()))

By("marking the machine pool ready")
Eventually(UpdateStatus(machinePool, func() {
setMachinePoolReady(machinePool, corev1.ConditionTrue)
})).Should(Succeed())

By("waiting for the machine to be scheduled once the pool is ready")
Eventually(Object(machine)).Should(SatisfyAll(
HaveField("Spec.MachinePoolRef", Equal(&corev1.LocalObjectReference{Name: machinePool.Name})),
HaveField("Status.State", Equal(computev1alpha1.MachineStatePending)),
))
})
})