diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index b853e0630..707d40fe8 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -11,7 +11,7 @@ jobs:
- name: Set up Go 1.x
uses: actions/setup-go@v5
with:
- go-version: 1.21
+ go-version: 1.22
- name: Check out code
uses: actions/checkout@v2
@@ -23,6 +23,7 @@ jobs:
key: ${{ runner.os }}-funnel-bin-${{ hashFiles('**/go.sum') }}-${{ github.ref }}
restore-keys: |
${{ runner.os }}-funnel-bin-${{ github.ref }}
+ ${{ runner.os }}-funnel-bin-
- name: Build Funnel (if cache doesn't exist)
run: |
diff --git a/.github/workflows/k8s.yaml b/.github/workflows/k8s.yaml
index 2ff197f23..2f325a9d6 100644
--- a/.github/workflows/k8s.yaml
+++ b/.github/workflows/k8s.yaml
@@ -35,8 +35,9 @@ jobs:
- name: Deploy Funnel
run: |
helm repo add ohsu https://ohsu-comp-bio.github.io/helm-charts
- # 'local-path' is a k3d specific storage class
- # Ref: https://k3d.io/v5.7.4/usage/k3s/#local-path-provisioner
+
+ # 'local-path' is a k3d specific storage class used to automatically create a PersistentVolume
+ # - Ref: https://k3d.io/v5.7.4/usage/k3s/#local-path-provisioner
helm upgrade --install funnel ohsu/funnel --set storage.className=local-path --set storage.provisioner=local-path
# Wait for the Deployment to be available
@@ -45,6 +46,9 @@ jobs:
# Port-forward the service
kubectl port-forward svc/funnel 8000:8000 &
+ - name: Setup tmate session
+ uses: mxschmitt/action-tmate@v3
+
- name: Submit Task
run: |
export PATH="$PATH:$(pwd)"
diff --git a/Dockerfile b/Dockerfile
index 71520ed07..32b259d93 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -13,7 +13,6 @@ RUN --mount=type=cache,target=/root/.cache/go-build make build
# final stage
FROM alpine
WORKDIR /opt/funnel
-VOLUME /opt/funnel/funnel-work-dir
EXPOSE 8000 9090
ENV PATH="/app:${PATH}"
COPY --from=build-env /go/src/github.com/ohsu-comp-bio/funnel/funnel /app/
diff --git a/README.md b/README.md
index b00de8d85..2902a9668 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,23 @@
-[](https://github.com/ohsu-comp-bio/funnel/actions/workflows/tests.yaml)
-[](https://github.com/ohsu-comp-bio/funnel/actions/workflows/compliance-test.yaml)
-[](https://gitter.im/ohsu-comp-bio/funnel)
-[](https://opensource.org/licenses/MIT)
-[](http://godoc.org/github.com/ohsu-comp-bio/funnel)
+[![Build Status][build-badge]][build]
+[![Compliance Tests Status][compliance-tests-badge]][compliance-tests]
+[![Gitter][gitter-badge]][gitter]
+[![License: MIT][license-badge]][license]
+[![Godoc][godoc-badge]][godoc]
+
+[build-badge]: https://img.shields.io/github/actions/workflow/status/ohsu-comp-bio/funnel/tests.yaml
+[build]: https://github.com/ohsu-comp-bio/funnel/actions/workflows/tests.yaml
+
+[compliance-tests]: https://github.com/ohsu-comp-bio/funnel/actions/workflows/compliance-test.yaml
+[compliance-tests-badge]: https://img.shields.io/github/actions/workflow/status/ohsu-comp-bio/funnel/compliance-test.yaml?label=Compliance%20Tests
+
+[gitter-badge]: https://badges.gitter.im/ohsu-comp-bio/funnel.svg
+[gitter]: https://gitter.im/ohsu-comp-bio/funnel
+
+[license-badge]: https://img.shields.io/badge/License-MIT-yellow.svg
+[license]: https://opensource.org/licenses/MIT
+
+[godoc-badge]: https://img.shields.io/badge/godoc-ref-blue.svg
+[godoc]: http://godoc.org/github.com/ohsu-comp-bio/funnel
diff --git a/compute/kubernetes/backend.go b/compute/kubernetes/backend.go
index ba7ea4590..334f2abbb 100644
--- a/compute/kubernetes/backend.go
+++ b/compute/kubernetes/backend.go
@@ -14,7 +14,6 @@ import (
v1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
k8errors "k8s.io/apimachinery/pkg/api/errors"
- "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
@@ -68,13 +67,17 @@ func NewBackend(ctx context.Context, conf config.Kubernetes, reader tes.ReadOnly
}
b := &Backend{
- client: clientset.BatchV1().Jobs(conf.Namespace),
- namespace: conf.Namespace,
- template: conf.Template,
- event: writer,
- database: reader,
- log: log,
- config: kubeconfig,
+ bucket: conf.Bucket,
+ region: conf.Region,
+ client: clientset.BatchV1().Jobs(conf.Namespace),
+ namespace: conf.Namespace,
+ template: conf.Template,
+ pvTemplate: conf.PVTemplate,
+ pvcTemplate: conf.PVCTemplate,
+ event: writer,
+ database: reader,
+ log: log,
+ config: kubeconfig,
}
if !conf.DisableReconciler {
@@ -87,9 +90,13 @@ func NewBackend(ctx context.Context, conf config.Kubernetes, reader tes.ReadOnly
// Backend represents the local backend.
type Backend struct {
+ bucket string
+ region string
client batchv1.JobInterface
namespace string
template string
+ pvTemplate string
+ pvcTemplate string
event events.Writer
database tes.ReadOnlyServer
log *logger.Logger
@@ -133,7 +140,7 @@ func (b *Backend) Close() {
//TODO: close database?
}
-// Create the Funnel Worker job
+// Create the Funnel Worker job from kubernetes-template.yaml
// Executor job is created in worker/kubernetes.go#Run
func (b *Backend) createJob(task *tes.Task) (*v1.Job, error) {
submitTpl, err := template.New(task.Id).Parse(b.template)
@@ -155,7 +162,7 @@ func (b *Backend) createJob(task *tes.Task) (*v1.Job, error) {
"DiskGb": res.GetDiskGb(),
})
if err != nil {
- return nil, fmt.Errorf("executing template: %v", err)
+ return nil, fmt.Errorf("executing Worker template: %v", err)
}
decode := scheme.Codecs.UniversalDeserializer().Decode
@@ -171,43 +178,74 @@ func (b *Backend) createJob(task *tes.Task) (*v1.Job, error) {
return job, nil
}
-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
+// Create the Worker/Executor PVC from config/kubernetes-pvc.yaml
+// TODO: Move this config file to Helm Charts so users can see/customize it
+func (b *Backend) createPVC(task *tes.Task) (*corev1.PersistentVolumeClaim, error) {
+ // Load templates
+ pvcTpl, err := template.New(task.Id).Parse(b.pvcTemplate)
if err != nil {
- return fmt.Errorf("getting kubernetes client: %v", err)
+ return nil, fmt.Errorf("parsing template: %v", err)
+ }
+
+ // Template parameters
+ var buf bytes.Buffer
+ err = pvcTpl.Execute(&buf, map[string]interface{}{
+ "TaskId": task.Id,
+ "Namespace": b.namespace,
+ "Bucket": b.bucket,
+ "Region": b.region,
+ })
+ if err != nil {
+ return nil, fmt.Errorf("executing PVC template: %v", err)
}
- storageSize := resource.NewQuantity(1024*1024*1024, resource.BinarySI) // 1Gi default
- if resources != nil && resources.DiskGb > 0 {
- storageSize = resource.NewQuantity(int64(resources.DiskGb*1024*1024*1024), resource.BinarySI)
- }
-
- pvc := &corev1.PersistentVolumeClaim{
- ObjectMeta: metav1.ObjectMeta{
- Name: fmt.Sprintf("funnel-pvc-%s", taskID),
- Labels: map[string]string{
- "app": "funnel",
- "taskId": taskID,
- },
- },
- Spec: corev1.PersistentVolumeClaimSpec{
- AccessModes: []corev1.PersistentVolumeAccessMode{
- corev1.ReadWriteOnce,
- },
- Resources: corev1.VolumeResourceRequirements{
- Requests: corev1.ResourceList{
- corev1.ResourceStorage: *storageSize,
- },
- },
- },
- }
-
- _, err = clientset.CoreV1().PersistentVolumeClaims(b.namespace).Create(ctx, pvc, metav1.CreateOptions{})
+ decode := scheme.Codecs.UniversalDeserializer().Decode
+ obj, _, err := decode(buf.Bytes(), nil, nil)
if err != nil {
- return fmt.Errorf("creating shared PVC: %v", err)
+ return nil, fmt.Errorf("decoding PVC spec: %v", err)
}
- return nil
+ fmt.Println("PVC spec: ", string(buf.Bytes()))
+ pvc, ok := obj.(*corev1.PersistentVolumeClaim)
+ if !ok {
+ return nil, fmt.Errorf("failed to decode PVC spec")
+ }
+ return pvc, nil
+}
+
+// Create the Worker/Executor PV from config/kubernetes-pv.yaml
+// TODO: Move this config file to Helm Charts so users can see/customize it
+func (b *Backend) createPV(task *tes.Task) (*corev1.PersistentVolume, error) {
+ // Load templates
+ pvTpl, err := template.New(task.Id).Parse(b.pvTemplate)
+ if err != nil {
+ return nil, fmt.Errorf("parsing template: %v", err)
+ }
+
+ // Template parameters
+ var buf bytes.Buffer
+ err = pvTpl.Execute(&buf, map[string]interface{}{
+ "TaskId": task.Id,
+ "Namespace": b.namespace,
+ "Bucket": b.bucket,
+ "Region": b.region,
+ })
+ if err != nil {
+ return nil, fmt.Errorf("executing PV template: %v", err)
+ }
+
+ decode := scheme.Codecs.UniversalDeserializer().Decode
+ obj, _, err := decode(buf.Bytes(), nil, nil)
+ if err != nil {
+ return nil, fmt.Errorf("decoding PV spec: %v", err)
+ }
+
+ fmt.Println("PV spec: ", string(buf.Bytes()))
+ pv, ok := obj.(*corev1.PersistentVolume)
+ if !ok {
+ return nil, fmt.Errorf("failed to decode PV spec")
+ }
+ return pv, nil
}
// Add this helper function for PVC cleanup
@@ -235,13 +273,35 @@ func (b *Backend) Submit(ctx context.Context, task *tes.Task) error {
// Create a new background context instead of inheriting from the potentially canceled one
submitCtx := context.Background()
- // TODO: Update this so that a PVC is only created if the task has inputs or outputs
+ // TODO: Update this so that a PVC/PV is only created if the task has inputs or outputs
// If the task has either inputs or outputs, then create a PVC
// shared between the Funnel Worker and the Executor
// e.g. `if len(task.Inputs) > 0 || len(task.Outputs) > 0 {}`
- err := b.createPVC(submitCtx, task.Id, task.GetResources())
+ pvc, err := b.createPVC(task)
+ if err != nil {
+ return fmt.Errorf("creating shared storage PVC: %v", err)
+ }
+
+ pv, err := b.createPV(task)
+ if err != nil {
+ return fmt.Errorf("creating shared storage PV: %v", err)
+ }
+
+ clientset, err := kubernetes.NewForConfig(b.config)
+ if err != nil {
+ return fmt.Errorf("getting kubernetes client: %v", err)
+ }
+
+ // Create PVC
+ pvc, err = clientset.CoreV1().PersistentVolumeClaims(b.namespace).Create(context.Background(), pvc, metav1.CreateOptions{})
+ if err != nil {
+ return fmt.Errorf("creating PVC: %v", err)
+ }
+
+ // Create PV
+ pv, err = clientset.CoreV1().PersistentVolumes().Create(context.Background(), pv, metav1.CreateOptions{})
if err != nil {
- return fmt.Errorf("creating shared storage: %v", err)
+ return fmt.Errorf("creating PV: %v", err)
}
// Create the worker job
diff --git a/config/config.go b/config/config.go
index 978aba8da..32ed83707 100644
--- a/config/config.go
+++ b/config/config.go
@@ -409,6 +409,10 @@ func (h FTPStorage) Valid() bool {
// Kubernetes describes the configuration for the Kubernetes compute backend.
type Kubernetes struct {
+ // The bucket to use for the task's Working Directory
+ Bucket string
+ // The region to use for the task's Bucket
+ Region string
// The executor used to execute tasks. Available executors: docker, kubernetes
Executor string
// Turn off task state reconciler. When enabled, Funnel communicates with Kuberenetes
@@ -428,6 +432,10 @@ type Kubernetes struct {
ExecutorTemplate string
// ExecutorTemplateFile is the path to the executor template.
ExecutorTemplateFile string
+ // Worker/Executor PV job template.
+ PVTemplate string
+ // Worker/Executor PVC job template.
+ PVCTemplate string
// Path to the Kubernetes configuration file, otherwise assumes the Funnel server is running in a pod and
// attempts to use https://godoc.org/k8s.io/client-go/rest#InClusterConfig to infer configuration.
ConfigFile string
diff --git a/config/default-config.yaml b/config/default-config.yaml
index 21b7b409a..15cf647f3 100644
--- a/config/default-config.yaml
+++ b/config/default-config.yaml
@@ -299,7 +299,7 @@ AWSBatch:
# Kubernetes describes the configuration for the Kubernetes compute backend.
Kubernetes:
# The executor used to execute tasks. Available executors: docker, kubernetes
- Executor: "kubernetes"
+ Executor: "docker"
# Turn off task state reconciler. When enabled, Funnel communicates with Kubernetes
# to find tasks that are stuck in a queued state or errored and
# updates the task state accordingly.
diff --git a/config/default.go b/config/default.go
index 2dfde8f1c..f873a859c 100644
--- a/config/default.go
+++ b/config/default.go
@@ -164,11 +164,17 @@ func DefaultConfig() Config {
kubernetesTemplate := intern.MustAsset("config/kubernetes-template.yaml")
executorTemplate := intern.MustAsset("config/kubernetes-executor-template.yaml")
+ pvTemplate := intern.MustAsset("config/kubernetes-pv.yaml")
+ pvcTemplate := intern.MustAsset("config/kubernetes-pvc.yaml")
c.Kubernetes.Executor = "docker"
c.Kubernetes.Namespace = "default"
c.Kubernetes.ServiceAccount = "funnel-sa"
c.Kubernetes.Template = string(kubernetesTemplate)
c.Kubernetes.ExecutorTemplate = string(executorTemplate)
+ c.Kubernetes.Bucket = ""
+ c.Kubernetes.Region = ""
+ c.Kubernetes.PVTemplate = string(pvTemplate)
+ c.Kubernetes.PVCTemplate = string(pvcTemplate)
c.Kubernetes.ReconcileRate = reconcile
return c
diff --git a/config/internal/bundle.go b/config/internal/bundle.go
index c4f9a5310..a707627bd 100644
--- a/config/internal/bundle.go
+++ b/config/internal/bundle.go
@@ -1,12 +1,14 @@
// Code generated by go-bindata. DO NOT EDIT.
// sources:
+// config/kubernetes-pvc.yaml (309B)
// config/gridengine-template.txt (346B)
// config/pbs-template.txt (361B)
// config/slurm-template.txt (415B)
-// config/kubernetes-executor-template.yaml (1.764kB)
+// config/kubernetes-pv.yaml (560B)
+// 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
@@ -74,6 +76,26 @@ func (fi bindataFileInfo) Sys() interface{} {
return nil
}
+var _configKubernetesPvcYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x54\x8f\xc1\x6a\xf3\x30\x10\x84\xef\x7a\x8a\x81\xff\xec\xfc\xe4\xaa\x6b\x28\xa5\x87\x84\x50\x8a\x73\xde\xca\xd3\x22\x6c\x4b\xaa\x56\x32\x2d\x26\xef\x5e\x6c\x6c\x4a\x8e\xb3\x3b\xf3\xc1\xf7\x0f\xb7\x98\x7b\xe6\xff\x4f\xdf\x74\xb5\xc4\x8c\x6b\x7b\x32\x92\x7c\xcb\xac\x3e\x06\x8b\xe9\x68\x7a\x1f\x3a\x8b\xeb\x72\xd1\xc2\x50\xda\x38\xd4\x91\xa7\x41\xfc\x68\x46\x16\xe9\xa4\x88\x35\x40\x90\x91\x16\x1f\x35\x04\x0e\x4d\x9a\x5c\x33\xcf\x87\x37\xd1\xfe\xa5\xbb\xdf\xb7\xb7\x26\x71\xb4\x98\x67\x1c\x2e\x7b\xc4\xfa\x1d\xe4\x9d\x83\x2e\x18\x40\x52\xda\x39\x6b\x2e\x2b\x64\x99\xfd\xf1\x34\xd1\x2d\x6d\x71\x8e\xaa\xe7\xd8\x71\x1b\x37\x78\xa5\x74\xb7\xec\x0b\xcf\x12\x7e\x0c\x90\xa9\xb1\x66\xb7\x17\x32\xbf\x2a\xb5\x6c\x09\xd0\x12\xb3\x7c\xd2\xe2\xf8\xec\x0d\x30\xad\x76\x97\x47\x97\x07\x95\xdf\x00\x00\x00\xff\xff\x01\x27\x69\xed\x35\x01\x00\x00")
+
+func configKubernetesPvcYamlBytes() ([]byte, error) {
+ return bindataRead(
+ _configKubernetesPvcYaml,
+ "config/kubernetes-pvc.yaml",
+ )
+}
+
+func configKubernetesPvcYaml() (*asset, error) {
+ bytes, err := configKubernetesPvcYamlBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "config/kubernetes-pvc.yaml", size: 309, mode: os.FileMode(0644), modTime: time.Unix(1732590327, 0)}
+ a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe9, 0xc, 0x1f, 0x92, 0xa1, 0xb3, 0x7, 0x8, 0xb0, 0x29, 0x2f, 0x8e, 0x77, 0x9d, 0x10, 0x18, 0xc6, 0xcd, 0x90, 0xbf, 0xdf, 0x92, 0xf6, 0xf5, 0x81, 0x70, 0x47, 0xb6, 0x35, 0x85, 0x1a, 0x9d}}
+ return a, nil
+}
+
var _configGridengineTemplateTxt = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x7c\x90\xcd\x4a\xc4\x30\x14\x85\xf7\x79\x8a\x6b\xc7\x59\x26\xed\x0b\xb8\xb2\x30\xb8\x71\x21\x82\x4b\x69\xc9\x0d\x13\x32\xf9\xe1\x26\x51\x30\xe4\xdd\xa5\x69\x11\x0a\x75\x76\x97\xc3\x77\x3e\xb8\xe7\xf4\xd0\xcf\xda\xf5\xf3\x14\xaf\xec\xf4\x08\xfc\x15\x4a\x11\xef\x53\x34\x2f\xb2\xd6\x96\xf8\x25\xf9\xf0\x64\x46\x4d\xb5\xf6\x2a\x3b\x87\x37\x1e\x93\xf4\x39\x35\x00\xff\x03\x90\x88\x95\xa2\x15\x38\x04\xf1\x1c\x72\x84\x01\x78\xad\xac\x94\x40\xda\x25\x05\xdd\x52\x0f\x08\x36\x68\x38\xcb\x6e\x85\x1a\xc0\x01\x9d\x6c\xd7\x56\x7f\x9b\xec\x65\x86\x41\x1c\x19\x6e\x70\xfd\xfc\xb2\x68\x9f\xce\x62\x50\x97\x6e\x83\x8f\x3d\xa3\x8e\xe6\xae\x48\x45\xfd\x83\x7f\xa6\x15\xdf\xa9\xd8\xfa\x20\x7c\x7b\x32\x48\x40\xd9\x01\xe7\x69\x59\x6c\xdc\x6d\xf7\x1b\x00\x00\xff\xff\xcf\x92\x30\x7f\x5a\x01\x00\x00")
func configGridengineTemplateTxtBytes() ([]byte, error) {
@@ -134,7 +156,27 @@ 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 _configKubernetesPvYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x5c\x91\x41\xab\xdb\x30\x0c\xc7\xef\xfe\x14\x82\x9d\x93\xed\x31\x1e\x03\xc3\x3b\x6c\x30\xb6\x1d\xda\x95\x30\xda\xb3\x6a\xab\x45\xc4\xb1\x8d\xad\xa4\x2b\xa1\xdf\x7d\xd8\x69\xc6\x6b\x6f\x96\xf4\xd3\x5f\xfa\x5b\x1f\xe0\x10\x52\x4f\xe9\xe3\xf7\xbf\x64\x46\x09\x09\x76\x7b\x85\x91\xf7\x94\x32\x07\xaf\x61\x7a\x51\x3d\x7b\xab\x61\x57\x32\x59\xc8\xcb\x3e\xb8\x71\x20\x35\x90\xa0\x45\x41\xad\x00\x3c\x0e\xa4\xe1\x34\x7a\x4f\xae\x89\x53\x33\xcf\xed\x1f\xcc\xfd\x2f\x7b\xbb\x29\x00\x87\x47\x72\xb9\x70\x00\x18\xe3\x0a\xd6\x58\x2a\xa6\xe1\x7d\x47\x8e\x64\x0a\x6d\x30\xa2\x61\xb9\x2e\x9d\x59\x42\xc2\x33\x69\x78\xf9\xc1\x0a\x00\x8d\xa1\x9c\x37\xc1\xd2\x5d\xb9\x81\x8e\xd0\x1e\x12\x0b\x6d\xd0\x5f\x15\x40\x7c\x5a\xb9\x23\xe3\x90\x87\x5d\x70\x6c\xae\x1a\x3a\x12\x64\xaf\x00\x86\x30\x7a\xf9\x1d\x85\x83\xff\xaf\x85\xce\x85\x4b\x63\xc9\x91\xd0\x43\x2a\x4c\x94\x2e\x65\xc8\x3d\x9b\xe8\xcc\xc1\xbf\xcd\x73\xdb\xd5\x57\x75\x5c\x0a\x27\x76\xd4\x0c\xc1\xd2\xdb\xa7\x2f\xaf\xaf\xc5\x4e\xe6\x45\xdd\x26\x9e\x28\x69\xc8\x9f\x5b\x93\xb9\xc5\x4b\x6e\x4d\x18\x6a\x69\xaa\x8b\xfe\x44\x6f\x1d\x15\xa0\x31\x99\x9f\x7e\x73\x85\xbe\x8a\x24\x3e\x8e\xb2\xfa\x07\x38\x8e\xa6\x27\xd9\xd6\x5b\xcc\x73\xfb\xad\x86\xb5\xa7\xfa\xee\xe8\xb4\x90\xe5\x5a\x39\xa2\x59\xb0\xed\x1a\xdd\xd5\x9f\x6e\x69\x1e\xc6\xff\x0b\x00\x00\xff\xff\x33\x84\x08\xef\x30\x02\x00\x00")
+
+func configKubernetesPvYamlBytes() ([]byte, error) {
+ return bindataRead(
+ _configKubernetesPvYaml,
+ "config/kubernetes-pv.yaml",
+ )
+}
+
+func configKubernetesPvYaml() (*asset, error) {
+ bytes, err := configKubernetesPvYamlBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "config/kubernetes-pv.yaml", size: 560, mode: os.FileMode(0644), modTime: time.Unix(1732649398, 0)}
+ a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa9, 0x15, 0x2e, 0x42, 0x94, 0x68, 0xc1, 0xf2, 0x27, 0xfe, 0xb7, 0xa7, 0xe8, 0x8d, 0x53, 0x1a, 0x1b, 0x36, 0xb0, 0x5c, 0xc, 0x59, 0xb4, 0x7d, 0x16, 0x9c, 0x2b, 0x72, 0xfc, 0x17, 0x7c, 0x20}}
+ return a, nil
+}
+
+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 +191,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(1733362467, 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
}
@@ -169,7 +211,7 @@ func configDefaultConfigYaml() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "config/default-config.yaml", size: 11655, mode: os.FileMode(0644), modTime: time.Unix(1732064227, 0)}
+ info := bindataFileInfo{name: "config/default-config.yaml", size: 11655, mode: os.FileMode(0644), modTime: time.Unix(1732326201, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x61, 0x5a, 0x7d, 0xb0, 0x9b, 0x9d, 0x13, 0x7, 0x49, 0xd0, 0x4c, 0xab, 0xc2, 0xe5, 0x37, 0xfa, 0x4a, 0x5a, 0x9a, 0x68, 0x89, 0x2b, 0x4b, 0x3e, 0xf3, 0x73, 0x35, 0x82, 0xe8, 0xf1, 0xbf, 0x3c}}
return a, nil
}
@@ -194,7 +236,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 +251,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
}
@@ -305,9 +347,11 @@ func AssetNames() []string {
// _bindata is a table, holding each asset generator, mapped to its name.
var _bindata = map[string]func() (*asset, error){
+ "config/kubernetes-pvc.yaml": configKubernetesPvcYaml,
"config/gridengine-template.txt": configGridengineTemplateTxt,
"config/pbs-template.txt": configPbsTemplateTxt,
"config/slurm-template.txt": configSlurmTemplateTxt,
+ "config/kubernetes-pv.yaml": configKubernetesPvYaml,
"config/kubernetes-executor-template.yaml": configKubernetesExecutorTemplateYaml,
"config/default-config.yaml": configDefaultConfigYaml,
"config/htcondor-template.txt": configHtcondorTemplateTxt,
@@ -365,6 +409,8 @@ var _bintree = &bintree{nil, map[string]*bintree{
"gridengine-template.txt": {configGridengineTemplateTxt, map[string]*bintree{}},
"htcondor-template.txt": {configHtcondorTemplateTxt, map[string]*bintree{}},
"kubernetes-executor-template.yaml": {configKubernetesExecutorTemplateYaml, map[string]*bintree{}},
+ "kubernetes-pv.yaml": {configKubernetesPvYaml, map[string]*bintree{}},
+ "kubernetes-pvc.yaml": {configKubernetesPvcYaml, map[string]*bintree{}},
"kubernetes-template.yaml": {configKubernetesTemplateYaml, map[string]*bintree{}},
"pbs-template.txt": {configPbsTemplateTxt, map[string]*bintree{}},
"slurm-template.txt": {configSlurmTemplateTxt, map[string]*bintree{}},
diff --git a/config/kubernetes-executor-template.yaml b/config/kubernetes-executor-template.yaml
index 8e10d2546..b87f8ef7f 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-pv.yaml b/config/kubernetes-pv.yaml
new file mode 100644
index 000000000..7bc53f64f
--- /dev/null
+++ b/config/kubernetes-pv.yaml
@@ -0,0 +1,27 @@
+# Worker/Executor PV
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+ name: funnel-pv-{{.TaskId}}
+ labels:
+ app: funnel
+ taskId: {{.TaskId}}
+spec:
+ capacity:
+ storage: 1Gi
+ accessModes:
+ - ReadWriteMany
+ persistentVolumeReclaimPolicy: Retain
+ mountOptions:
+ - allow-delete
+ - allow-overwrite
+ - region={{.Region}}
+ - file-mode=0755
+ csi:
+ driver: s3.csi.aws.com
+ volumeHandle: s3-csi-{{.TaskId}}
+ volumeAttributes:
+ bucketName: {{.Bucket}}
+ claimRef:
+ namespace: {{.Namespace}}
+ name: funnel-pvc-{{.TaskId}}
diff --git a/config/kubernetes-pvc.yaml b/config/kubernetes-pvc.yaml
new file mode 100644
index 000000000..183a87ba9
--- /dev/null
+++ b/config/kubernetes-pvc.yaml
@@ -0,0 +1,16 @@
+# Worker/Executor PVC
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: funnel-pvc-{{.TaskId}}
+ namespace: {{ .Namespace }}
+ labels:
+ app: funnel
+ taskId: {{.TaskId}}
+spec:
+ accessModes:
+ - ReadWriteMany
+ resources:
+ requests:
+ storage: 1Gi
+ volumeName: funnel-pv-{{.TaskId}}
diff --git a/config/kubernetes-template.yaml b/config/kubernetes-template.yaml
index 81239b68a..97f8af013 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 42db24fba..d55e41595 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.15
# 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/config/funnel-server.yaml b/deployments/kubernetes/helm/config/funnel-server.yaml
index 29812b538..5deeb38fe 100644
--- a/deployments/kubernetes/helm/config/funnel-server.yaml
+++ b/deployments/kubernetes/helm/config/funnel-server.yaml
@@ -1,8 +1,15 @@
Compute: {{ .Values.Compute }}
Kubernetes:
- Executor: "kubernetes"
+ Executor: {{ .Values.Kubernetes.Executor }}
Namespace: {{ .Release.Namespace }}
+ DisableReconciler: {{ .Values.Kubernetes.DisableReconciler }}
+ ReconcileRate: {{ .Values.Kubernetes.ReconcileRate }}
+ ServiceAccount: {{ .Values.Kubernetes.ServiceAccount }}
+ Template: {{ .Values.Kubernetes.Template }}
+ TemplateFile: {{ .Values.Kubernetes.TemplateFile }}
+ Bucket: {{ .Values.Kubernetes.Bucket }}
+ Region: {{ .Values.Kubernetes.Region }}
Database: {{ .Values.Database }}
diff --git a/deployments/kubernetes/helm/config/funnel-worker.yaml b/deployments/kubernetes/helm/config/funnel-worker.yaml
index 5f2a3cb61..d8abf37d3 100644
--- a/deployments/kubernetes/helm/config/funnel-worker.yaml
+++ b/deployments/kubernetes/helm/config/funnel-worker.yaml
@@ -3,8 +3,15 @@ Database: {{ .Values.Database }}
Compute: {{ .Values.Compute }}
Kubernetes:
- Executor: "kubernetes"
+ Executor: {{ .Values.Kubernetes.Executor }}
Namespace: {{ .Release.Namespace }}
+ DisableReconciler: {{ .Values.Kubernetes.DisableReconciler }}
+ ReconcileRate: {{ .Values.Kubernetes.ReconcileRate }}
+ ServiceAccount: {{ .Values.Kubernetes.ServiceAccount }}
+ Template: {{ .Values.Kubernetes.Template }}
+ TemplateFile: {{ .Values.Kubernetes.TemplateFile }}
+ Bucket: {{ .Values.Kubernetes.Bucket }}
+ Region: {{ .Values.Kubernetes.Region }}
Logger:
Level: {{ .Values.Logger.level }}
diff --git a/deployments/kubernetes/helm/templates/NOTES.txt b/deployments/kubernetes/helm/templates/NOTES.txt
index 19666b112..34e155afb 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 000000000..31e4ff694
--- /dev/null
+++ b/deployments/kubernetes/helm/templates/clusterrole.yaml
@@ -0,0 +1,15 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ name: {{ .Release.Namespace }}-{{ .Release.Name }}-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 000000000..6c3584fa6
--- /dev/null
+++ b/deployments/kubernetes/helm/templates/clusterrolebinding.yaml
@@ -0,0 +1,12 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: {{ .Release.Namespace }}-{{ .Release.Name }}-clusterrolebinding
+subjects:
+- kind: ServiceAccount
+ name: funnel-sa
+ namespace: {{ .Release.Namespace }}
+roleRef:
+ kind: ClusterRole
+ name: {{ .Release.Namespace }}-{{ .Release.Name }}-clusterrole
+ apiGroup: rbac.authorization.k8s.io
diff --git a/deployments/kubernetes/helm/templates/role.yaml b/deployments/kubernetes/helm/templates/role.yaml
index 64628d22e..32fa3b93c 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/deployments/kubernetes/helm/values.yaml b/deployments/kubernetes/helm/values.yaml
index 55ae99bf8..1860b2c60 100644
--- a/deployments/kubernetes/helm/values.yaml
+++ b/deployments/kubernetes/helm/values.yaml
@@ -349,7 +349,7 @@ AWSBatch:
# Kubernetes describes the configuration for the Kubernetes compute backend.
Kubernetes:
# The executor used to execute tasks. Available executors: docker, kubernetes
- Executor: "kubernetes"
+ Executor: "kubernetes"
# Turn off task state reconciler. When enabled, Funnel communicates with Kubernetes
# to find tasks that are stuck in a queued state or errored and
# updates the task state accordingly.
@@ -365,6 +365,10 @@ Kubernetes:
Template: ""
# TemplateFile is the path to the master job template.
TemplateFile: ""
+ # The bucket to use for the task's Working Directory
+ Bucket: ""
+ # The region to use for the task's Bucket
+ Region: ""
# Configuration of the Kubernetes executor.
diff --git a/examples/internal/bundle.go b/examples/internal/bundle.go
index b8c2533b5..4699b377d 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
}
diff --git a/funnel.config.yml b/funnel.config.yml
deleted file mode 100644
index caf984b06..000000000
--- a/funnel.config.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-LocalStorage:
- # Whitelist of local directory paths which Funnel is allowed to access.
- AllowedDirs:
- - ./
- - /tmp
-
-Worker:
- LeaveWorkDir: true
diff --git a/go.mod b/go.mod
index 3b8faf2e5..e95132c1e 100644
--- a/go.mod
+++ b/go.mod
@@ -135,6 +135,7 @@ require (
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/montanaflynn/stats v0.7.1 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
+ github.com/muonsoft/openapi-mock v0.3.9 // indirect
github.com/nsf/termbox-go v1.1.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect
diff --git a/go.sum b/go.sum
index 6d8271209..b99eb742e 100644
--- a/go.sum
+++ b/go.sum
@@ -316,6 +316,8 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/muonsoft/openapi-mock v0.3.9 h1:MNeqzwk6QzGTtnhvyRyDIywvt1YdCIvBEbtENiOnXmo=
+github.com/muonsoft/openapi-mock v0.3.9/go.mod h1:M5zGO4+q2BSS+KKsZtHX+lBFKMJ5QTQ0PdK2SdhHHc4=
github.com/ncw/swift v1.0.53 h1:luHjjTNtekIEvHg5KdAFIBaH7bWfNkefwFnpDffSIks=
github.com/ncw/swift v1.0.53/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/nsf/termbox-go v1.1.1 h1:nksUPLCb73Q++DwbYUBEglYBRPZyoXJdrj5L+TkjyZY=
diff --git a/website/content/docs/compute/kubernetes.md b/website/content/docs/compute/kubernetes.md
index 004a285fb..b484fda49 100644
--- a/website/content/docs/compute/kubernetes.md
+++ b/website/content/docs/compute/kubernetes.md
@@ -104,7 +104,9 @@ funnel task create hello-world.json
# Storage Architecture
-
+
+
+
# Additional Resources 📚
diff --git a/website/static/img/k8s-pvc.png b/website/static/img/k8s-pvc.png
index 9325fb5bc..7a815d5b5 100644
Binary files a/website/static/img/k8s-pvc.png and b/website/static/img/k8s-pvc.png differ
diff --git a/worker/kubernetes.go b/worker/kubernetes.go
index 2ad7ca6b4..49987127c 100644
--- a/worker/kubernetes.go
+++ b/worker/kubernetes.go
@@ -5,6 +5,7 @@ import (
"context"
"fmt"
"io"
+ "strings"
"text/template"
"github.com/ohsu-comp-bio/funnel/tes"
@@ -26,10 +27,11 @@ type KubernetesCommand struct {
Namespace string
Resources *tes.Resources
ServiceAccount string
+ Clientset kubernetes.Interface
Command
}
-// Create the Executor K8s job
+// Create the Executor K8s job from kubernetes-executor-template.yaml
// Funnel Worker job is created in compute/kubernetes/backend.go#createJob
func (kcmd KubernetesCommand) Run(ctx context.Context) error {
var taskId = kcmd.TaskId
@@ -43,6 +45,11 @@ func (kcmd KubernetesCommand) Run(ctx context.Context) error {
if kcmd.StdinFile != "" {
command = append(command, "<", kcmd.StdinFile)
}
+ for i, v := range command {
+ if strings.Contains(v, " ") {
+ command[i] = fmt.Sprintf("'%s'", v)
+ }
+ }
var buf bytes.Buffer
err = tpl.Execute(&buf, map[string]interface{}{
@@ -74,9 +81,13 @@ func (kcmd KubernetesCommand) Run(ctx context.Context) error {
return err
}
- clientset, err := getKubernetesClientset()
- if err != nil {
- return err
+ clientset := kcmd.Clientset
+ if clientset == nil {
+ var err error
+ clientset, err = getKubernetesClientset()
+ if err != nil {
+ return err
+ }
}
var client = clientset.BatchV1().Jobs(kcmd.Namespace)
diff --git a/worker/worker.go b/worker/worker.go
index ab4210202..93683ddf0 100644
--- a/worker/worker.go
+++ b/worker/worker.go
@@ -34,6 +34,10 @@ type Executor struct {
Backend string
// Kubernetes executor template
Template string
+ // Kubernetes persistent volume template
+ PVTemplate string
+ // Kubernetes persistent volume claim template
+ PVCTemplate string
// Kubernetes namespace
Namespace string
// Kubernetes service account name