From 3e93314a09b9d509a4705a985b4ec4e0dd3c7b5c Mon Sep 17 00:00:00 2001 From: Oleksii Kurinnyi Date: Thu, 17 Apr 2025 15:20:50 +0300 Subject: [PATCH 1/2] fix: common PVC cleanup job to be assigned to a correct node Signed-off-by: Oleksii Kurinnyi --- pkg/constants/constants.go | 5 ++++ pkg/provision/storage/cleanup.go | 45 ++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index 8087aad7e..01fc15b26 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -96,3 +96,8 @@ const ( // ProjectCloneDisable specifies that project cloning should be disabled. ProjectCloneDisable = "disable" ) + +const ( + // This annotation is added to a PVC that is triggered by a scheduler to be dynamically provisioned. Its value is the name of the selected node. + SelectedNodeAnnotation = "volume.kubernetes.io/selected-node" +) diff --git a/pkg/provision/storage/cleanup.go b/pkg/provision/storage/cleanup.go index f9e4e4987..758d58cc8 100644 --- a/pkg/provision/storage/cleanup.go +++ b/pkg/provision/storage/cleanup.go @@ -120,6 +120,13 @@ func getSpecCommonPVCCleanupJob(workspace *common.DevWorkspaceWithConfig, cluste pvcName = workspace.Config.Workspace.PVCName } + targetNode, err := getCommonPVCTargetNode(workspace, clusterAPI) + if err != nil { + clusterAPI.Logger.Info("Error getting target node for PVC", "PVC", fmt.Sprintf("%s/%s", workspace.Namespace, workspace.Config.Workspace.PVCName), "error", err) + } else if targetNode == "" { + clusterAPI.Logger.Info("PVC does not have a target node annotation", "PVC", fmt.Sprintf("%s/%s", workspace.Namespace, workspace.Config.Workspace.PVCName)) + } + jobLabels := map[string]string{ constants.DevWorkspaceIDLabel: workspaceId, constants.DevWorkspaceNameLabel: workspace.Name, @@ -189,11 +196,30 @@ func getSpecCommonPVCCleanupJob(workspace *common.DevWorkspaceWithConfig, cluste }, }, }, + Affinity: &corev1.Affinity{}, }, }, }, } + if targetNode != "" { + job.Spec.Template.Spec.Affinity.NodeAffinity = &corev1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{ + { + MatchExpressions: []corev1.NodeSelectorRequirement{ + { + Key: "kubernetes.io/hostname", + Operator: corev1.NodeSelectorOpIn, + Values: []string{targetNode}, + }, + }, + }, + }, + }, + } + } + podTolerations, nodeSelector, err := nsconfig.GetNamespacePodTolerationsAndNodeSelector(workspace.Namespace, clusterAPI) if err != nil { return nil, err @@ -226,3 +252,22 @@ func commonPVCExists(workspace *common.DevWorkspaceWithConfig, clusterAPI sync.C } return true, nil } + +func getCommonPVCTargetNode(workspace *common.DevWorkspaceWithConfig, clusterAPI sync.ClusterAPI) (string, error) { + namespacedName := types.NamespacedName{ + Name: workspace.Config.Workspace.PVCName, + Namespace: workspace.Namespace, + } + pvc := &corev1.PersistentVolumeClaim{} + err := clusterAPI.Client.Get(clusterAPI.Ctx, namespacedName, pvc) + if err != nil { + return "", err + } + + targetNode := "" + if pvc.Annotations != nil { + targetNode = pvc.Annotations[constants.SelectedNodeAnnotation] + } + + return targetNode, nil +} From a5dce39a8574bbf1fef0ce5de0ce18fce80c97ab Mon Sep 17 00:00:00 2001 From: Oleksii Kurinnyi Date: Wed, 7 May 2025 11:18:16 +0300 Subject: [PATCH 2/2] Update pkg/constants/constants.go Co-authored-by: Rohan Kumar Signed-off-by: Oleksii Kurinnyi --- pkg/constants/constants.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index 01fc15b26..b63830659 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -98,6 +98,6 @@ const ( ) const ( - // This annotation is added to a PVC that is triggered by a scheduler to be dynamically provisioned. Its value is the name of the selected node. + // SelectedNodeAnnotation annotation is added to a PVC that is triggered by a scheduler to be dynamically provisioned. Its value is the name of the selected node. SelectedNodeAnnotation = "volume.kubernetes.io/selected-node" )