Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add a new field called minValues that introduces flexibility to the NodePool requirement. #1

Merged
merged 29 commits into from
Feb 21, 2024

Conversation

nikmohan123
Copy link
Owner

@nikmohan123 nikmohan123 commented Feb 9, 2024

Description
This PR adds minValues flexibility to the NodePool requirement. The new NodePool requirement will be represented as:

type NodeSelectorRequirementWithMinValues struct {
	v1.NodeSelectorRequirement `json:",inline"`
	// MinValues is the minimum number of unique values required to define the flexibility of the specific requirement.
	// +kubebuilder:validation:Minimum:=1
	// +kubebuilder:validation:Maximum:=100
	// +optional
	MinValues *int `json:"minValues,omitempty"`
}

minValues represents the minimum number of unique values that needs to be considered for a particular requirement. So, this value ensures that the scheduler creates NodeClaims meeting this new requirement.

This PR has a corresponding changes in the karpenter aws-cloud-provider and is sent as a separate PR: aws/karpenter-provider-aws#5640

The main changes in the PR is related to changing the requirement struct to a new one that has flexibility of minValues in it and adding the new minValues field to the API and wire it to scheduler/consolidation layer. This PR tracks the already sent out PR: kubernetes-sigs#963 that has the core scheduler/consolidation layer changes.

How was this change tested?
Added functional test.
Manually tested by passing in the minValues through different requirements and checked the CreateFleet inputs to see if all the requirements were met for the NodeClaim.

TODO: Add more functional tests around consolidation and probably around more requirement keys.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@@ -38,7 +38,7 @@ type NodeClaimSpec struct {
// +kubebuilder:validation:XValidation:message="requirements operator 'Gt' or 'Lt' must have a single positive integer value",rule="self.all(x, (x.operator == 'Gt' || x.operator == 'Lt') ? (x.values.size() == 1 && int(x.values[0]) >= 0) : true)"
// +kubebuilder:validation:MaxItems:=30
// +required
Requirements []v1.NodeSelectorRequirement `json:"requirements" hash:"ignore"`
Requirements []NodeSelectorRequirementWithFlexibility `json:"requirements" hash:"ignore"`

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Requirements []NodeSelectorRequirementWithFlexibility `json:"requirements" hash:"ignore"`
Requirements []NodeSelectorRequirement`json:"requirements" hash:"ignore"`

Any reason to make this more verbose? Or can we just call this the Karpenter version of the NodeSelectorRequirement

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed offline that we would go with NodeSelectorRequirementWithMinValues since the K8 NodeSelectorRequirement is also used in the code which might cause confusion. Changed to this.

// which represents the minimum number of unique values that needs to be considered for a particular requirement.
type NodeSelectorRequirementWithFlexibility struct {
v1.NodeSelectorRequirement `json:",inline"`
// This is an alpha field.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// This is an alpha field.
// This field is ALPHA and can be dropped or replaced at any time

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed.

@@ -54,6 +54,18 @@ type NodeClaimSpec struct {
NodeClassRef *NodeClassReference `json:"nodeClassRef"`
}

// NodeSelectorRequirementWithFlexibility introduces flexibility to the NodeSelectorRequirement through minValues
// which represents the minimum number of unique values that needs to be considered for a particular requirement.
type NodeSelectorRequirementWithFlexibility struct {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a CEL expression here that does the same check that you have in the validation code around if we have less values listed in the requirement compared to the minValues that have been specified. If you need some help getting that CEL written, I can definitely help out with that

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added. Thanks.

}
Expect(env.Client.Create(ctx, nodeClaim)).ToNot(Succeed())
})
It("should error when minValues is more than 50", func() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have a check here that validates that we don't have fewer values in a NodeSelectorRequirement with the "In" operator than the minValues that are specified?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, seems like I added this in webhook test and missed it here. Thanks. Added it here as well.

}
Expect(env.Client.Create(ctx, nodePool)).ToNot(Succeed())
})
It("should error when minValues is more than 50", func() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question here: Probably a validation on the number of values relative to the minValues specified is warranted

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, seems like I added this in webhook test and missed it here. Thanks. Added it here as well.

Available: true,
},
}
instanceTypes = append(instanceTypes, fake.NewInstanceType(opts1))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth creating 4 instance types here to ensure that Karpenter is actually fulfilling both of the requirements. This test could theoretically pass on the instance type requirement alone.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since minValues for InstanceTypes is 1 and we have an instance that definitely fits both the pods and is a cheaper option, it will always have 1 instance in the nodeclaim if not for the arch label which demands at least 2 in this case and hence the nodeclaim will have 2 instances because each one has different architecture.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. Does it even make sense to have a minValues of 1 on the instance type? I don't really think that is really doing anything honestly since we already require that at least one value exist for us to be able to launch and bind.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine if we capture this in some of the other testing improvements and take care of this in a follow-on if that's eaisier.

@@ -603,4 +643,357 @@ var _ = Describe("Instance Type Selection", func() {
node := ExpectScheduled(ctx, env.Client, pod)
Expect(node.Labels[v1.LabelInstanceTypeStable]).To(Equal("test-instance1"))
})
It("should schedule respecting the minValues from instance-type requirements", func() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to validate minValues with other types of operators here? We are testing In a bunch (which is good) but should we also test NotIn, Gt, Lt , Exists and NotExists?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have added combinations and individual tests on NotIn, Gt, Lt and Exists operators. I think NotExists anyways wouldn't schedule the pods and we have tests for that. minValues is going to be a no-op there and we have tests in requirements_test file to get the intersections.

NodeSelectorRequirement: v1.NodeSelectorRequirement{
Key: v1beta1.CapacityTypeLabelKey,
Operator: v1.NodeSelectorOpExists,
},
},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need a test with topology here to validate that topology won't work from an application with minValues. It's definitely a weird thing to ensure, but it validates our understanding of how the whole system fits together. Something like "should not succeed to meet minValues when using topologySpread on the same key"

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added.

@@ -88,14 +100,14 @@ func newPodRequirements(pod *v1.Pod, typ podRequirementType) Requirements {
// Select heaviest preference and treat as a requirement. An outer loop will iteratively unconstrain them if unsatisfiable.
if preferred := pod.Spec.Affinity.NodeAffinity.PreferredDuringSchedulingIgnoredDuringExecution; len(preferred) > 0 {
sort.Slice(preferred, func(i int, j int) bool { return preferred[i].Weight > preferred[j].Weight })
requirements.Add(NewNodeSelectorRequirements(preferred[0].Preference.MatchExpressions...).Values()...)
requirements.Add(NewNodeSelectorRequirements(ConvertNodeSelectorRequirementToNodeSelectorRequirementWithFlexibility(preferred[0].Preference.MatchExpressions...)...).Values()...)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than converting everything here, is it better to just create a different Add() function that can handle nodeSelectorRequirements without flexibility? I think that's going to result in less code churn and less memory utilization overall

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, good idea. Thanks. Changed it.

@@ -25,6 +25,8 @@ import (
. "github.com/onsi/gomega"
"github.com/samber/lo"
v1 "k8s.io/api/core/v1"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have a test in here that validates that when we add multiple requirements that have the same key and are using minValues that we take the max of the two minValues?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have it added here already. Are we talking about the same thing ?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, got it. I think I got confused because we have both a requirement_test.go file and a requirements_test.go file

@@ -54,6 +55,18 @@ type NodeClaimSpec struct {
NodeClassRef *NodeClassReference `json:"nodeClassRef"`
}

// NodeSelectorRequirementWithMinValues introduces flexibility to the NodeSelectorRequirement through minValues

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we should try to match our description for this NodeSelectorRequirement to be close to the upstream one but with an addendum that says that you can specify minValues on it?

This is the upstream description

A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only reason that I'm calling this out is because this gets put into the CRD description that gets auto-generated by the change

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. Changed it to closely mimic that.

// A node selector requirement with min values is a selector that contains values, a key, an operator that relates the key and values
// and minValues that represent the requirement to have at least that many values.

Let me know if this sounds good.

@@ -36,9 +36,10 @@ type NodeClaimSpec struct {
// Requirements are layered with GetLabels and applied to every node.
// +kubebuilder:validation:XValidation:message="requirements with operator 'In' must have a value defined",rule="self.all(x, x.operator == 'In' ? x.values.size() != 0 : true)"
// +kubebuilder:validation:XValidation:message="requirements operator 'Gt' or 'Lt' must have a single positive integer value",rule="self.all(x, (x.operator == 'Gt' || x.operator == 'Lt') ? (x.values.size() == 1 && int(x.values[0]) >= 0) : true)"
// +kubebuilder:validation:XValidation:message="requirements with 'minValues' must have minimum values defined",rule="self.all(x, (x.operator == 'In' && has(x.minValues)) ? x.values.size() >= x.minValues : true)"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// +kubebuilder:validation:XValidation:message="requirements with 'minValues' must have minimum values defined",rule="self.all(x, (x.operator == 'In' && has(x.minValues)) ? x.values.size() >= x.minValues : true)"
// +kubebuilder:validation:XValidation:message="requirements with 'minValues' must have at least that many values specified in the "values" field",rule="self.all(x, (x.operator == 'In' && has(x.minValues)) ? x.values.size() >= x.minValues : true)"

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed.

@@ -163,6 +163,11 @@ func ValidateRequirement(requirement v1.NodeSelectorRequirement) error { //nolin
if requirement.Operator == v1.NodeSelectorOpIn && len(requirement.Values) == 0 {
errs = multierr.Append(errs, fmt.Errorf("key %s with operator %s must have a value defined", requirement.Key, requirement.Operator))
}

if requirement.Operator == v1.NodeSelectorOpIn && requirement.MinValues != nil && len(requirement.Values) < lo.FromPtr(requirement.MinValues) {
errs = multierr.Append(errs, fmt.Errorf("key %s with operator %s must have at least minimum number of values defined", requirement.Key, requirement.Operator))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
errs = multierr.Append(errs, fmt.Errorf("key %s with operator %s must have at least minimum number of values defined", requirement.Key, requirement.Operator))
errs = multierr.Append(errs, fmt.Errorf("key %s with operator %s must have at least minimum number of values defined in 'values' field", requirement.Key, requirement.Operator))

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed.

Expect(env.Client.Create(ctx, nodeClaim)).ToNot(Succeed())
}
})
It("should error when minValues is negative", func() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like we shouldn't just test that it's negative. Seems like 0 is also invalid here as well

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Added.

})
It("should error when minValues is more than 50", func() {
nodeClaim.Spec.Requirements = []NodeSelectorRequirementWithMinValues{
{NodeSelectorRequirement: v1.NodeSelectorRequirement{Key: v1.LabelInstanceTypeStable, Operator: v1.NodeSelectorOpIn, Values: []string{"c4.large"}}, MinValues: lo.ToPtr(51)},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which part of CEL does this fail on? The values check or the In requirement has enough values check? Seems like you should use an Exists here to ensure that we are only failing on the exact thing that we are testing

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the ambiguity now. I was under the impression that this wouldn't even get to the point of trying to check how many values in the requirement to meet the minValues given that it should fail at the validation of minValues itself. I will change the operator.

@@ -603,4 +644,930 @@ var _ = Describe("Instance Type Selection", func() {
node := ExpectScheduled(ctx, env.Client, pod)
Expect(node.Labels[v1.LabelInstanceTypeStable]).To(Equal("test-instance1"))
})
It("should schedule respecting the minValues from instance-type requirements", func() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since these are all MinValues tests, do they deserve their own Context block in this suite_test.go file?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, definitely. Changed it. Thanks.

ExpectApplied(ctx, env.Client, nodePool)
pods := test.UnschedulablePods(test.PodOptions{ObjectMeta: metav1.ObjectMeta{Labels: labels}, TopologySpreadConstraints: topology}, 4)
ExpectProvisioned(ctx, env.Client, cluster, cloudProvider, prov, pods...)
ExpectNotScheduled(ctx, env.Client, pods[0])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we explain why we expect the topology spread to fail here? It'll make it a little easier to parse out in the future. Essentially, we know that we have to select a value when we are using topologySpread, which directly constrains us down to 1 value, so asking for more than that 1 value on that key isn't possible for Karpenter to reason about today

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added this stmt. Thanks.

@@ -25,6 +25,8 @@ import (
. "github.com/onsi/gomega"
"github.com/samber/lo"
v1 "k8s.io/api/core/v1"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, got it. I think I got confused because we have both a requirement_test.go file and a requirements_test.go file

@@ -25,9 +25,12 @@ import (
"github.com/samber/lo"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something to think about (maybe for a different PR): Is there a way to categorize these tests better so they are more organized for someone who is trying to make changes and is coming at this file fresh?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you. This test file escalated quickly with a lot more changes than I expected with the combinations I had in my mind for intersections. I can take this as a follow-up item to see how I can get this to a better shape.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. Worth tracking as a GH issue so that there's visibility generally? Could just call it "improve requirement testing organization" and mark it as a chore

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created one : kubernetes-sigs#1024

@@ -1483,6 +1483,354 @@ var _ = Describe("Consolidation", func() {
// and delete the old one
ExpectNotFound(ctx, env.Client, spotNodeClaim, spotNode)
})
It("spot to spot consolidation should consider the max of default and minimum number of instanceTypeOptions from minValues in requirement for truncation.", func() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
It("spot to spot consolidation should consider the max of default and minimum number of instanceTypeOptions from minValues in requirement for truncation.", func() {
It("spot to spot consolidation should consider the max of default and minimum number of instanceTypeOptions from minValues in requirement for truncation if minimum number of instanceTypeOptions from minValues in requirement is greater than 15.", func() {

nit: This part would just help provide a little more clarity so that I can understand exactly what is being tested here and it also provides parity with the next test case

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

})
It("should error when minValues is more than 50", func() {
nodePool.Spec.Template.Spec.Requirements = []NodeSelectorRequirementWithMinValues{
{NodeSelectorRequirement: v1.NodeSelectorRequirement{Key: v1.LabelInstanceTypeStable, Operator: v1.NodeSelectorOpExists, Values: []string{"insance-type-1"}}, MinValues: lo.ToPtr(51)},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can't specify values with an Exists requirement, or at least you shouldn't. Really, we shouldn't be allowing it, what's correct is to have no values with the Exists operator

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected it.

@@ -603,4 +644,932 @@ var _ = Describe("Instance Type Selection", func() {
node := ExpectScheduled(ctx, env.Client, pod)
Expect(node.Labels[v1.LabelInstanceTypeStable]).To(Equal("test-instance1"))
})
Context("Scheduler behavior for requirements with minValues", func() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Context("Scheduler behavior for requirements with minValues", func() {
Context("MinValues", func() {

nit: I'd personally just shorten it

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed.

Copy link

@jonathan-innis jonathan-innis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🚀 Approved with some nits

})
It("should schedule respecting the minValues in Gt operator.", func() {
// custom key that will help us with numerical values to be used for Gt operator
instanceGeneration := "karpenter/numerical-value"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
instanceGeneration := "karpenter/numerical-value"
numericalRequirementKey := v1beta1.Group + "/numerical-value"

nit: Typically you prefix with the group name

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't allow you do attach the label with karpenter.sh as it complains that it is a restricted label like I said here.

Error:

got an error:
      <*errors.StatusError | 0x1400069a1e0>:
      NodePool.karpenter.sh "speakerleather-1-znthvad9w8" is invalid: spec.template.spec.requirements[0].key: Invalid value: "string": label domain "karpenter.sh" is restricted
      {

So, not fixing this and for the rest.

})
It("scheduler should fail if the minValues in Gt operator is not satisfied.", func() {
// custom key that will help us with numerical values to be used for Gt operator
instanceGeneration := "karpenter/numerical-value"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
instanceGeneration := "karpenter/numerical-value"
numericalRequirementKey := v1beta1.Group + "/numerical-value"

Same comment here

})
It("should schedule respecting the minValues in Lt operator.", func() {
// custom key that will help us with numerical values to be used for Lt operator
instanceGeneration := "karpenter/numerical-value"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
instanceGeneration := "karpenter/numerical-value"
numericalRequirementKey := v1beta1.Group + "/numerical-value"

})
It("scheduler should fail if the minValues in Lt operator is not satisfied.", func() {
// custom key that will help us with numerical values to be used for Lt operator
instanceGeneration := "karpenter/numerical-value"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
instanceGeneration := "karpenter/numerical-value"
numericalRequirementKey := v1beta1.Group + "/numerical-value"

})
It("should schedule considering the max of the minValues of Gt and Lt operators.", func() {
// custom key that will help us with numerical values to be used for Gt operator
instanceGeneration := "karpenter/numerical-value"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
instanceGeneration := "karpenter/numerical-value"
numericalRequirementKey := v1beta1.Group + "/numerical-value"

// Ensures that NodeClaims are created with 2 instanceTypes
Expect(len(supportedInstanceTypes(cloudProvider.CreateCalls[0]))).To(BeNumerically(">=", 2))
})
It("should schedule respecting the minValues in Gt operator.", func() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
It("should schedule respecting the minValues in Gt operator.", func() {
It("should schedule respecting the minValues in Gt operator", func() {

nit

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

// Ensures that NodeClaims are created with 2 instanceTypes
Expect(len(supportedInstanceTypes(cloudProvider.CreateCalls[0]))).To(BeNumerically(">=", 2))
})
It("scheduler should fail if the minValues in Gt operator is not satisfied.", func() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
It("scheduler should fail if the minValues in Gt operator is not satisfied.", func() {
It("scheduler should fail if the minValues in Gt operator is not satisfied", func() {

nit

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

ExpectNotScheduled(ctx, env.Client, pod1)
ExpectNotScheduled(ctx, env.Client, pod2)
})
It("should schedule respecting the minValues in Lt operator.", func() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
It("should schedule respecting the minValues in Lt operator.", func() {
It("should schedule respecting the minValues in Lt operator", func() {

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

// Ensures that NodeClaims are created with 2 instanceTypes
Expect(len(supportedInstanceTypes(cloudProvider.CreateCalls[0]))).To(BeNumerically(">=", 2))
})
It("scheduler should fail if the minValues in Lt operator is not satisfied.", func() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
It("scheduler should fail if the minValues in Lt operator is not satisfied.", func() {
It("scheduler should fail if the minValues in Lt operator is not satisfied", func() {

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

// Ensures that NodeClaims are created with 2 instanceTypes
Expect(len(supportedInstanceTypes(cloudProvider.CreateCalls[0]))).To(BeNumerically(">=", 2))
})
It("should schedule and respect multiple requirement keys with minValues.", func() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
It("should schedule and respect multiple requirement keys with minValues.", func() {
It("should schedule and respect multiple requirement keys with minValues", func() {

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link

@jonathan-innis jonathan-innis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🚀

Copy link

@jonathan-innis jonathan-innis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🚀

@nikmohan123 nikmohan123 merged commit 8af4c61 into cps_final Feb 21, 2024
3 of 10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants