Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/integration-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
env:
KIND_CLUSTER_NAME: fournos-ci
KIND_EXPERIMENTAL_PROVIDER: docker
FOURNOS_NAMESPACE: psap-automation-ci-test
FOURNOS_WORKLOAD_NAMESPACE: psap-automation-ci-test

jobs:
integration:
Expand Down
10 changes: 5 additions & 5 deletions Fournos_Design_Document.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ sequenceDiagram
1. **on_create**: Operator validates the spec (cluster exists if specified, `exclusive` requires `cluster` — and `exclusive` defaults to `true`). If `spec.shutdown` is set (`Stop` or `Terminate`), immediately sets `phase=Stopped`. Otherwise sets `phase=Resolving`.
2. **timer (Resolving)**: Reads the `fournos.dev/resolve-image` annotation from the Tekton Pipeline referenced by `spec.pipeline` and launches a resolve K8s Job using that image. The resolve Job patches the FournosJob spec with `hardware` (if not user-provided) and `secretRefs`. Polls the Job for completion. On success, reads the FournosJob spec, validates hardware (GPU type checked against Kueue; hardware is optional for exclusive+cluster jobs), validates `secretRefs` against Vault secrets, creates the Kueue Workload (exclusive jobs request all 100 `fournos/cluster-slot` units; non-exclusive jobs request 1), and sets `phase=Pending`. Failed resolve Jobs are preserved for debugging.
3. **timer (Pending)**: Polls the Workload for Kueue admission. On admission, extracts the assigned cluster and sets `phase=Admitted`.
4. **timer (Admitted)**: Reads `secretRefs` from the FournosJob spec, copies each referenced secret from `secrets_namespace` into the operator namespace (per-job name `<fjob-name>-<ref>`, with `ownerReferences` for automatic cleanup), resolves the kubeconfig Secret, creates the Tekton PipelineRun with `FJOB_NAME` + `FOURNOS_NAMESPACE` params (so the execution engine can look up the full spec), a projected `vault-secrets` volume mounting all copied secrets at `/var/run/secrets/fournos/<entry-name>/`, and `ownerReferences` pointing at the FournosJob, sets `phase=Running`.
4. **timer (Admitted)**: Reads `secretRefs` from the FournosJob spec, copies each referenced secret from `secrets_namespace` into the operator namespace (per-job name `<fjob-name>-<ref>`, with `ownerReferences` for automatic cleanup), resolves the kubeconfig Secret, creates the Tekton PipelineRun with `FJOB_NAME` + `FOURNOS_WORKLOAD_NAMESPACE` params (so the execution engine can look up the full spec), a projected `vault-secrets` volume mounting all copied secrets at `/var/run/secrets/fournos/<entry-name>/`, and `ownerReferences` pointing at the FournosJob, sets `phase=Running`.
5. **timer (Running)**: Polls the PipelineRun for completion. On success/failure, deletes the Workload and sets `phase=Succeeded` or `phase=Failed`.
6. **timer (any non-terminal phase, shutdown)**: If `spec.shutdown` is set (`Stop` or `Terminate`) and the job has a PipelineRun (Admitted/Running), the timer cancels the PipelineRun — `Stop` uses Tekton's `CancelledRunFinally` (runs `finally` tasks), `Terminate` uses `Cancelled` (skips `finally` tasks) — and sets `phase=Stopping`. The Workload is **not** deleted yet — it stays alive to hold the cluster slot while the PipelineRun winds down. If no PipelineRun exists (Pending), the Workload is deleted immediately and the job goes straight to `phase=Stopped`.
7. **timer (Stopping)**: Polls the PipelineRun until it reaches a terminal state (`succeeded` or `failed`). Once complete, deletes the Workload to release Kueue quota and sets `phase=Stopped`.
Expand Down Expand Up @@ -258,7 +258,7 @@ The execution engine is the benchmark framework that runs on the hub cluster ins
Instead of extracting individual fields from the FournosJob spec and passing them as separate pipeline params, the operator passes two identifiers to both the resolve Job and the Tekton Pipeline:

- **`FJOB_NAME`** — the FournosJob `metadata.name`
- **`FOURNOS_NAMESPACE`** — the operator namespace
- **`FOURNOS_WORKLOAD_NAMESPACE`** — the namespace where FournosJobs and their execution resources (PipelineRuns, Workloads) live

The execution engine uses these to look up the full FournosJob spec via the Kubernetes API, giving it access to all configuration in one go (`spec.executionEngine`, `spec.env`, etc.) without the operator needing to serialize and forward individual fields.

Expand Down Expand Up @@ -324,7 +324,7 @@ Namespace-scoped tenant on a shared OpenShift management cluster:
```bash
kubectl apply -f manifests/crd.yaml
for rbac_file in manifests/rbac/*.yaml; do
cat "$rbac_file" | NAMESPACE=$FOURNOS_NAMESPACE envsubst | oc apply -f- -n $FOURNOS_NAMESPACE
cat "$rbac_file" | NAMESPACE=$FOURNOS_WORKLOAD_NAMESPACE envsubst | oc apply -f- -n $FOURNOS_WORKLOAD_NAMESPACE
done
kubectl apply -f config/kueue-config.yaml
kubectl apply -f config/kueue-cluster-config.yaml
Expand All @@ -338,7 +338,7 @@ All settings via environment variables with `FOURNOS_` prefix ([fournos/settings

| Variable | Default | Description |
| ----------------------------------- | ---------------------- | ------------------------------ |
| `FOURNOS_NAMESPACE` | `psap-automation` | Kubernetes namespace |
| `FOURNOS_WORKLOAD_NAMESPACE` | `psap-automation` | Namespace for FournosJobs and execution resources |
| `FOURNOS_SECRETS_NAMESPACE` | `psap-secrets` | Dedicated namespace for secrets |
| `FOURNOS_TEKTON_DASHBOARD_URL` | *(empty)* | Tekton Dashboard base URL |
| `FOURNOS_KUBECONFIG_SECRET_PATTERN` | `kubeconfig-{cluster}` | Secret name pattern |
Expand Down Expand Up @@ -408,7 +408,7 @@ README.md
- **CRD-based operator** (kopf) — consumers interact via `kubectl` / Kubernetes API, getting RBAC, audit logging, and `kubectl wait` for free
- **Unified Kueue scheduling** — all jobs flow through Kueue for consistent quota tracking and priority ordering. Cluster-pinned jobs use `nodeSelector` to constrain admission to a single ResourceFlavor; hardware-request jobs leave all flavors eligible.
- **Separation of concerns** — Fournos owns scheduling, bookkeeping, and parameter passing; the execution engine (e.g. FORGE) owns all target-cluster operations (setup, execution, cleanup). Fournos never touches target clusters directly.
- **Execution engine is opaque** — Fournos never validates execution engine config; it passes `FJOB_NAME` and `FOURNOS_NAMESPACE` so the execution engine can look up the full FournosJob spec via the K8s API
- **Execution engine is opaque** — Fournos never validates execution engine config; it passes `FJOB_NAME` and `FOURNOS_WORKLOAD_NAMESPACE` so the execution engine can look up the full FournosJob spec via the K8s API
- **Tekton for execution, Kueue for scheduling** — virtual Workload pattern with `fournos/gpu-`* resources
- **Stateless operator** — all job state lives in Kubernetes resources (FournosJob CRs, PipelineRuns, Workloads), not in memory. Crash-safe via `on_resume`.
- **Timer-based reconciliation** — the operator polls Workload admission and PipelineRun completion via a kopf timer (5s interval), eliminating the need for callback tasks or watch streams on third-party resources
Expand Down
38 changes: 25 additions & 13 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ KIND_CLUSTER_NAME ?= fournos-dev
KIND_EXPERIMENTAL_PROVIDER ?= podman
KIND_CONTEXT := kind-$(KIND_CLUSTER_NAME)
VENV_BIN := $(if $(wildcard .venv/bin/),.venv/bin/,)
FOURNOS_NAMESPACE ?= fournos-local-dev
FOURNOS_CONTROLLER_NAMESPACE ?= fournos-controller-local
FOURNOS_WORKLOAD_NAMESPACE ?= fournos-local-dev
FOURNOS_SECRETS_NAMESPACE ?= psap-secrets

.PHONY: lint format test docker-build docker-push \
Expand Down Expand Up @@ -32,24 +33,31 @@ install:
kubectl apply -f manifests/crd.yaml

deploy: install
kubectl create ns $(FOURNOS_SECRETS_NAMESPACE) --dry-run -oyaml | kubectl apply -f-
for rbac_file in manifests/rbac/*.yaml; do \
cat $$rbac_file | NAMESPACE=$(FOURNOS_NAMESPACE) envsubst | kubectl apply -f- -n $(FOURNOS_NAMESPACE); \
kubectl create ns $(FOURNOS_CONTROLLER_NAMESPACE) --dry-run=client -oyaml | kubectl apply -f-
kubectl create ns $(FOURNOS_WORKLOAD_NAMESPACE) --dry-run=client -oyaml | kubectl apply -f-
kubectl label ns $(FOURNOS_WORKLOAD_NAMESPACE) fournos.dev/queue-access=true --overwrite
kubectl create ns $(FOURNOS_SECRETS_NAMESPACE) --dry-run=client -oyaml | kubectl apply -f-
kubectl apply -f manifests/rbac/sa_fournos.yaml -n $(FOURNOS_CONTROLLER_NAMESPACE)
kubectl apply -f manifests/rbac/sa_fournos.yaml -n $(FOURNOS_WORKLOAD_NAMESPACE)
for rbac_file in manifests/rbac/role_fournos.yaml manifests/rbac/rolebinding_fournos.yaml; do \
cat $$rbac_file | CONTROLLER_NAMESPACE=$(FOURNOS_CONTROLLER_NAMESPACE) envsubst '$$CONTROLLER_NAMESPACE' | kubectl apply -f- -n $(FOURNOS_WORKLOAD_NAMESPACE); \
done
cat manifests/rbac/clusterrole_fournos.yaml | kubectl apply -f-
cat manifests/rbac/clusterrolebinding_fournos.yaml | CONTROLLER_NAMESPACE=$(FOURNOS_CONTROLLER_NAMESPACE) envsubst '$$CONTROLLER_NAMESPACE' | kubectl apply -f-
cat manifests/secrets-ns-rbac.yaml \
| NAMESPACE=$(FOURNOS_NAMESPACE) SECRETS_NAMESPACE=$(FOURNOS_SECRETS_NAMESPACE) envsubst \
| CONTROLLER_NAMESPACE=$(FOURNOS_CONTROLLER_NAMESPACE) SECRETS_NAMESPACE=$(FOURNOS_SECRETS_NAMESPACE) envsubst \
| kubectl apply -f-
kubectl apply -f config/kueue-cluster-config.yaml
kubectl apply -f config/kueue-config.yaml -n $(FOURNOS_NAMESPACE)
kubectl apply -f config/kueue-config.yaml -n $(FOURNOS_WORKLOAD_NAMESPACE)
for wf in config/forge/workflows/*.yaml; do \
cat $$wf | NAMESPACE=$(FOURNOS_NAMESPACE) envsubst '$$NAMESPACE' | kubectl apply -f- -n $(FOURNOS_NAMESPACE); \
cat $$wf | NAMESPACE=$(FOURNOS_WORKLOAD_NAMESPACE) envsubst '$$NAMESPACE' | kubectl apply -f- -n $(FOURNOS_WORKLOAD_NAMESPACE); \
done
kubectl apply -f manifests/deployment.yaml -n $(FOURNOS_NAMESPACE)
cat manifests/deployment.yaml | NAMESPACE=$(FOURNOS_WORKLOAD_NAMESPACE) envsubst '$$NAMESPACE' | kubectl apply -f- -n $(FOURNOS_CONTROLLER_NAMESPACE)

##@ Testing

test:
FOURNOS_NAMESPACE=$(or $(FOURNOS_NAMESPACE),fournos-local-dev) \
FOURNOS_WORKLOAD_NAMESPACE=$(or $(FOURNOS_WORKLOAD_NAMESPACE),fournos-local-dev) \
FOURNOS_SECRETS_NAMESPACE=$(or $(FOURNOS_SECRETS_NAMESPACE),psap-secrets) \
$(VENV_BIN)pytest -v tests/

Expand All @@ -66,13 +74,15 @@ sync-vault-secrets-dry-run:
dev-setup:
@KIND_CLUSTER_NAME=$(KIND_CLUSTER_NAME) \
KIND_EXPERIMENTAL_PROVIDER=$(KIND_EXPERIMENTAL_PROVIDER) \
FOURNOS_NAMESPACE=$(or $(FOURNOS_NAMESPACE),fournos-local-dev) \
FOURNOS_CONTROLLER_NAMESPACE=$(FOURNOS_CONTROLLER_NAMESPACE) \
FOURNOS_WORKLOAD_NAMESPACE=$(or $(FOURNOS_WORKLOAD_NAMESPACE),fournos-local-dev) \
FOURNOS_SECRETS_NAMESPACE=$(or $(FOURNOS_SECRETS_NAMESPACE),psap-secrets) \
bash dev/setup.sh

dev-run:
FOURNOS_GC_INTERVAL_SEC=5 \
FOURNOS_NAMESPACE=$(or $(FOURNOS_NAMESPACE),fournos-local-dev) \
FOURNOS_CONTROLLER_NAMESPACE=$(FOURNOS_CONTROLLER_NAMESPACE) \
FOURNOS_WORKLOAD_NAMESPACE=$(or $(FOURNOS_WORKLOAD_NAMESPACE),fournos-local-dev) \
FOURNOS_SECRETS_NAMESPACE=$(or $(FOURNOS_SECRETS_NAMESPACE),psap-secrets) \
FOURNOS_RESOLVE_JOB_TEMPLATE=dev/mock-resolve/resolve_job.yaml \
$(VENV_BIN)python -m fournos
Expand All @@ -85,13 +95,15 @@ dev-teardown:
ci-setup:
@KIND_CLUSTER_NAME=$(KIND_CLUSTER_NAME) \
KIND_EXPERIMENTAL_PROVIDER=docker \
FOURNOS_NAMESPACE=$(or $(FOURNOS_NAMESPACE),psap-automation-ci-test) \
FOURNOS_CONTROLLER_NAMESPACE=$(or $(FOURNOS_CONTROLLER_NAMESPACE),fournos-controller-ci-test) \
FOURNOS_WORKLOAD_NAMESPACE=$(or $(FOURNOS_WORKLOAD_NAMESPACE),psap-automation-ci-test) \
FOURNOS_SECRETS_NAMESPACE=$(or $(FOURNOS_SECRETS_NAMESPACE),psap-secrets) \
bash dev/setup.sh

ci-run:
FOURNOS_GC_INTERVAL_SEC=5 \
FOURNOS_NAMESPACE=$(or $(FOURNOS_NAMESPACE),psap-automation-ci-test) \
FOURNOS_CONTROLLER_NAMESPACE=$(or $(FOURNOS_CONTROLLER_NAMESPACE),fournos-controller-ci-test) \
FOURNOS_WORKLOAD_NAMESPACE=$(or $(FOURNOS_WORKLOAD_NAMESPACE),psap-automation-ci-test) \
FOURNOS_SECRETS_NAMESPACE=$(or $(FOURNOS_SECRETS_NAMESPACE),psap-secrets) \
FOURNOS_RESOLVE_JOB_TEMPLATE=dev/mock-resolve/resolve_job.yaml \
$(VENV_BIN)python -m fournos \
Expand Down
63 changes: 26 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@ spec:
```

```bash
FOURNOS_NAMESPACE=fournos-$USER-dev
oc create -f config/forge/samples/job-full.yaml -n $FOURNOS_NAMESPACE # returns the generated name, e.g. forge-full-sample-x7k2m
oc get FournosJobs -n $FOURNOS_NAMESPACE -w # watch status transitions
oc patch FournosJob <name> -n $FOURNOS_NAMESPACE --type merge -p '{"spec":{"shutdown":"Stop"}}' # graceful stop (runs finally tasks)
oc patch FournosJob <name> -n $FOURNOS_NAMESPACE --type merge -p '{"spec":{"shutdown":"Terminate"}}' # immediate terminate (skips finally tasks)
oc delete FournosJob -n $FOURNOS_NAMESPACE <name> # cleanup
FOURNOS_WORKLOAD_NAMESPACE=fournos-$USER-dev
oc create -f config/forge/samples/job-full.yaml -n $FOURNOS_WORKLOAD_NAMESPACE # returns the generated name, e.g. forge-full-sample-x7k2m
oc get FournosJobs -n $FOURNOS_WORKLOAD_NAMESPACE -w # watch status transitions
oc patch FournosJob <name> -n $FOURNOS_WORKLOAD_NAMESPACE --type merge -p '{"spec":{"shutdown":"Stop"}}' # graceful stop (runs finally tasks)
oc patch FournosJob <name> -n $FOURNOS_WORKLOAD_NAMESPACE --type merge -p '{"spec":{"shutdown":"Terminate"}}' # immediate terminate (skips finally tasks)
oc delete FournosJob -n $FOURNOS_WORKLOAD_NAMESPACE <name> # cleanup
```

### Spec fields
Expand Down Expand Up @@ -122,12 +122,12 @@ make dev-run # starts the operator locally (connects to the kind cluster)
```

Both targets default to the `fournos-local-dev` namespace. Override with
`FOURNOS_NAMESPACE=<YOUR_NAMESPACE> make dev-setup dev-run`.
`FOURNOS_WORKLOAD_NAMESPACE=<YOUR_NAMESPACE> make dev-setup dev-run`.

In another terminal:

```bash
FOURNOS_NAMESPACE=fournos-local-dev make test # run the integration test suite
FOURNOS_WORKLOAD_NAMESPACE=fournos-local-dev make test # run the integration test suite
```

```bash
Expand All @@ -152,26 +152,15 @@ make test # integration tests (operator must be running)

**Execution engine on the hub:** [`config/forge/`](config/forge/) is the real OpenShift configuration for this repo — ImageStreams, Builds, Tekton Tasks and Pipelines, and sample jobs you apply to a cluster. It is **not** the same as the lightweight stand-ins under [`dev/mock-pipelines/`](dev/mock-pipelines/), which [`make dev-setup`](#local-development) installs on kind for local testing only.

Prepare the namespaces
```bash
FOURNOS_NAMESPACE=fournos-$USER-dev
FOURNOS_SECRETS_NAMESPACE=psap-secrets
oc create ns $FOURNOS_NAMESPACE
oc label ns/$FOURNOS_NAMESPACE fournos.dev/queue-access=true
oc create ns $FOURNOS_SECRETS_NAMESPACE
```

Deploy the operator:
Deploy the full stack (namespaces, CRD, RBAC, Kueue config, workflows, Deployment).
The operator runs in a dedicated controller namespace; execution resources
(Tekton, Kueue, FournosJobs) live in the execution namespace:

```bash
oc apply -n $FOURNOS_NAMESPACE -f manifests/crd.yaml
for rbac_file in manifests/rbac/*.yaml; do
cat $rbac_file | NAMESPACE=$FOURNOS_NAMESPACE envsubst | oc apply -f- -n $FOURNOS_NAMESPACE
done
cat manifests/secrets-ns-rbac.yaml \
| NAMESPACE=$FOURNOS_NAMESPACE SECRETS_NAMESPACE=$FOURNOS_SECRETS_NAMESPACE envsubst \
| oc apply -f-
oc apply -n $FOURNOS_NAMESPACE -f manifests/deployment.yaml
make deploy \
FOURNOS_CONTROLLER_NAMESPACE=fournos-controller-$USER \
FOURNOS_WORKLOAD_NAMESPACE=fournos-$USER-dev \
FOURNOS_SECRETS_NAMESPACE=psap-secrets
```

### Onboarding a new cluster
Expand Down Expand Up @@ -207,9 +196,9 @@ oc apply -f config/kueue-config.yaml
match the new target, then:

```bash
FOURNOS_NAMESPACE=fournos-$USER-dev
oc create -f config/fournos-validation/samples/test-connectivity-job.yaml -n $FOURNOS_NAMESPACE
oc get fournosjobs -n $FOURNOS_NAMESPACE -w # should reach Succeeded
FOURNOS_WORKLOAD_NAMESPACE=fournos-$USER-dev
oc create -f config/fournos-validation/samples/test-connectivity-job.yaml -n $FOURNOS_WORKLOAD_NAMESPACE
oc get fournosjobs -n $FOURNOS_WORKLOAD_NAMESPACE -w # should reach Succeeded
```

This runs the `fournos-validate-only` pipeline, which only checks `oc
Expand All @@ -220,17 +209,17 @@ details.

### Deploying the execution engine workflow configuration

Apply the production execution engine assets from `config/forge/` (not the kind mocks in `dev/mock-pipelines/`). Deploy the cluster configuration (Builds + Tekton):
Apply the production execution engine assets from `config/forge/` (not the kind mocks in `dev/mock-pipelines/`). Deploy the cluster configuration (Builds + Tekton) to the **execution namespace**:

```bash
oc apply -n $FOURNOS_NAMESPACE -f config/forge/images/is_forge.yaml
oc apply -n $FOURNOS_WORKLOAD_NAMESPACE -f config/forge/images/is_forge.yaml
cat config/forge/images/build_forge-main.yaml \
| sed 's/psap-automation/'$FOURNOS_NAMESPACE'/g' \
| oc apply -n $FOURNOS_NAMESPACE
oc create -n $FOURNOS_NAMESPACE -f config/forge/images/buildrun_forge-main.yaml
| NAMESPACE=$FOURNOS_WORKLOAD_NAMESPACE envsubst '$NAMESPACE' \
| oc apply -f- -n $FOURNOS_WORKLOAD_NAMESPACE
oc create -n $FOURNOS_WORKLOAD_NAMESPACE -f config/forge/images/buildrun_forge-main.yaml

for wf_file in config/forge/workflows/*.yaml; do
cat "$wf_file" | NAMESPACE=$FOURNOS_NAMESPACE envsubst '$NAMESPACE' | oc apply -f- -n $FOURNOS_NAMESPACE
cat "$wf_file" | NAMESPACE=$FOURNOS_WORKLOAD_NAMESPACE envsubst '$NAMESPACE' | oc apply -f- -n $FOURNOS_WORKLOAD_NAMESPACE
done
```

Expand Down Expand Up @@ -299,7 +288,7 @@ All settings are read from environment variables with the `FOURNOS_` prefix:

| Variable | Default | Description |
|---|---|---|
| `FOURNOS_NAMESPACE` | **required** | Kubernetes namespace |
| `FOURNOS_WORKLOAD_NAMESPACE` | **required** | Namespace for FournosJobs and execution resources |
| `FOURNOS_SECRETS_NAMESPACE` | `psap-secrets` | Namespace where kubeconfig and vault-synced secrets are stored |
| `FOURNOS_TEKTON_DASHBOARD_URL` | | Tekton Dashboard base URL |
| `FOURNOS_KUBECONFIG_SECRET_PATTERN` | `kubeconfig-{cluster}` | Pattern for resolving cluster names to Secret names |
Expand All @@ -324,7 +313,7 @@ The operator runs as a single-replica Deployment using
1. **Resolves** job requirements by launching a resolve K8s Job (using the configured execution engine image) that populates the FournosJob spec with GPU type/count and secret references
2. **Creates** a Kueue Workload with the resolved GPU resources (owned by the FournosJob via `ownerReferences`)
3. **Polls** (5 s timer) for Kueue admission and assigned cluster
4. **Copies** referenced Vault secrets from the secrets namespace into the operator namespace (per-job copies with `ownerReferences` for automatic cleanup) and **launches** a Tekton PipelineRun with `FJOB_NAME` + `FOURNOS_NAMESPACE` (so the execution engine can look up the full FournosJob spec), the secrets mounted as a projected volume at `/var/run/secrets/fournos/` (owned by the FournosJob via `ownerReferences`), and a shared `artifacts` workspace backed by a `volumeClaimTemplate` PVC for cross-task artifact storage (managed by Tekton)
4. **Copies** referenced Vault secrets from the secrets namespace into the operator namespace (per-job copies with `ownerReferences` for automatic cleanup) and **launches** a Tekton PipelineRun with `FJOB_NAME` + `FOURNOS_WORKLOAD_NAMESPACE` (so the execution engine can look up the full FournosJob spec), the secrets mounted as a projected volume at `/var/run/secrets/fournos/` (owned by the FournosJob via `ownerReferences`), and a shared `artifacts` workspace backed by a `volumeClaimTemplate` PVC for cross-task artifact storage (managed by Tekton)
5. **Watches** the PipelineRun until completion
6. **Deletes** the Workload to release Kueue quota

Expand Down
Loading
Loading