From 5b38ccb8d01ff8e2abb9519392e1109d2b1f9f38 Mon Sep 17 00:00:00 2001 From: Liam Beckman Date: Thu, 21 Nov 2024 19:17:01 -0800 Subject: [PATCH] Add initial support for S3 backed PVCs --- compute/kubernetes/backend.go | 108 +++++++++++++++++- config/internal/bundle.go | 16 +-- config/kubernetes-executor-template.yaml | 14 +-- config/kubernetes-template.yaml | 9 +- deployments/kubernetes/helm/Chart.yaml | 2 +- .../kubernetes/helm/templates/NOTES.txt | 4 +- .../helm/templates/clusterrole.yaml | 15 +++ .../helm/templates/clusterrolebinding.yaml | 12 ++ .../kubernetes/helm/templates/role.yaml | 2 +- examples/internal/bundle.go | 8 +- 10 files changed, 153 insertions(+), 37 deletions(-) create mode 100644 deployments/kubernetes/helm/templates/clusterrole.yaml create mode 100644 deployments/kubernetes/helm/templates/clusterrolebinding.yaml diff --git a/compute/kubernetes/backend.go b/compute/kubernetes/backend.go index ba7ea459..bc14b7a3 100644 --- a/compute/kubernetes/backend.go +++ b/compute/kubernetes/backend.go @@ -21,6 +21,7 @@ import ( batchv1 "k8s.io/client-go/kubernetes/typed/batch/v1" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" + "k8s.io/utils/ptr" "github.com/ohsu-comp-bio/funnel/config" "github.com/ohsu-comp-bio/funnel/events" @@ -172,19 +173,67 @@ func (b *Backend) createJob(task *tes.Task) (*v1.Job, error) { } func (b *Backend) createPVC(ctx context.Context, taskID string, resources *tes.Resources) error { - clientset, err := kubernetes.NewForConfig(b.config) // You'll need to store the config during NewBackend + clientset, err := kubernetes.NewForConfig(b.config) if err != nil { return fmt.Errorf("getting kubernetes client: %v", err) } - storageSize := resource.NewQuantity(1024*1024*1024, resource.BinarySI) // 1Gi default + // Define storage size (ignored by S3 CSI driver but required by the API) + storageSize := resource.NewQuantity(1024*1024*1024, resource.BinarySI) // Default 1Gi if resources != nil && resources.DiskGb > 0 { storageSize = resource.NewQuantity(int64(resources.DiskGb*1024*1024*1024), resource.BinarySI) } + pvName := fmt.Sprintf("funnel-pv-%s", taskID) + pvcName := fmt.Sprintf("funnel-pvc-%s", taskID) + bucketName := "funnel-testing" + + // Step 1: Create the PersistentVolume + pv := &corev1.PersistentVolume{ + ObjectMeta: metav1.ObjectMeta{ + Name: pvName, + Labels: map[string]string{ + "app": "funnel", + "taskId": taskID, + }, + }, + Spec: corev1.PersistentVolumeSpec{ + Capacity: corev1.ResourceList{ + corev1.ResourceStorage: *storageSize, + }, + AccessModes: []corev1.PersistentVolumeAccessMode{ + corev1.ReadWriteMany, // S3 CSI supports RWX + }, + PersistentVolumeReclaimPolicy: corev1.PersistentVolumeReclaimRetain, + StorageClassName: "", + ClaimRef: &corev1.ObjectReference{ + Namespace: b.namespace, + Name: pvcName, + }, + MountOptions: []string{ + "allow-delete", + "region=us-west-2", + }, + PersistentVolumeSource: corev1.PersistentVolumeSource{ + CSI: &corev1.CSIPersistentVolumeSource{ + Driver: "s3.csi.aws.com", + VolumeHandle: fmt.Sprintf("s3-csi-%s", taskID), + VolumeAttributes: map[string]string{ + "bucketName": bucketName, + }, + }, + }, + }, + } + + if _, err := clientset.CoreV1().PersistentVolumes().Create(ctx, pv, metav1.CreateOptions{}); err != nil { + return fmt.Errorf("creating PersistentVolume: %v", err) + } + + // Step 2: Create the PersistentVolumeClaim pvc := &corev1.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("funnel-pvc-%s", taskID), + Name: pvcName, Labels: map[string]string{ "app": "funnel", "taskId": taskID, @@ -192,19 +241,61 @@ func (b *Backend) createPVC(ctx context.Context, taskID string, resources *tes.R }, Spec: corev1.PersistentVolumeClaimSpec{ AccessModes: []corev1.PersistentVolumeAccessMode{ - corev1.ReadWriteOnce, + corev1.ReadWriteMany, }, Resources: corev1.VolumeResourceRequirements{ Requests: corev1.ResourceList{ corev1.ResourceStorage: *storageSize, }, }, + StorageClassName: func() *string { s := ""; return &s }(), + VolumeName: pvName, }, } - _, err = clientset.CoreV1().PersistentVolumeClaims(b.namespace).Create(ctx, pvc, metav1.CreateOptions{}) + if _, err := clientset.CoreV1().PersistentVolumeClaims(b.namespace).Create(ctx, pvc, metav1.CreateOptions{}); err != nil { + return fmt.Errorf("creating PersistentVolumeClaim: %v", err) + } + + return nil +} + +func (b *Backend) addOwnerReference(ctx context.Context, taskID string, job *v1.Job) error { + // Fetch the Job that will own the PVC and PV + jobName := fmt.Sprintf("funnel-job-%s", taskID) + _, err := b.client.Get(ctx, jobName, metav1.GetOptions{}) if err != nil { - return fmt.Errorf("creating shared PVC: %v", err) + return fmt.Errorf("fetching Job for owner reference: %v", err) + } + + // Fetch the PVC + pvcName := fmt.Sprintf("funnel-pvc-%s", taskID) + clientset, err := kubernetes.NewForConfig(b.config) + if err != nil { + return fmt.Errorf("getting kubernetes client: %v", err) + } + pvc, err := clientset.CoreV1().PersistentVolumeClaims(b.namespace).Get(ctx, pvcName, metav1.GetOptions{}) + if err != nil { + return fmt.Errorf("fetching PVC: %v", err) + } + + // Add OwnerReference for the Job + ownerRef := metav1.OwnerReference{ + APIVersion: "batch/v1", + Kind: "Job", + Name: job.Name, + UID: job.UID, + BlockOwnerDeletion: ptr.To(true), + Controller: ptr.To(true), + } + + // Append the OwnerReference to the PVC + pvc.OwnerReferences = append(pvc.OwnerReferences, ownerRef) + + // Update the PVC + _, err = clientset.CoreV1().PersistentVolumeClaims(b.namespace).Update(ctx, pvc, metav1.UpdateOptions{}) + if err != nil { + return fmt.Errorf("updating PVC: %v", err) } return nil @@ -257,6 +348,11 @@ func (b *Backend) Submit(ctx context.Context, task *tes.Task) error { return fmt.Errorf("creating job in backend: %v", err) } + err = b.addOwnerReference(submitCtx, task.Id, job) + if err != nil { + return fmt.Errorf("updating PVC with OwnerReference: %v", err) + } + return nil } diff --git a/config/internal/bundle.go b/config/internal/bundle.go index c4f9a531..59e082e6 100644 --- a/config/internal/bundle.go +++ b/config/internal/bundle.go @@ -3,10 +3,10 @@ // config/gridengine-template.txt (346B) // config/pbs-template.txt (361B) // config/slurm-template.txt (415B) -// config/kubernetes-executor-template.yaml (1.764kB) +// config/kubernetes-executor-template.yaml (1.232kB) // config/default-config.yaml (11.655kB) // config/htcondor-template.txt (505B) -// config/kubernetes-template.yaml (1.34kB) +// config/kubernetes-template.yaml (1.483kB) package config @@ -134,7 +134,7 @@ func configSlurmTemplateTxt() (*asset, error) { return a, nil } -var _configKubernetesExecutorTemplateYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x95\xc1\x8e\xdb\x36\x10\x86\xef\x7e\x8a\x81\xbc\x45\x2f\x91\x57\x7b\xe9\x41\x40\x0f\x0b\x6f\xb0\xd9\xa0\x71\x16\xc9\x36\x3d\x14\x3d\x50\xd4\xc8\x66\x2d\x92\xea\xcc\xd0\x59\x43\xf5\xbb\x17\x94\x64\x45\xda\x38\x29\xa2\x13\xc5\x19\x7e\xf3\xcf\xaf\xa1\xbd\x84\x27\xc5\x7b\x78\xfd\x8c\x3a\x88\xa7\x85\x6a\xcc\x27\x24\x36\xde\xe5\x50\x28\xd1\xbb\xeb\xc3\xcd\x62\x6f\x5c\x99\xc3\x5b\x5f\x2c\x2c\x8a\x2a\x95\xa8\x7c\x01\xe0\x94\xc5\x1c\xda\x76\x15\x09\x0f\xe5\xe9\x94\xb6\xed\xea\xad\x2f\xe2\x72\x08\x73\xa3\x74\x9f\xb3\x39\xbf\x75\xb1\x5a\x15\x58\x73\x84\x00\xfc\xed\x8b\xf4\xbb\x28\x6e\x50\xc7\xd4\x42\xe9\xbd\xaf\xaa\xdf\x8c\x35\x92\x43\xb6\x00\xd0\xde\x36\x35\x8a\xf1\x8e\x73\xb8\x59\x00\x08\xda\xa6\x56\x82\x3d\xf9\x7c\x30\x3e\x84\x2c\x8a\xe4\xd1\xd7\x46\x1f\x73\xd8\xe0\x01\x69\x08\x31\xd2\xc1\x68\xbc\xd5\xda\x07\x27\x9b\x4e\x4a\x15\x9c\xc3\x3a\x65\x35\xe4\x2c\xe1\x23\x4a\x68\x80\x8f\xb6\x36\x6e\xcf\x50\x91\xb7\xf0\xd9\xd3\x1e\x4a\x43\x20\x1e\x44\xd1\x16\x05\x1a\x25\x3b\x1e\x0e\x19\x67\x64\xed\x9d\x28\xe3\x90\xf8\xac\x24\x1d\x8c\xe3\x08\x4c\x4b\x43\xe7\x74\x00\x63\xd5\x16\x73\x28\x02\x1f\x0b\xff\x3c\x6e\x6b\x6f\xad\x8a\x5f\xe0\xcf\xe4\xba\x30\xee\x9a\x77\xc9\x2b\x48\x52\x9d\xfc\x35\xa6\x28\xda\x8e\x05\xfa\x22\xff\x4e\xde\xa2\xfe\x35\xa1\x12\x04\x15\xf5\xa2\x16\x4f\xc7\xa8\xba\x30\xae\x04\x1b\xfb\x06\xd9\x61\xd7\x10\xd2\xcf\x0c\x95\xa9\x91\x2f\x13\x1a\x45\xe8\x64\xc4\x18\x64\xa8\x3c\x81\x72\xc7\xae\xf9\xce\x75\x53\x19\x2c\xc1\xb8\x0e\x2a\x8a\xf7\x97\x51\x31\x3a\x38\xfa\xc5\x50\xa4\x0b\x96\xce\xce\xa3\xde\x79\x48\x66\xee\xe6\x3d\xd2\xb8\xed\x4c\x98\x72\xe5\xf8\xc9\x92\x91\xc1\xa8\x03\x19\x39\xc6\xd3\xf8\x2c\x53\xdf\x28\xb8\x5b\xfe\x9d\x23\x30\x8b\x42\x3f\x04\x07\x8a\x81\xbc\x97\xa8\x08\x1d\x07\xc2\x89\x85\xba\xab\xea\x5d\xa7\xfc\x6c\x98\xfe\xe6\x37\x1f\xc6\xaa\x6f\x33\x9d\xcc\xfb\xcb\x11\x68\xdb\xd5\x43\x5c\xbd\x8c\x3c\x86\xba\x3e\xcf\xf0\x6d\xfd\x59\x1d\xf9\x87\xa7\x24\xb2\xd7\x7d\xee\x84\x1e\x25\x19\xb7\xbd\x33\xd4\x25\xfc\xe1\x69\x5f\x1a\x9a\x24\x10\xb2\x0f\xa4\x71\x36\x66\x84\xff\x04\x64\x99\xed\x01\xe8\x26\x44\x88\xa9\xc0\x21\xac\xd6\x4d\x60\xc8\x20\x3d\x9d\x62\xe1\x26\x70\x5c\x00\xd6\x8c\x10\x57\xc9\x4d\x96\xd9\x24\xae\x70\x26\x28\x3e\x16\xad\xa7\xe3\x84\xf5\x41\xd9\xfb\x02\xb2\xd5\x80\x6b\xc8\x38\xa9\x20\xf9\x69\x95\x55\xf7\xc9\x10\xee\x50\x35\x63\x0f\xff\xe5\xdd\x37\xd8\xd8\xec\xd0\x22\xa9\x3a\x65\xf1\x34\x98\x3e\x94\xb9\x33\xbc\xff\x5e\x9d\x3e\x3e\x2f\x94\x65\x97\x2a\x8d\x8b\x83\xaf\x83\xc5\x77\xf1\xa6\x4d\xdc\x5a\x2e\x97\x70\xf7\x1e\x36\xef\x9f\x60\xfd\xe6\x76\x73\xff\x1a\x9e\xde\x3c\x7c\x1c\xc3\x6d\x4b\xca\x6d\x11\xae\x4c\xf9\xfc\x0a\xae\x8c\xa0\x85\xfc\x57\x58\x7d\xea\x60\x3c\xa9\xf3\x62\xc0\x86\x96\xd2\xb6\xbd\xfa\x7a\xc4\xa0\xbf\xf0\x8f\x4a\x76\xb1\xe7\x0e\xbb\x1a\x6f\x52\xdc\x9e\x25\x73\x28\xc6\xd4\x11\xf6\x7f\xc7\xce\x3e\x2c\xa6\xdd\x73\x0e\x97\xef\xc3\x17\xb9\x5f\xab\x6d\xe2\xbf\x11\x0b\x3a\xe9\xbb\x5e\xd7\xca\xd8\xe9\xbc\xe9\xb8\x31\xfb\xd5\x6e\x0e\x7a\x86\xfa\x2f\x00\x00\xff\xff\x63\xd1\xdc\x25\xe4\x06\x00\x00") +var _configKubernetesExecutorTemplateYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x84\x54\xcd\x4f\xdb\x4e\x10\xbd\xfb\xaf\x18\x39\xfc\x6e\xd8\x98\xcb\xef\x60\xa9\x07\x14\x10\x1f\x2a\x01\xb5\x88\x1e\xaa\x1e\xc6\x9b\x49\xb2\xcd\x7e\x75\x67\x1d\x40\x56\xfe\xf7\x6a\xfd\x55\x07\x28\xf5\x69\xb2\xef\xf9\xbd\x37\x93\x59\xcf\xe0\x01\x79\x0b\x17\xcf\x24\xea\x60\x7d\x82\x4e\x3e\x92\x67\x69\x4d\x09\x15\x06\xb1\x39\xd9\x9d\x26\x5b\x69\x96\x25\xdc\xd8\x2a\xd1\x14\x70\x89\x01\xcb\x04\xc0\xa0\xa6\x12\x9a\x26\x8f\x0a\xd7\xcb\xfd\x3e\x6b\x9a\xfc\xc6\x56\xb1\xec\x61\x76\x28\x3a\xce\x62\xf8\xd5\x62\x0a\x2b\x52\x1c\x45\x00\xd0\xb9\x12\x56\xb5\x31\xa4\x32\x1a\x62\x44\xe0\xa7\xad\xb2\x0f\x3d\xd8\x91\x88\x1a\x15\x8a\xad\x5d\xad\x3e\x4b\x2d\x43\x09\x45\x02\x20\xac\x76\x8a\x82\xb4\x86\x4b\x38\x4d\x00\x02\x69\xa7\x30\x50\x67\x39\xbc\x18\x1f\x4f\x1c\xd0\x87\x7b\xab\xa4\x78\x29\x61\x41\x3b\xf2\x3d\xc4\xe4\x77\x52\xd0\x99\x10\xb6\x36\x61\xd1\x46\xe9\x83\x32\xf6\x1c\x61\x4d\x40\x69\xc8\xf3\x20\x98\xf5\x83\xe9\x99\x4f\xd6\x6f\xc9\x67\x93\x16\x7a\x1e\x80\xd4\xb8\xee\xba\xbb\x8e\xd5\x6b\xe4\xbe\x56\x6a\x88\x75\xa6\x9e\xf0\x85\x47\x5c\x58\xad\x31\xfe\x27\xdf\xd3\x93\x4a\x9a\x13\xde\xa4\xc7\x90\x66\x22\xfd\x31\x52\xd0\xaf\xb9\xd5\x9e\x77\xdc\x89\x7a\x8c\x24\xcd\xfa\x5c\xfa\x96\xf0\xcd\xfa\xed\x52\xfa\x09\xc1\x13\xdb\xda\x0b\x1a\x7b\xea\x0e\x7f\xd5\xc4\xe1\xe0\x0c\x40\xb8\x3a\x8a\xc8\x15\x18\x82\x7c\xee\x6a\x86\x02\xb2\xfd\x3e\x1a\xbb\x9a\x63\x01\xa4\x98\x20\x56\xe9\x69\x51\xe8\x34\x56\x74\x10\x28\x3e\x9a\xb4\xf5\x2f\x13\xad\x2f\xa8\x2f\x2b\x28\xf2\x5e\xce\x79\x69\xc2\x0a\xd2\xff\xf2\x62\x75\x99\xf6\x70\x2b\xa5\x98\x3a\xf1\xff\x6f\xff\xa2\x4d\x6e\x43\x9a\x3c\xaa\x8c\x83\xf5\xfd\xd0\x7b\x9b\x73\xc9\xdb\x8f\x7c\x3a\xfc\xd0\xa8\x28\xde\x73\x1a\x8b\x9d\x55\xb5\xa6\xdb\xb8\x34\x93\x69\xcd\x66\x33\x38\xbf\x83\xc5\xdd\x03\xcc\xaf\xce\x16\x97\x17\xf0\x70\x75\xfd\x75\x84\x9b\xc6\xa3\x59\x13\x1c\xc9\xe5\xf3\x31\x1c\xc9\x40\x1a\xca\x4f\x90\x3f\xb6\x62\x3c\xf1\x79\xb5\x60\x7d\x4b\x59\xd3\x1c\xbd\x5d\x31\x00\x1d\x63\xdc\x63\xd8\xc4\x9e\x5b\xd9\x7c\x3e\xec\x6c\x3c\x3e\x20\x73\x5d\x8d\xd4\x51\xec\x5f\xaf\x0d\x73\x48\xa6\xdd\x73\x09\xef\xdf\x87\x3f\x71\xdf\xa6\x75\xf1\xcb\xc3\x81\x4c\xe8\xba\x9e\x2b\x94\x7a\xba\x6f\x22\x1e\x1c\x5c\x44\xb7\x13\x07\x52\xbf\x03\x00\x00\xff\xff\x00\x13\xe6\xe4\xd0\x04\x00\x00") func configKubernetesExecutorTemplateYamlBytes() ([]byte, error) { return bindataRead( @@ -149,8 +149,8 @@ func configKubernetesExecutorTemplateYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "config/kubernetes-executor-template.yaml", size: 1764, mode: os.FileMode(0644), modTime: time.Unix(1732069321, 0)} - a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x25, 0x2, 0xdd, 0x4b, 0xb1, 0xe0, 0x8, 0x1f, 0xee, 0xb8, 0xec, 0x74, 0x27, 0xdb, 0xee, 0x63, 0x56, 0x82, 0x78, 0xa4, 0x2a, 0x2b, 0x8c, 0x98, 0x5c, 0xdd, 0x1c, 0xf6, 0x19, 0xd6, 0x9a, 0xb2}} + info := bindataFileInfo{name: "config/kubernetes-executor-template.yaml", size: 1232, mode: os.FileMode(0644), modTime: time.Unix(1732240371, 0)} + a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x28, 0xc4, 0x2b, 0x17, 0x62, 0x5d, 0x51, 0xe4, 0x35, 0x84, 0xde, 0x2a, 0x3, 0x35, 0x7d, 0x71, 0x79, 0x5a, 0xe0, 0xbd, 0x90, 0xcd, 0x65, 0x9d, 0xe8, 0x11, 0x72, 0x90, 0x35, 0xe7, 0x36, 0x7a}} return a, nil } @@ -194,7 +194,7 @@ func configHtcondorTemplateTxt() (*asset, error) { return a, nil } -var _configKubernetesTemplateYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x54\xc9\x6e\xdb\x30\x10\xbd\xeb\x2b\x06\x2a\x7a\xd4\x92\x4b\x0f\xbc\x05\x09\x1a\xb4\x68\x82\xa0\x28\xd2\xf3\x88\x1e\xd9\x84\xb9\x85\x8b\x02\xc3\xd0\xbf\x17\x14\xe5\x56\x72\xec\x00\xe5\x89\x9c\xe5\x2d\xe4\x48\x9f\xe0\x6b\xd4\x9a\x24\xfc\x36\x6e\x4f\xae\x40\x2b\x5e\xc8\x79\x61\x34\x83\x0e\x03\xdf\x35\xc3\x4d\xb1\x17\x7a\xc3\xe0\xbb\xe9\x0a\x45\x01\x37\x18\x90\x15\x00\x1a\x15\x31\x38\x1e\xeb\x5f\xe8\xf7\xdf\x36\xe3\x38\xc7\xbc\x45\x9e\x13\x4f\xa7\xd3\x38\x16\xde\x12\x67\x50\x00\x74\xc8\xf7\xa6\xef\x7f\x08\x25\x02\x83\xb6\x00\xe0\x46\x59\x49\x41\x18\xed\x19\xdc\x14\x00\x81\x94\x95\x18\x28\xb1\x00\x4c\x9d\xd3\x0e\xc0\x93\x1b\x04\xa7\x5b\xce\x4d\xd4\xe1\x69\x52\xd0\x4f\x06\x2a\x8f\x73\x8d\x23\x1f\xd0\x85\x67\x23\x05\x3f\x30\x78\xa2\x81\xdc\x9c\xe2\x46\x07\x14\x9a\x9c\x9f\xa4\xe4\x55\xcd\x4e\x66\x9c\xb7\xe9\x22\xaa\xb5\xaf\xd3\x12\x0a\xb7\xc4\xe0\x35\xe2\xa1\x16\xa6\x31\x3b\x1f\xab\x24\xbf\xea\x84\x69\x32\x00\xdb\xd0\x40\xd2\x58\x45\x3a\x9c\x77\x3e\x47\x29\x4f\xba\x6e\xe5\x1b\x1e\xfc\xa2\x02\xdd\xd6\xb3\xc5\x39\x29\x2b\xb3\x9a\xf2\x3c\xec\xa2\x7e\x17\xab\x2a\x6e\x74\x2f\xb6\xef\x12\x0d\x05\xde\xe4\x5c\xb3\x32\x59\x1f\x50\xc9\x0b\x38\x21\x19\xbf\x3f\x4f\x5c\xbe\x11\x47\xde\x44\xc7\xe9\x4c\xba\xa3\xd7\x48\x3e\x9c\x45\x01\xb8\x8d\x69\x34\x44\x0f\x9a\xa0\xbe\xb3\xd1\x43\x0b\xd5\x38\x1e\x8f\xd3\x21\x6d\x80\xa4\x27\x48\xbb\xf2\xa6\x6d\x55\x99\x76\xa4\xd7\xac\x69\x29\x52\xc6\x1d\x16\x68\x3f\x51\x3d\x74\xd0\xd6\x33\xa0\x75\x42\x87\x1e\xca\xcf\x75\xdb\x3f\x94\x73\x7a\x02\x93\x9e\x32\xfc\x97\xc7\xab\xe8\x64\x77\xa4\xc8\xa1\xac\x7c\x30\x6e\x7a\xf5\xbf\x44\xf7\xc2\xef\x3f\x62\xca\xf9\x35\x55\xdb\x5e\xe6\x1a\x8c\x8c\x8a\x1e\xd3\x38\xaf\x2e\xeb\x34\x95\xf9\xdd\xaa\x5c\xb6\xd2\xa8\x52\xcf\x33\x86\x1d\x83\xc5\x0b\x2f\x4a\x2e\xa0\x9d\xbe\x95\x6c\xe9\xca\x90\xaf\xa1\x8d\x0d\xf3\xd4\x2c\x87\xa7\xda\x08\xd7\x5c\x6b\xf7\xb1\xcb\xcd\xcb\x82\x62\xe9\xf7\xdf\xf7\xf7\xb1\xcf\x1c\x7d\x44\xbb\xbc\x9a\x95\x95\xd9\x75\xf1\xdf\x3e\x6d\xfa\xcd\xf9\x40\x3a\xbc\x4c\x9c\x77\x12\x85\x5a\xd2\xf0\x14\x58\xfd\x62\xec\xc0\x97\x50\x7f\x02\x00\x00\xff\xff\x58\xbe\x1f\x47\x3c\x05\x00\x00") +var _configKubernetesTemplateYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x54\xc9\x6e\xdb\x30\x10\xbd\xeb\x2b\x06\x2e\x7a\xa4\xa5\x5c\x7a\xe0\x2d\x48\xd0\x20\x45\x13\x04\x45\x91\x9e\x47\xf4\x28\x26\xcc\x2d\x5c\x1c\x18\x86\xff\xbd\xa0\x28\xa7\x94\x63\x07\x28\x4f\xd4\x2c\xef\xbd\x59\xc4\x2f\xf0\x3d\x19\x43\x0a\xfe\x58\xbf\x21\xdf\xa0\x93\xcf\xe4\x83\xb4\x86\x43\x8f\x51\xac\xdb\xed\x55\xb3\x91\x66\xc5\xe1\x87\xed\x1b\x4d\x11\x57\x18\x91\x37\x00\x06\x35\x71\xd8\xef\x97\xbf\x31\x6c\xee\x57\x87\xc3\x64\x0b\x0e\x45\x71\x3c\x1e\xbf\x46\x9f\xc2\x9e\x54\xc8\x99\x00\xe8\x1c\x87\x61\x64\x66\x6f\x85\x39\x9b\x23\x86\x0d\x93\xab\x39\x6a\x70\x24\x38\x34\x00\x3d\x8a\x8d\x1d\x86\x9f\x52\xcb\xc8\xa1\x6b\x00\x84\xd5\x4e\x51\x94\xd6\x04\x0e\x57\x0d\x40\x24\xed\x14\x46\x2a\x2c\xb5\xda\x7c\x6a\x05\x9f\xa8\xb8\xa8\x24\x3b\x46\x35\x53\x58\x20\xbf\x95\x82\xae\x85\xb0\xc9\xc4\xc7\xb1\x1f\x13\x5c\xc0\x29\xc6\x53\x88\xe8\xe3\x93\x55\x52\xec\x38\x3c\xd2\xf6\x9d\x45\x58\x13\x51\x1a\xf2\x61\x2c\xaf\x1c\x36\xf5\x75\x26\x8b\x9d\xaa\x28\x47\x6a\x7c\x21\x0e\xaf\x09\x77\x4b\x69\x5b\xbb\x0e\x89\xe5\x96\xb0\x5e\xda\xb6\x00\xf0\x15\x6d\x49\x59\xa7\xc9\xc4\xd3\xcc\xa7\xa4\xd4\x51\xd7\xb5\x7a\xc3\x5d\xa8\x22\xd0\xbf\x54\x9d\x2a\xca\x16\x45\xcd\xe2\xd4\xec\x93\xf9\x60\x63\x4c\x58\x33\xc8\x97\x0f\x8e\x96\xa2\x68\x8b\xaf\x9d\x15\xb9\xdc\xa1\x56\x67\x70\xf2\x28\xee\x6f\x4f\x1d\xe7\x3b\xe2\x29\xd8\xe4\x05\x9d\x48\xf7\xf4\x9a\x28\xc4\x13\x2b\x80\x70\x29\x4f\x58\x0e\x60\x08\x96\x37\x2e\x05\xe8\x80\x1d\x0e\xfb\xfd\xf8\x91\x2f\x40\x2a\x10\xe4\xdb\xe2\xaa\xeb\xf4\x22\xdf\xc8\xcc\x59\x61\xdc\x35\x6d\xfd\xae\x42\xfb\x85\xfa\xae\x87\x6e\x39\x01\x3a\x2f\x4d\x1c\x60\xf1\x75\xd9\x0d\x77\x8b\xc9\x3d\x82\xa9\x40\x05\xfe\xdb\xc3\x45\x74\x72\x6b\xd2\xe4\x51\xb1\x10\xad\x1f\xa7\xfe\x4e\x74\x2b\xc3\xe6\x33\xa6\xe2\x9f\x53\x75\xdd\x79\xae\xad\x55\x49\xd3\x43\x5e\xe7\x59\xb3\x8e\x5b\x59\xe6\xc6\x4a\xd8\x4c\xa3\xce\x39\x4f\x18\xd7\x1c\xaa\x09\x57\x21\x67\xd0\x8e\xff\x4a\x29\xe9\xc2\x92\xcf\xa1\xad\x8b\xd3\xd6\xd4\xcb\xc3\x56\xd2\xb7\x97\xd2\x43\xea\x4b\x72\x1d\xd0\xd4\xf5\xfe\xfb\xff\x3e\xaf\xb3\x58\x1f\xd0\xd5\xad\x99\x95\x32\x55\xdd\xfc\x77\x9d\x2e\x3f\xba\x21\x92\x89\xcf\x23\xe7\x8d\x42\xa9\x6b\x1a\x91\x0d\xb3\x27\xc6\x6d\xc5\x0c\xea\x6f\x00\x00\x00\xff\xff\x08\x8f\xc3\x13\xcb\x05\x00\x00") func configKubernetesTemplateYamlBytes() ([]byte, error) { return bindataRead( @@ -209,8 +209,8 @@ func configKubernetesTemplateYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "config/kubernetes-template.yaml", size: 1340, mode: os.FileMode(0644), modTime: time.Unix(1732069183, 0)} - a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd, 0x9f, 0xc2, 0x40, 0x16, 0xb2, 0xe4, 0xc1, 0xca, 0x91, 0x63, 0x8c, 0xd5, 0x75, 0x4a, 0x48, 0x1f, 0x5b, 0x6a, 0xca, 0xcd, 0x8d, 0x20, 0x7d, 0x76, 0xa4, 0x7, 0x7f, 0xf3, 0xe5, 0x87, 0xe5}} + info := bindataFileInfo{name: "config/kubernetes-template.yaml", size: 1483, mode: os.FileMode(0644), modTime: time.Unix(1732239949, 0)} + a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x2c, 0x8c, 0x8e, 0x18, 0x35, 0xe0, 0x7c, 0x96, 0x55, 0x8e, 0x9a, 0x5a, 0x33, 0xde, 0x4f, 0x66, 0x80, 0xae, 0x95, 0xb, 0x6a, 0x60, 0xf3, 0xb4, 0x8d, 0xd9, 0xa9, 0xf4, 0x6b, 0x90, 0xbc, 0x91}} return a, nil } diff --git a/config/kubernetes-executor-template.yaml b/config/kubernetes-executor-template.yaml index 8e10d254..b87f8ef7 100644 --- a/config/kubernetes-executor-template.yaml +++ b/config/kubernetes-executor-template.yaml @@ -5,6 +5,7 @@ metadata: name: {{.TaskId}}-{{.JobId}} namespace: {{.Namespace}} labels: + app: funnel-executor job-name: {{.TaskId}}-{{.JobId}} spec: backoffLimit: 0 @@ -13,19 +14,6 @@ spec: spec: restartPolicy: Never serviceAccountName: funnel-sa - # Setup symlinks from work dir to target paths - initContainers: - - name: setup-dirs - image: busybox - command: ["/bin/sh", "-c"] - args: - - | - # Create a directory to bind mount the worker's files - # Create parent directories for any path specified in the task - # Create the symlink from worker dir to target path - echo "initContainer: Creating directories and symlinks" - securityContext: - runAsUser: 0 # Run as root to ensure directory creation works containers: - name: funnel-worker-{{.TaskId}} image: {{.Image}} diff --git a/config/kubernetes-template.yaml b/config/kubernetes-template.yaml index 81239b68..97f8af01 100644 --- a/config/kubernetes-template.yaml +++ b/config/kubernetes-template.yaml @@ -4,10 +4,17 @@ kind: Job metadata: name: {{.TaskId}} namespace: {{.Namespace}} + labels: + app: funnel-worker + task-id: {{.TaskId}} spec: backoffLimit: 0 completions: 1 template: + metadata: + labels: + app: funnel-worker + task-id: {{.TaskId}} spec: serviceAccountName: funnel-sa restartPolicy: Never @@ -42,4 +49,4 @@ spec: - name: funnel-storage-{{.TaskId}} persistentVolumeClaim: - claimName: funnel-pvc-{{.TaskId}} \ No newline at end of file + claimName: funnel-pvc-{{.TaskId}} diff --git a/deployments/kubernetes/helm/Chart.yaml b/deployments/kubernetes/helm/Chart.yaml index 42db24fb..c93d104c 100644 --- a/deployments/kubernetes/helm/Chart.yaml +++ b/deployments/kubernetes/helm/Chart.yaml @@ -17,7 +17,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.11 +version: 0.1.12 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/deployments/kubernetes/helm/templates/NOTES.txt b/deployments/kubernetes/helm/templates/NOTES.txt index 19666b11..34e155af 100644 --- a/deployments/kubernetes/helm/templates/NOTES.txt +++ b/deployments/kubernetes/helm/templates/NOTES.txt @@ -1,5 +1,3 @@ -1. To access the Funnel application, use the following instructions: - -To access the service locally, use: +To access the Funnel service locally, use: kubectl --namespace {{ .Release.Namespace }} port-forward svc/{{ include "funnel.fullname" . }} 8000:8000 echo "Visit http://127.0.0.1:8000" diff --git a/deployments/kubernetes/helm/templates/clusterrole.yaml b/deployments/kubernetes/helm/templates/clusterrole.yaml new file mode 100644 index 00000000..39968966 --- /dev/null +++ b/deployments/kubernetes/helm/templates/clusterrole.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: funnel-clusterrole +rules: +- apiGroups: [""] + resources: + - persistentvolumes + verbs: + - get + - list + - watch + - create + - update + - delete diff --git a/deployments/kubernetes/helm/templates/clusterrolebinding.yaml b/deployments/kubernetes/helm/templates/clusterrolebinding.yaml new file mode 100644 index 00000000..672d4d66 --- /dev/null +++ b/deployments/kubernetes/helm/templates/clusterrolebinding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: funnel-clusterrolebinding +subjects: +- kind: ServiceAccount + name: funnel-sa + namespace: funnel +roleRef: + kind: ClusterRole + name: funnel-clusterrole + apiGroup: rbac.authorization.k8s.io diff --git a/deployments/kubernetes/helm/templates/role.yaml b/deployments/kubernetes/helm/templates/role.yaml index 64628d22..32fa3b93 100644 --- a/deployments/kubernetes/helm/templates/role.yaml +++ b/deployments/kubernetes/helm/templates/role.yaml @@ -6,7 +6,7 @@ metadata: namespace: {{ .Release.Namespace }} rules: - apiGroups: [""] - resources: ["pods", "pods/log", "persistentvolumeclaims"] # Added PVCs + resources: ["pods", "pods/log", "persistentvolumeclaims"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] - apiGroups: ["batch", "extensions"] resources: ["jobs"] diff --git a/examples/internal/bundle.go b/examples/internal/bundle.go index b8c2533b..4699b377 100644 --- a/examples/internal/bundle.go +++ b/examples/internal/bundle.go @@ -10,7 +10,7 @@ // examples/s3-sleep.json (518B) // examples/md5sum.json (737B) // examples/nextflow.json (551B) -// examples/s3.json (524B) +// examples/s3.json (532B) // examples/malicious-tag.json (283B) // examples/full-hello.json (577B) @@ -280,7 +280,7 @@ func examplesNextflowJson() (*asset, error) { return a, nil } -var _examplesS3Json = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x64\x90\xcf\x4e\xf3\x30\x10\xc4\xef\x79\x8a\x95\x4f\xdf\x27\x35\xb1\x44\xc5\x25\xd7\xb4\xe2\x52\x71\xa0\x70\x01\xf5\xb0\x71\xb6\xa9\xc1\x7f\x22\xaf\x4d\x83\xaa\xbe\x3b\x8a\x0b\x2d\x85\x4b\x14\x69\xc6\x33\xbf\x9d\x43\x01\x20\x1c\x5a\x12\x35\x88\xf5\x1c\xd6\xd1\x07\xec\x09\x68\x44\x3b\x18\x12\xb3\x49\xef\x88\x55\xd0\x43\xd4\xde\x4d\xb6\x47\xe4\x37\xd0\x6e\x48\x91\x01\x5d\x07\x3e\xc5\xfc\xaf\xd0\x41\x4b\xd0\x18\x9f\xba\x73\xd0\xd3\xc3\x8a\xab\x53\x0c\x8d\xa4\x52\xf4\x81\x45\x0d\x2f\x05\x00\xc0\x21\x7f\x01\x84\xb6\xd8\x67\x84\xd4\x26\x17\x53\xf6\x67\x41\x79\x6b\xd1\x75\xd3\x0b\x61\xbb\x5b\x4e\x56\xcc\x40\xc8\x40\x86\x90\xa9\x7a\x65\xef\xc4\x26\x9b\x8f\x05\xc0\x26\xf7\x9c\xd0\xfe\x96\x7c\x9f\x99\xf5\x4b\xc5\xaf\xeb\x16\x7e\xef\x8c\xc7\x0e\x10\x86\xd4\x1a\xad\x60\xab\x0d\xc1\x36\x78\x0b\x3f\x06\xfa\xd7\x3c\x43\xb3\x5c\xad\xc6\xbb\xe5\xfd\x12\x16\x9a\x95\x7f\xa7\x00\x0d\x39\x4e\x0c\x0b\x8c\x58\xc3\x2e\xc6\x81\x6b\x29\x03\xf5\x9a\x63\xf8\xa8\xfc\x40\xae\xc3\x88\x15\xee\x59\x46\xec\x65\xab\xbd\x76\x5b\x1f\x2c\x46\xad\x58\xfe\xbf\x50\xa5\x60\x26\x1a\x9e\xd7\x52\x2a\x32\x66\xec\xc9\x51\xa9\x72\x7c\x79\x02\x2b\x13\x97\x7b\xe2\x58\xde\x64\xc7\x97\x78\xbd\xcd\x39\x6f\xc0\xb8\x9b\x02\xaf\xe5\xcb\x72\xc5\xb1\xf8\x0c\x00\x00\xff\xff\xc0\x06\x69\xef\x0c\x02\x00\x00") +var _examplesS3Json = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x64\x90\x4f\x8f\xd3\x30\x10\xc5\xef\xf9\x14\x23\x9f\x40\xda\xc4\x12\x2b\x2e\xb9\xa6\x15\x97\x8a\x03\x0b\x17\x50\x0f\x13\x67\x9a\x1a\xfc\x4f\x9e\x31\x0d\xaa\xfa\xdd\x51\x5c\x68\x61\x7b\xb1\x2c\xbd\x99\xf7\x7e\xf3\xce\x0d\x80\x0a\xe8\x49\xf5\xa0\x5e\x9e\xe1\x45\x62\xc6\x99\x80\x16\xf4\xc9\x91\x7a\x5a\xf5\x89\xd8\x64\x9b\xc4\xc6\xb0\x8e\x7d\x46\xfe\x01\x36\xa4\x22\x0c\x18\x26\x88\x45\xea\xdf\x60\x80\x91\x60\x70\xb1\x4c\x37\xa3\x2f\x9f\x76\xdc\x5d\x6d\x68\x21\x53\x24\x66\x56\x3d\x7c\x6b\x00\x00\xce\xf5\x05\x50\xd6\xe3\x5c\x11\xca\x58\x82\x94\x3a\x5f\x05\x13\xbd\xc7\x30\xad\x1b\xca\x4f\xef\xb9\x78\xf5\x04\x4a\x8b\x4f\x3a\x93\x23\x64\xea\xbe\x73\x0c\x6a\x5f\x17\x2e\x0d\xc0\xbe\x66\x5d\xf1\x1e\x83\xfe\x9e\x5a\xf5\x7b\xcc\xab\x0b\x37\xf1\x14\x5c\xc4\x09\x10\x52\x19\x9d\x35\x70\xb0\x8e\xe0\x90\xa3\x87\x7f\x4a\x7a\x33\x7c\x85\x61\xbb\xdb\x2d\x1f\xb6\x1f\xb7\xb0\xb1\x6c\xe2\x4f\xca\x30\x50\xe0\xc2\xb0\x41\xc1\x1e\x8e\x22\x89\x7b\xad\x33\xcd\x96\x25\xff\xea\x62\xa2\x30\xa1\x60\x87\x27\xd6\x82\xb3\x1e\x6d\xb4\xe1\x10\xb3\x47\xb1\x86\xf5\xdb\x3b\x55\xc9\x6e\xa5\xe1\xe7\x5e\x6b\x43\xce\x2d\x33\x05\x6a\x4d\xb5\x6f\xaf\x60\x6d\xe1\xf6\x44\x2c\xed\xbb\x3a\xf1\x47\xfc\xbf\x9b\x9b\x5f\x42\x39\xae\x86\x8f\xf5\xdd\xdb\x6b\x2e\xcd\xef\x00\x00\x00\xff\xff\x65\xd0\xc2\x9b\x14\x02\x00\x00") func examplesS3JsonBytes() ([]byte, error) { return bindataRead( @@ -295,8 +295,8 @@ func examplesS3Json() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "examples/s3.json", size: 524, mode: os.FileMode(0644), modTime: time.Unix(1732064231, 0)} - a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa5, 0x12, 0xab, 0xa6, 0x34, 0xd0, 0xb, 0xd6, 0x56, 0x79, 0x95, 0xa, 0x80, 0x42, 0x6e, 0x70, 0x53, 0xb8, 0xcb, 0x92, 0x4, 0xb6, 0x62, 0xe0, 0xb, 0x1c, 0xfb, 0xb1, 0xd5, 0x78, 0xa4, 0x37}} + info := bindataFileInfo{name: "examples/s3.json", size: 532, mode: os.FileMode(0644), modTime: time.Unix(1732133183, 0)} + a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xce, 0xcf, 0xc, 0x0, 0xf8, 0xd5, 0x2b, 0x3c, 0x3f, 0x6e, 0x32, 0xcb, 0x99, 0x40, 0x9, 0x3b, 0x20, 0xd4, 0xde, 0x90, 0xd6, 0x4b, 0x53, 0x91, 0xd3, 0x71, 0x9b, 0x4f, 0x31, 0x3b, 0x70, 0x94}} return a, nil }