diff --git a/internal/k8s/jobs.go b/internal/k8s/jobs.go index 263d5e8..482c96c 100644 --- a/internal/k8s/jobs.go +++ b/internal/k8s/jobs.go @@ -107,6 +107,9 @@ func (c *Client) CreateBackupJob(ctx context.Context, cfg *config.Config, req ap } job := buildBackupJob(cfg, req, jobName, secretName) + if nodeName, err := c.resolvePVCMountedNode(ctx, req.Namespace, req.PVC); err == nil && nodeName != "" { + job.Spec.Template.Spec.NodeName = nodeName + } created, err := c.Clientset.BatchV1().Jobs(req.Namespace).Create(ctx, job, metav1.CreateOptions{}) if err != nil { _ = c.Clientset.CoreV1().Secrets(req.Namespace).Delete(ctx, secretName, metav1.DeleteOptions{}) @@ -120,6 +123,33 @@ func (c *Client) CreateBackupJob(ctx context.Context, cfg *config.Config, req ap return jobName, secretName, nil } +func (c *Client) resolvePVCMountedNode(ctx context.Context, namespace, pvc string) (string, error) { + pods, err := c.Clientset.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{}) + if err != nil { + return "", err + } + + for _, pod := range pods.Items { + if pod.DeletionTimestamp != nil || pod.Spec.NodeName == "" { + continue + } + if pod.Status.Phase == corev1.PodSucceeded || pod.Status.Phase == corev1.PodFailed { + continue + } + for _, volume := range pod.Spec.Volumes { + claim := volume.PersistentVolumeClaim + if claim == nil { + continue + } + if claim.ClaimName == pvc { + return pod.Spec.NodeName, nil + } + } + } + + return "", nil +} + func (c *Client) CreateRestoreJob(ctx context.Context, cfg *config.Config, req api.RestoreTestRequest) (string, string, error) { if req.Namespace == "" { return "", "", errors.New("namespace is required")