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

Allow to delete queue-name on deployment. #3648

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
16 changes: 10 additions & 6 deletions pkg/controller/jobs/deployment/deployment_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"

"sigs.k8s.io/kueue/pkg/controller/constants"
"sigs.k8s.io/kueue/pkg/constants"
controllerconsts "sigs.k8s.io/kueue/pkg/controller/constants"
"sigs.k8s.io/kueue/pkg/controller/jobframework"
"sigs.k8s.io/kueue/pkg/controller/jobframework/webhook"
"sigs.k8s.io/kueue/pkg/controller/jobs/pod"
Expand Down Expand Up @@ -83,7 +84,11 @@ func (wh *Webhook) Default(ctx context.Context, obj runtime.Object) error {
}
queueName := jobframework.QueueNameForObject(deployment.Object())
if queueName != "" {
deployment.Spec.Template.Labels[constants.QueueLabel] = queueName
deployment.Labels[constants.ManagedByKueueLabel] = "true"
deployment.Spec.Template.Labels[controllerconsts.QueueLabel] = queueName
} else if deployment.Labels[constants.ManagedByKueueLabel] == "true" {
delete(deployment.Labels, constants.ManagedByKueueLabel)
delete(deployment.Spec.Template.Labels, controllerconsts.QueueLabel)
}
}

Expand All @@ -107,7 +112,7 @@ func (wh *Webhook) ValidateCreate(ctx context.Context, obj runtime.Object) (warn

var (
labelsPath = field.NewPath("metadata", "labels")
queueNameLabelPath = labelsPath.Key(constants.QueueLabel)
queueNameLabelPath = labelsPath.Key(controllerconsts.QueueLabel)
)

func (wh *Webhook) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (warnings admission.Warnings, err error) {
Expand All @@ -123,9 +128,8 @@ func (wh *Webhook) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Ob
allErrs := field.ErrorList{}
allErrs = append(allErrs, jobframework.ValidateQueueName(newDeployment.Object())...)

// Prevents updating the queue-name if at least one Pod is not suspended
// or if the queue-name has been deleted.
if oldDeployment.Status.ReadyReplicas > 0 || newQueueName == "" {
// Prevents updating the queue-name if at least one Pod is not suspended.
if oldDeployment.Status.ReadyReplicas > 0 {
allErrs = append(allErrs, apivalidation.ValidateImmutableField(oldQueueName, newQueueName, queueNameLabelPath)...)
}

Expand Down
20 changes: 18 additions & 2 deletions pkg/controller/jobs/deployment/deployment_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ func TestDefault(t *testing.T) {
Obj(),
want: testingdeployment.MakeDeployment("test-pod", "").
Queue("test-queue").
ManagedByKueue().
PodTemplateSpecQueue("test-queue").
PodTemplateAnnotation(pod.SuspendedByParentAnnotation, FrameworkName).
Obj(),
Expand All @@ -62,6 +63,7 @@ func TestDefault(t *testing.T) {
Obj(),
want: testingdeployment.MakeDeployment("test-pod", "").
Queue("new-test-queue").
ManagedByKueue().
PodTemplateSpecQueue("new-test-queue").
PodTemplateAnnotation(pod.SuspendedByParentAnnotation, FrameworkName).
Obj(),
Expand All @@ -70,6 +72,13 @@ func TestDefault(t *testing.T) {
deployment: testingdeployment.MakeDeployment("test-pod", "").PodTemplateSpecQueue("test-queue").Obj(),
want: testingdeployment.MakeDeployment("test-pod", "").PodTemplateSpecQueue("test-queue").Obj(),
},
"deployment without queue with pod template spec queue and managed by kueue label": {
deployment: testingdeployment.MakeDeployment("test-pod", "").
ManagedByKueue().
PodTemplateSpecQueue("test-queue").
Obj(),
want: testingdeployment.MakeDeployment("test-pod", "").Obj(),
},
"LocalQueueDefaulting enabled, default lq is created, job doesn't have queue label": {
localQueueDefaulting: true,
defaultLqExist: true,
Expand Down Expand Up @@ -123,7 +132,7 @@ func TestDefault(t *testing.T) {
if err := w.Default(ctx, tc.deployment); err != nil {
t.Errorf("failed to set defaults for v1/deployment: %s", err)
}
if diff := cmp.Diff(tc.want, tc.deployment); len(diff) != 0 {
if diff := cmp.Diff(tc.want, tc.deployment, cmpopts.EquateEmpty()); len(diff) != 0 {
t.Errorf("Default() mismatch (-want,+got):\n%s", diff)
}
})
Expand Down Expand Up @@ -190,11 +199,18 @@ func TestValidateUpdate(t *testing.T) {
oldDeployment: testingdeployment.MakeDeployment("test-pod", "").Obj(),
newDeployment: testingdeployment.MakeDeployment("test-pod", "").Obj(),
},
"without queue": {
"without queue (ReadyReplicas = 0)": {
oldDeployment: testingdeployment.MakeDeployment("test-pod", "").
Queue("test-queue").
Obj(),
newDeployment: testingdeployment.MakeDeployment("test-pod", "").Obj(),
},
"without queue (ReadyReplicas > 0)": {
oldDeployment: testingdeployment.MakeDeployment("test-pod", "").
ReadyReplicas(1).
Queue("test-queue").
Obj(),
newDeployment: testingdeployment.MakeDeployment("test-pod", "").Obj(),
wantErr: field.ErrorList{
&field.Error{
Type: field.ErrorTypeInvalid,
Expand Down
12 changes: 9 additions & 3 deletions pkg/util/testingjobs/deployment/wrappers.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ import (
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"sigs.k8s.io/kueue/pkg/controller/constants"
"sigs.k8s.io/kueue/pkg/constants"
controllerconstants "sigs.k8s.io/kueue/pkg/controller/constants"
)

// DeploymentWrapper wraps a Deployment.
Expand Down Expand Up @@ -82,7 +83,12 @@ func (d *DeploymentWrapper) Label(k, v string) *DeploymentWrapper {

// Queue updates the queue name of the Deployment
func (d *DeploymentWrapper) Queue(q string) *DeploymentWrapper {
return d.Label(constants.QueueLabel, q)
return d.Label(controllerconstants.QueueLabel, q)
}

// ManagedByKueue updates the queue name of the Deployment
func (d *DeploymentWrapper) ManagedByKueue() *DeploymentWrapper {
return d.Label(constants.ManagedByKueueLabel, "true")
}

// Name updated the name of the Deployment
Expand Down Expand Up @@ -139,5 +145,5 @@ func (d *DeploymentWrapper) PodTemplateAnnotation(k, v string) *DeploymentWrappe

// PodTemplateSpecQueue updates the queue name of the pod template spec of the Deployment
func (d *DeploymentWrapper) PodTemplateSpecQueue(q string) *DeploymentWrapper {
return d.PodTemplateSpecLabel(constants.QueueLabel, q)
return d.PodTemplateSpecLabel(controllerconstants.QueueLabel, q)
}
2 changes: 1 addition & 1 deletion test/e2e/singlecluster/deployment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ var _ = ginkgo.Describe("Deployment", func() {
g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(deployment), createdDeployment)).To(gomega.Succeed())
g.Expect(createdDeployment.Status.Replicas).To(gomega.Equal(int32(3)))
g.Expect(createdDeployment.Status.UnavailableReplicas).To(gomega.Equal(int32(3)))
g.Expect(createdDeployment.Status.AvailableReplicas).To(gomega.Equal(int32(0)))
g.Expect(createdDeployment.Status.ReadyReplicas).To(gomega.Equal(int32(0)))
}, util.Timeout, util.Interval).Should(gomega.Succeed())
})

Expand Down
28 changes: 27 additions & 1 deletion test/integration/webhook/jobs/deployment_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,18 @@ var _ = ginkgo.Describe("Deployment Webhook", ginkgo.Ordered, ginkgo.ContinueOnF
})
})

ginkgo.It("shouldn't allow to remove the queue label", func() {
ginkgo.It("shouldn't allow to remove the queue label (ReadyReplicas > 0)", func() {
createdDeployment := &appsv1.Deployment{}

ginkgo.By("Update status ReadyReplicas = 1", func() {
gomega.Eventually(func(g gomega.Gomega) {
g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(deployment), createdDeployment)).Should(gomega.Succeed())
createdDeployment.Status.Replicas = 1
createdDeployment.Status.ReadyReplicas = 1
gomega.Expect(k8sClient.Status().Update(ctx, createdDeployment)).To(gomega.Succeed())
}, util.Timeout, util.Interval).Should(gomega.Succeed())
})

ginkgo.By("Try to remove queue label", func() {
gomega.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(deployment), createdDeployment)).Should(gomega.Succeed())
delete(createdDeployment.Labels, constants.QueueLabel)
Expand All @@ -131,6 +140,23 @@ var _ = ginkgo.Describe("Deployment Webhook", ginkgo.Ordered, ginkgo.ContinueOnF
})
})

ginkgo.It("should allow to remove the queue label (ReadyReplicas = 0)", func() {
createdDeployment := &appsv1.Deployment{}

ginkgo.By("Try to remove queue label", func() {
gomega.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(deployment), createdDeployment)).Should(gomega.Succeed())
delete(createdDeployment.Labels, constants.QueueLabel)
gomega.Expect(k8sClient.Update(ctx, createdDeployment)).To(gomega.Succeed())
})

ginkgo.By("Check that queue label deleted from pod template spec", func() {
gomega.Eventually(func(g gomega.Gomega) {
g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(deployment), createdDeployment)).Should(gomega.Succeed())
g.Expect(createdDeployment.Spec.Template.Labels).ShouldNot(gomega.HaveKey(constants.QueueLabel))
}, util.Timeout, util.Interval).Should(gomega.Succeed())
})
})

ginkgo.It("shouldn't allow to change the queue name (ReadyReplicas > 0)", func() {
createdDeployment := &appsv1.Deployment{}

Expand Down