Repository: kubernetes-sigs/kueue

Issue:
Local queues prometheus metrics
**What would you like to be added**:

Expose Prometheus metrics for local queues, equivalent to the existing cluster queue metrics, but filtered and labeled by local queues.

Similarly to the visibility API, that serves information about pending workloads in local queues, it would be possible to get metrics like like pending workloads, admitted active workloads, resource usage, etc, for local queues.

If cardinality is a concern, those metrics could be exposed behind a feature flag.

**Why is this needed**:

Metrics about local queues can be useful for the batch users persona, so they can have visibility and historical trends about their workloads.

While some metrics are already available for cluster queues, exposing them to the batch users persona presents the following challenges / limitations:
* Cluster queues metrics are global and cannot be filtered by namespaces / tenants
* Querying "cluster-scoped" metrics in secured Prometheus instances is generally only authorised for cluster admin users that have access to all namespaces / tenants

**Completion requirements**:

This enhancement requires the following artifacts:

- [ ] Design doc
- [x] API change
- [ ] Docs update

The artifacts should be linked in subsequent comments.


Discussion:
@astefanutti: @alculquicondor @tenzen-y Do you think that'd be a useful / possible enhancement?@alculquicondor: > If cardinality is a concern, those metrics could be exposed behind a feature flag.

Yes, that's the primary concern. I wouldn't make it a feature flag, but a long-term configuration field.@tenzen-y: > @alculquicondor @tenzen-y Do you think that'd be a useful / possible enhancement?

I understand that this feature is so useful, but I have the same concern with @alculquicondor.
IIRC, previously, we had similar discussions when we designed Visibility/Visibility On-demand. 
So, if we introduce this feature, configurable this feature by [Config API](https://github.com/kubernetes-sigs/kueue/blob/74d17e38e76c2d8b47dbea74364aecc5529f3a78/config/components/manager/controller_manager_config.yaml) would be better.

Anyway, I guess that having a small KEP would be better since we may extend the existing Config API.

@astefanutti: That makes sense. There could be one or two options added to the Config API,  similar to the existing `.metrics.enableClusterQueueResources`, like `.metrics.enableLocalQueues` and `.metrics.enableLocalQueueResources`.

I can work on a small KEP if you guys give the green light.@alculquicondor: It seems simple enough.@tenzen-y: SGTM@astefanutti: Thanks for your quick feedback! I'll work on it asap.

/assign@k8s-triage-robot: The Kubernetes project currently lacks enough contributors to adequately respond to all issues.

This bot triages un-triaged issues according to the following rules:
- After 90d of inactivity, `lifecycle/stale` is applied
- After 30d of inactivity since `lifecycle/stale` was applied, `lifecycle/rotten` is applied
- After 30d of inactivity since `lifecycle/rotten` was applied, the issue is closed

You can:
- Mark this issue as fresh with `/remove-lifecycle stale`
- Close this issue with `/close`
- Offer to help out with [Issue Triage][1]

Please send feedback to sig-contributor-experience at [kubernetes/community](https://github.com/kubernetes/community).

/lifecycle stale

[1]: https://www.kubernetes.dev/docs/guide/issue-triage/@alculquicondor: @astefanutti are you still looking into this?@astefanutti: @alculquicondor I haven't, but hopefully we'll get back to it soon.@astefanutti: /remove-lifecycle stale@astefanutti: /unassign@alculquicondor: @varshaprasad96, please write `/assign` in a comment to claim this issue. It's important to communicate that you are working on an issue so that other contributors don't try to work on the same thing.@varshaprasad96: /assign@k8s-triage-robot: The Kubernetes project currently lacks enough contributors to adequately respond to all issues.

This bot triages un-triaged issues according to the following rules:
- After 90d of inactivity, `lifecycle/stale` is applied
- After 30d of inactivity since `lifecycle/stale` was applied, `lifecycle/rotten` is applied
- After 30d of inactivity since `lifecycle/rotten` was applied, the issue is closed

You can:
- Mark this issue as fresh with `/remove-lifecycle stale`
- Close this issue with `/close`
- Offer to help out with [Issue Triage][1]

Please send feedback to sig-contributor-experience at [kubernetes/community](https://github.com/kubernetes/community).

/lifecycle stale

[1]: https://www.kubernetes.dev/docs/guide/issue-triage/@tenzen-y: /remove-lifecycle stale

@varshaprasad96 Do you still work on this enhancement?
@varshaprasad96: @tenzen-y  Yes. I'm planning to get the implementation PR up by next few days. @tenzen-y: > @tenzen-y Yes. I'm planning to get the implementation PR up by next few days.

Awsome, thanks for your effort!
@KPostOffice: /assign@KPostOffice: I've been working on the this KEP for the last couple days and overall it seemed pretty straightforward, until I got to adding the LocalQueueByStatus metric since afaict the status metric for CQs is a bubbling up of the internal [cq.status](https://github.com/kubernetes-sigs/kueue/blob/9987c0d730c1d226993428cc4709ca2b2e5142f4/pkg/cache/clusterqueue.go#L67). The only representation of LQ states exists inside the [CQ struct](https://github.com/kubernetes-sigs/kueue/blob/9987c0d730c1d226993428cc4709ca2b2e5142f4/pkg/cache/clusterqueue.go#L74), and I felt like adding all LQs to the cache struct felt wrong. My current thought is to add a new Type in metrics `LocalQueueStatus` which has the following values (`active`, `pending`, and `orphaned`) where the LQ will inherit the status from its CQ parent. If the parent is terminating the LQ status will move to pending and if the CQ is deleted then the status would move to orphaned. When reconciling the LQ to update status I can just directly grab the status from the CQ in cache.@KPostOffice: cc @mimowo @PBundyra @tenzen-y @varshaprasad96: @KPostOffice Could you elaborate on where exactly in `localqueue_controller` are you trying to update the metrics. IIUC - the local queue reconciler [watches](https://github.com/kubernetes-sigs/kueue/blob/b0665c7d41b998d490e1f5f8a15dba278836868e/pkg/controller/core/localqueue_controller.go#L298) the CQ, and any status updates would be reflected in [here](https://github.com/kubernetes-sigs/kueue/blob/b0665c7d41b998d490e1f5f8a15dba278836868e/pkg/controller/core/localqueue_controller.go#L110-L122).

>  I felt like adding all LQs to the cache struct felt wrong

Also, the local_queue has reference to the respective [cluster queue](https://github.com/kubernetes-sigs/kueue/blob/b0665c7d41b998d490e1f5f8a15dba278836868e/pkg/queue/local_queue.go#L34). Can't we just directly query CQ's [cache status](https://github.com/kubernetes-sigs/kueue/blob/b0665c7d41b998d490e1f5f8a15dba278836868e/pkg/controller/core/localqueue_controller.go#L61) instead while reporting metrics?@KPostOffice: @varshaprasad96 I wasn't planning on adding the metrics to the `localqueue_controller` I was adding them to either `manager.go` or `cache` so that the metrics were reflective of Kueue's operational state, this is what is done for CQ status metrics, see [here](https://github.com/kubernetes-sigs/kueue/blob/b0665c7d41b998d490e1f5f8a15dba278836868e/pkg/cache/clusterqueue.go#L252). I'm having trouble figuring out how to exactly represent the LQ's status. I think it can just update when either:

1. a LQ is added
2. a LQ is updated
3. the LQ's underlying CQ status is updated@mimowo: /reopen 
we can use the issue for follow up API changes and Beta graduation. @k8s-ci-robot: @mimowo: Reopened this issue.

<details>

In response to [this](https://github.com/kubernetes-sigs/kueue/issues/1833#issuecomment-2520597690):

>/reopen 
>we can use the issue for follow up API changes and Beta graduation. 


Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository.
</details>@mimowo: Let's also update the documentation https://kueue.sigs.k8s.io/docs/reference/metrics/ to mention the LocalQueue metrics@tenzen-y: I added a comment for the guarding this metric by Config API: https://github.com/kubernetes-sigs/kueue/pull/3673#discussion_r1884162004

I am still wondering if we should guard this metric by that.
@tenzen-y: As we discussed in https://github.com/kubernetes-sigs/kueue/pull/3673#discussion_r1884172427, we will introduce the feature knob to the Config API in the v0.11 version, and then we will guard the slown down Prometheus query performance.
@k8s-triage-robot: The Kubernetes project currently lacks enough contributors to adequately respond to all issues.

This bot triages un-triaged issues according to the following rules:
- After 90d of inactivity, `lifecycle/stale` is applied
- After 30d of inactivity since `lifecycle/stale` was applied, `lifecycle/rotten` is applied
- After 30d of inactivity since `lifecycle/rotten` was applied, the issue is closed

You can:
- Mark this issue as fresh with `/remove-lifecycle stale`
- Close this issue with `/close`
- Offer to help out with [Issue Triage][1]

Please send feedback to sig-contributor-experience at [kubernetes/community](https://github.com/kubernetes/community).

/lifecycle stale

[1]: https://www.kubernetes.dev/docs/guide/issue-triage/@mimowo: /remove-lifecycle stale@k8s-triage-robot: The Kubernetes project currently lacks enough contributors to adequately respond to all issues.

This bot triages un-triaged issues according to the following rules:
- After 90d of inactivity, `lifecycle/stale` is applied
- After 30d of inactivity since `lifecycle/stale` was applied, `lifecycle/rotten` is applied
- After 30d of inactivity since `lifecycle/rotten` was applied, the issue is closed

You can:
- Mark this issue as fresh with `/remove-lifecycle stale`
- Close this issue with `/close`
- Offer to help out with [Issue Triage][1]

Please send feedback to sig-contributor-experience at [kubernetes/community](https://github.com/kubernetes/community).

/lifecycle stale

[1]: https://www.kubernetes.dev/docs/guide/issue-triage/@mimowo: /remove-lifecycle stale@k8s-triage-robot: The Kubernetes project currently lacks enough contributors to adequately respond to all issues.

This bot triages un-triaged issues according to the following rules:
- After 90d of inactivity, `lifecycle/stale` is applied
- After 30d of inactivity since `lifecycle/stale` was applied, `lifecycle/rotten` is applied
- After 30d of inactivity since `lifecycle/rotten` was applied, the issue is closed

You can:
- Mark this issue as fresh with `/remove-lifecycle stale`
- Close this issue with `/close`
- Offer to help out with [Issue Triage][1]

Please send feedback to sig-contributor-experience at [kubernetes/community](https://github.com/kubernetes/community).

/lifecycle stale

[1]: https://www.kubernetes.dev/docs/guide/issue-triage/@mimowo: @tenzen-y I want to re-evaluate this entire KEP. 

Rather than introducing new metrics, I would like to have an extra label "local_queue" in the existing once. 

For users concerns with the cardinality, we could have configuration indicating that value for "local_queue" is left empty.

I propose similar apporach inspired by the recent proposal to introduce workload_priority label. https://github.com/kubernetes-sigs/kueue/issues/5989@k8s-triage-robot: The Kubernetes project currently lacks enough active contributors to adequately respond to all issues.

This bot triages un-triaged issues according to the following rules:
- After 90d of inactivity, `lifecycle/stale` is applied
- After 30d of inactivity since `lifecycle/stale` was applied, `lifecycle/rotten` is applied
- After 30d of inactivity since `lifecycle/rotten` was applied, the issue is closed

You can:
- Mark this issue as fresh with `/remove-lifecycle rotten`
- Close this issue with `/close`
- Offer to help out with [Issue Triage][1]

Please send feedback to sig-contributor-experience at [kubernetes/community](https://github.com/kubernetes/community).

/lifecycle rotten

[1]: https://www.kubernetes.dev/docs/guide/issue-triage/@k8s-triage-robot: The Kubernetes project currently lacks enough active contributors to adequately respond to all issues and PRs.

This bot triages issues according to the following rules:
- After 90d of inactivity, `lifecycle/stale` is applied
- After 30d of inactivity since `lifecycle/stale` was applied, `lifecycle/rotten` is applied
- After 30d of inactivity since `lifecycle/rotten` was applied, the issue is closed

You can:
- Reopen this issue with `/reopen`
- Mark this issue as fresh with `/remove-lifecycle rotten`
- Offer to help out with [Issue Triage][1]

Please send feedback to sig-contributor-experience at [kubernetes/community](https://github.com/kubernetes/community).

/close not-planned

[1]: https://www.kubernetes.dev/docs/guide/issue-triage/@k8s-ci-robot: @k8s-triage-robot: Closing this issue, marking it as "Not Planned".

<details>

In response to [this](https://github.com/kubernetes-sigs/kueue/issues/1833#issuecomment-3507643393):

>The Kubernetes project currently lacks enough active contributors to adequately respond to all issues and PRs.
>
>This bot triages issues according to the following rules:
>- After 90d of inactivity, `lifecycle/stale` is applied
>- After 30d of inactivity since `lifecycle/stale` was applied, `lifecycle/rotten` is applied
>- After 30d of inactivity since `lifecycle/rotten` was applied, the issue is closed
>
>You can:
>- Reopen this issue with `/reopen`
>- Mark this issue as fresh with `/remove-lifecycle rotten`
>- Offer to help out with [Issue Triage][1]
>
>Please send feedback to sig-contributor-experience at [kubernetes/community](https://github.com/kubernetes/community).
>
>/close not-planned
>
>[1]: https://www.kubernetes.dev/docs/guide/issue-triage/


Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository.
</details>

Solution patch:
diff --git a/.github/ISSUE_TEMPLATE/NEW_RELEASE.md b/.github/ISSUE_TEMPLATE/NEW_RELEASE.md
index 7cc5614ae..71bc10e2c 100644
--- a/.github/ISSUE_TEMPLATE/NEW_RELEASE.md
+++ b/.github/ISSUE_TEMPLATE/NEW_RELEASE.md
@@ -37,7 +37,7 @@ Please do not remove items from the checklist
 - [ ] An OWNER pushes the tag with
       `git push $VERSION`
   - Triggers prow to build and publish a staging container image
-      `gcr.io/k8s-staging-kueue/kueue:$VERSION`
+      `us-central1-docker.pkg.dev/k8s-staging-images/kueue/kueue:$VERSION`
 - [ ] Submit a PR against [k8s.io](https://github.com/kubernetes/k8s.io),
       updating `registry.k8s.io/images/k8s-staging-kueue/images.yaml` to
       [promote the container images](https://github.com/kubernetes/k8s.io/tree/main/k8s.gcr.io#image-promoter)
@@ -51,10 +51,11 @@ Please do not remove items from the checklist
 - [ ] Send an announcement email to `sig-scheduling@kubernetes.io` and `wg-batch@kubernetes.io` with the subject `[ANNOUNCE] kueue $VERSION is released`.   <!--Link: example https://groups.google.com/a/kubernetes.io/g/wg-batch/c/-gZOrSnwDV4 -->
 - [ ] Update the below files with respective values in `main` branch :
   - Latest version in `README.md`
+  - Latest version in `cmd/experimental/kjobctl/docs/installation.md`
   - Release notes in the `CHANGELOG`
-  - `version` in `site/config.toml`
+  - `version` in `site/hugo.toml`
   - `appVersion` in `charts/kueue/Chart.yaml`
-  - `last-updated`, `last-reviewed`, `commit-hash`, `project-release`, `distribution-points` and `sbom-file` in `SECURITY-INSIGHTS.yaml`
+  - `SECURITY-INSIGHTS.yaml` values by running `make update-security-insights GIT_TAG=$VERSION`
 - [ ] For a major or minor release, prepare the repo for the next version:
   - [ ] create an unannotated _devel_ tag in the
         `main` branch, on the first commit that gets merged after the release
diff --git a/.github/workflows/krew-release.yml b/.github/workflows/krew-release.yml
new file mode 100644
index 000000000..3fac814de
--- /dev/null
+++ b/.github/workflows/krew-release.yml
@@ -0,0 +1,11 @@
+on:
+  release:
+    types: [released]
+jobs:
+  krew-release:
+    runs-on: ubuntu-24.04
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v4
+      - name: Update new version in krew-index
+        uses: rajatjindal/krew-release-bot@v0.0.46
\ No newline at end of file
diff --git a/.golangci.yaml b/.golangci.yaml
index f1a888f08..3d67c8eaf 100644
--- a/.golangci.yaml
+++ b/.golangci.yaml
@@ -43,6 +43,7 @@ linters:
     - perfsprint
     - revive
     - unconvert
+    - makezero
 
 # Settings related to issues
 issues:
diff --git a/.krew.yaml b/.krew.yaml
new file mode 100644
index 000000000..ae711acf8
--- /dev/null
+++ b/.krew.yaml
@@ -0,0 +1,41 @@
+apiVersion: krew.googlecontainertools.github.com/v1alpha2
+kind: Plugin
+metadata:
+  name: kueue
+spec:
+  version: {{ .TagName }}
+  shortDescription: Controls Kueue queueing manager.
+  homepage: https://kueue.sigs.k8s.io/docs/reference/kubectl-kueue/
+  description: |
+    The kubectl-kueue plugin, kueuectl, allows you to list, create, resume
+    and stop kueue resources such as clusterqueues, localqueues and workloads.
+
+    See the documentation for more information: https://kueue.sigs.k8s.io/docs/reference/kubectl-kueue/
+  caveats: |
+    Requires the Kueue operator to be installed:
+      https://kueue.sigs.k8s.io/docs/installation/
+  platforms:
+  - selector:
+      matchLabels:
+        os: "linux"
+        arch: "amd64"
+    {{addURIAndSha "https://github.com/kubernetes-sigs/kueue/releases/download/{{ .TagName }}/kubectl-kueue-linux-amd64.tar.gz" .TagName }}
+    bin: "kubectl-kueue"
+  - selector:
+      matchLabels:
+        os: "linux"
+        arch: "arm64"
+    {{addURIAndSha "https://github.com/kubernetes-sigs/kueue/releases/download/{{ .TagName }}/kubectl-kueue-linux-arm64.tar.gz" .TagName }}
+    bin: "kubectl-kueue"
+  - selector:
+      matchLabels:
+        os: "darwin"
+        arch: "amd64"
+    {{addURIAndSha "https://github.com/kubernetes-sigs/kueue/releases/download/{{ .TagName }}/kubectl-kueue-darwin-amd64.tar.gz" .TagName }}
+    bin: "kubectl-kueue"
+  - selector:
+      matchLabels:
+        os: "darwin"
+        arch: "arm64"
+    {{addURIAndSha "https://github.com/kubernetes-sigs/kueue/releases/download/{{ .TagName }}/kubectl-kueue-darwin-arm64.tar.gz" .TagName }}
+    bin: "kubectl-kueue"
diff --git a/Makefile b/Makefile
index f79f5e678..472055f25 100644
--- a/Makefile
+++ b/Makefile
@@ -31,13 +31,12 @@ CLI_PLATFORMS ?= linux/amd64,linux/arm64,darwin/amd64,darwin/arm64
 DOCKER_BUILDX_CMD ?= docker buildx
 IMAGE_BUILD_CMD ?= $(DOCKER_BUILDX_CMD) build
 IMAGE_BUILD_EXTRA_OPTS ?=
-# TODO(#52): Add kueue to k8s gcr registry
-STAGING_IMAGE_REGISTRY := gcr.io/k8s-staging-kueue
-IMAGE_REGISTRY ?= $(STAGING_IMAGE_REGISTRY)
+STAGING_IMAGE_REGISTRY := us-central1-docker.pkg.dev/k8s-staging-images
+IMAGE_REGISTRY ?= $(STAGING_IMAGE_REGISTRY)/kueue
 IMAGE_NAME := kueue
 IMAGE_REPO ?= $(IMAGE_REGISTRY)/$(IMAGE_NAME)
 IMAGE_TAG ?= $(IMAGE_REPO):$(GIT_TAG)
-HELM_CHART_REPO := $(IMAGE_REGISTRY)/charts
+HELM_CHART_REPO := $(STAGING_IMAGE_REGISTRY)/charts
 
 ifdef EXTRA_TAG
 IMAGE_EXTRA_TAG ?= $(IMAGE_REPO):$(EXTRA_TAG)
@@ -212,7 +211,7 @@ image-push: image-build
 
 .PHONY: helm-chart-push
 helm-chart-push: yq helm
-	EXTRA_TAG="$(EXTRA_TAG)" GIT_TAG="$(GIT_TAG)" HELM_CHART_REPO="$(HELM_CHART_REPO)" IMAGE_REPO="$(IMAGE_REPO)" HELM="$(HELM)" YQ="$(YQ)" ./hack/push-chart.sh
+	EXTRA_TAG="$(EXTRA_TAG)" GIT_TAG="$(GIT_TAG)" IMAGE_REGISTRY="$(IMAGE_REGISTRY)" HELM_CHART_REPO="$(HELM_CHART_REPO)" IMAGE_REPO="$(IMAGE_REPO)" HELM="$(HELM)" YQ="$(YQ)" ./hack/push-chart.sh
 
 # Build an amd64 image that can be used for Kind E2E tests.
 .PHONY: kind-image-build
@@ -226,7 +225,7 @@ ifndef ignore-not-found
   ignore-not-found = false
 endif
 
-clean-manifests = (cd config/components/manager && $(KUSTOMIZE) edit set image controller=gcr.io/k8s-staging-kueue/kueue:$(RELEASE_BRANCH))
+clean-manifests = (cd config/components/manager && $(KUSTOMIZE) edit set image controller=us-central1-docker.pkg.dev/k8s-staging-images/kueue/kueue:$(RELEASE_BRANCH))
 
 .PHONY: install
 install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config.
@@ -277,14 +276,23 @@ artifacts: kustomize yq helm ## Generate release artifacts.
 
 .PHONY: prepare-release-branch
 prepare-release-branch: yq kustomize ## Prepare the release branch with the release version.
-	$(SED) -r 's/v[0-9]+\.[0-9]+\.[0-9]+/$(RELEASE_VERSION)/g' -i README.md -i site/hugo.toml
+	$(SED) -r 's/v[0-9]+\.[0-9]+\.[0-9]+/$(RELEASE_VERSION)/g' -i README.md -i site/hugo.toml -i cmd/experimental/kjobctl/docs/installation.md
 	$(YQ) e '.appVersion = "$(RELEASE_VERSION)"' -i charts/kueue/Chart.yaml
 	@$(call clean-manifests)
 
+.PHONY: update-security-insights
+update-security-insights: yq
+	$(YQ) e '.header.last-updated = "$(shell git log -1 --date=short --format=%cd $(GIT_TAG))"' -i SECURITY-INSIGHTS.yaml
+	$(YQ) e '.header.last-reviewed = "$(shell git log -1 --date=short --format=%cd $(GIT_TAG))"' -i SECURITY-INSIGHTS.yaml
+	$(YQ) e '.header.commit-hash = "$(shell git rev-list -1 $(GIT_TAG))"' -i SECURITY-INSIGHTS.yaml
+	$(YQ) e '.header.project-release = "$(shell echo "$(GIT_TAG)" | $(SED) 's/v//g')"' -i SECURITY-INSIGHTS.yaml
+	$(YQ) e '.distribution-points[0] = "https://github.com/kubernetes-sigs/kueue/releases/download/$(GIT_TAG)/manifests.yaml"' -i SECURITY-INSIGHTS.yaml
+	$(YQ) e '.dependencies.sbom[0].sbom-file = "https://github.com/kubernetes-sigs/kueue/releases/download/$(GIT_TAG)/kueue-$(GIT_TAG).spdx.json"' -i SECURITY-INSIGHTS.yaml
+
 ##@ Debug
 
 # Build an image that can be used with kubectl debug
-# Developers don't need to build this image, as it will be available as gcr.io/k8s-staging-kueue/debug
+# Developers don't need to build this image, as it will be available as us-central1-docker.pkg.dev/k8s-staging-images/kueue/debug
 .PHONY: debug-image-push
 debug-image-push: ## Build and push the debug image to the registry
 	$(IMAGE_BUILD_CMD) -t $(IMAGE_REGISTRY)/debug:$(GIT_TAG) \
@@ -312,7 +320,7 @@ importer-image-build:
 importer-image-push: PUSH=--push
 importer-image-push: importer-image-build
 
-# Build a docker local gcr.io/k8s-staging-kueue/importer image
+# Build a docker local us-central1-docker.pkg.dev/k8s-staging-images/kueue/importer image
 .PHONY: importer-image
 importer-image: PLATFORMS=linux/amd64
 importer-image: PUSH=--load
diff --git a/Makefile-test.mk b/Makefile-test.mk
index a6bc04372..89bb4457f 100644
--- a/Makefile-test.mk
+++ b/Makefile-test.mk
@@ -50,9 +50,8 @@ E2E_K8S_VERSIONS ?= 1.27.13 1.28.9 1.29.4 1.30.0
 KIND_CLUSTER_NAME ?= kind
 
 GIT_TAG ?= $(shell git describe --tags --dirty --always)
-# TODO(#52): Add kueue to k8s gcr registry
-STAGING_IMAGE_REGISTRY := gcr.io/k8s-staging-kueue
-IMAGE_REGISTRY ?= $(STAGING_IMAGE_REGISTRY)
+STAGING_IMAGE_REGISTRY := us-central1-docker.pkg.dev/k8s-staging-images
+IMAGE_REGISTRY ?= $(STAGING_IMAGE_REGISTRY)/kueue
 IMAGE_NAME := kueue
 IMAGE_REPO ?= $(IMAGE_REGISTRY)/$(IMAGE_NAME)
 IMAGE_TAG ?= $(IMAGE_REPO):$(GIT_TAG)
diff --git a/PROJECT b/PROJECT
index b0aa53973..622a84339 100644
--- a/PROJECT
+++ b/PROJECT
@@ -1,3 +1,7 @@
+# Code generated by tool. DO NOT EDIT.
+# This file is used to track the info used to scaffold your project
+# and allow the plugins properly work.
+# More info: https://book.kubebuilder.io/reference/project-config.html
 domain: x-k8s.io
 layout:
 - go.kubebuilder.io/v3
@@ -61,4 +65,12 @@ resources:
   kind: AdmissionCheck
   path: sigs.k8s.io/kueue/apis/kueue/v1beta1
   version: v1beta1
+- api:
+    crdVersion: v1
+    namespaced: true
+  domain: x-k8s.io
+  group: kueue
+  kind: Cohort
+  path: sigs.k8s.io/kueue/apis/kueue/v1alpha1
+  version: v1alpha1
 version: "3"
diff --git a/README.md b/README.md
index 0592b80e3..7c0af440b 100644
--- a/README.md
+++ b/README.md
@@ -36,10 +36,10 @@ Read the [overview](https://kueue.sigs.k8s.io/docs/overview/) to learn more.
   - ✔️ Unit Test [testgrid](https://testgrid.k8s.io/sig-scheduling#periodic-kueue-test-unit-main).
   - ✔️ Integration Test [testgrid](https://testgrid.k8s.io/sig-scheduling#periodic-kueue-test-integration-main)
   - ✔️ E2E Tests for Kubernetes
-    [1.25](https://testgrid.k8s.io/sig-scheduling#periodic-kueue-test-e2e-main-1-25),
-    [1.26](https://testgrid.k8s.io/sig-scheduling#periodic-kueue-test-e2e-main-1-26),
     [1.27](https://testgrid.k8s.io/sig-scheduling#periodic-kueue-test-e2e-main-1-27),
-    [1.28](https://testgrid.k8s.io/sig-scheduling#periodic-kueue-test-e2e-main-1-28)
+    [1.28](https://testgrid.k8s.io/sig-scheduling#periodic-kueue-test-e2e-main-1-28),
+    [1.29](https://testgrid.k8s.io/sig-scheduling#periodic-kueue-test-e2e-main-1-29),
+    [1.30](https://testgrid.k8s.io/sig-scheduling#periodic-kueue-test-e2e-main-1-30) 
     on Kind.
 - ✔️ Scalability verification via [performance tests](https://github.com/kubernetes-sigs/kueue/tree/main/test/performance).
 - ✔️ Monitoring via [metrics](https://kueue.sigs.k8s.io/docs/reference/metrics).
diff --git a/apis/kueue/v1alpha1/cohort_types.go b/apis/kueue/v1alpha1/cohort_types.go
new file mode 100644
index 000000000..1450bd957
--- /dev/null
+++ b/apis/kueue/v1alpha1/cohort_types.go
@@ -0,0 +1,105 @@
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1alpha1
+
+import (
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	kueuebeta "sigs.k8s.io/kueue/apis/kueue/v1beta1"
+)
+
+// CohortSpec defines the desired state of Cohort
+type CohortSpec struct {
+	// Parent references the name of the Cohort's parent, if
+	// any. It satisfies one of three cases:
+	// 1) Unset. This Cohort is the root of its Cohort tree.
+	// 2) References a non-existent Cohort. We use default Cohort (no borrowing/lending limits).
+	// 3) References an existent Cohort.
+	//
+	// If a cycle is created, we disable all members of the
+	// Cohort, including ClusterQueues, until the cycle is
+	// removed.  We prevent further admission while the cycle
+	// exists.
+	//
+	//+kubebuilder:validation:MaxLength=253
+	//+kubebuilder:validation:Pattern="^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$"
+	//
+	Parent string `json:"parent,omitempty"`
+
+	// ResourceGroups describes groupings of Resources and
+	// Flavors.  Each ResourceGroup defines a list of Resources
+	// and a list of Flavors which provide quotas for these
+	// Resources. Each Resource and each Flavor may only form part
+	// of one ResourceGroup.  There may be up to 16 ResourceGroups
+	// within a Cohort.
+	//
+	// BorrowingLimit limits how much members of this Cohort
+	// subtree can borrow from the parent subtree.
+	//
+	// LendingLimit limits how much members of this Cohort subtree
+	// can lend to the parent subtree.
+	//
+	// Borrowing and Lending limits must only be set when the
+	// Cohort has a parent.  Otherwise, the Cohort create/update
+	// will be rejected by the webhook.
+	//
+	//+listType=atomic
+	//+kubebuilder:validation:MaxItems=16
+	ResourceGroups []kueuebeta.ResourceGroup `json:"resourceGroups,omitempty"`
+}
+
+const (
+	// Condition indicating that a Cohort is correctly configured,
+	// for example, there is no cycle.
+	CohortActive = "Active"
+)
+
+// CohortStatus defines the observed state of Cohort
+type CohortStatus struct {
+
+	//+listType=map
+	//+listMapKey=type
+	//+patchStrategy=merge
+	//+patchMergeKey=type
+	Conditions []metav1.Condition `json:"conditions,omitempty"`
+}
+
+//+kubebuilder:object:root=true
+//+kubebuilder:subresource:status
+//+kubebuilder:resource:scope=Cluster
+
+// Cohort is the Schema for the cohorts API
+type Cohort struct {
+	metav1.TypeMeta   `json:",inline"`
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	Spec   CohortSpec   `json:"spec,omitempty"`
+	Status CohortStatus `json:"status,omitempty"`
+}
+
+//+kubebuilder:object:root=true
+
+// CohortList contains a list of Cohort
+type CohortList struct {
+	metav1.TypeMeta `json:",inline"`
+	metav1.ListMeta `json:"metadata,omitempty"`
+	Items           []Cohort `json:"items"`
+}
+
+func init() {
+	SchemeBuilder.Register(&Cohort{}, &CohortList{})
+}
diff --git a/apis/kueue/v1alpha1/zz_generated.deepcopy.go b/apis/kueue/v1alpha1/zz_generated.deepcopy.go
index 61cdc5618..7bce77a1e 100644
--- a/apis/kueue/v1alpha1/zz_generated.deepcopy.go
+++ b/apis/kueue/v1alpha1/zz_generated.deepcopy.go
@@ -23,8 +23,112 @@ package v1alpha1
 import (
 	"k8s.io/apimachinery/pkg/apis/meta/v1"
 	runtime "k8s.io/apimachinery/pkg/runtime"
+	"sigs.k8s.io/kueue/apis/kueue/v1beta1"
 )
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Cohort) DeepCopyInto(out *Cohort) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+	in.Spec.DeepCopyInto(&out.Spec)
+	in.Status.DeepCopyInto(&out.Status)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Cohort.
+func (in *Cohort) DeepCopy() *Cohort {
+	if in == nil {
+		return nil
+	}
+	out := new(Cohort)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *Cohort) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *CohortList) DeepCopyInto(out *CohortList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]Cohort, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CohortList.
+func (in *CohortList) DeepCopy() *CohortList {
+	if in == nil {
+		return nil
+	}
+	out := new(CohortList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *CohortList) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *CohortSpec) DeepCopyInto(out *CohortSpec) {
+	*out = *in
+	if in.ResourceGroups != nil {
+		in, out := &in.ResourceGroups, &out.ResourceGroups
+		*out = make([]v1beta1.ResourceGroup, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CohortSpec.
+func (in *CohortSpec) DeepCopy() *CohortSpec {
+	if in == nil {
+		return nil
+	}
+	out := new(CohortSpec)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *CohortStatus) DeepCopyInto(out *CohortStatus) {
+	*out = *in
+	if in.Conditions != nil {
+		in, out := &in.Conditions, &out.Conditions
+		*out = make([]v1.Condition, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CohortStatus.
+func (in *CohortStatus) DeepCopy() *CohortStatus {
+	if in == nil {
+		return nil
+	}
+	out := new(CohortStatus)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *KubeConfig) DeepCopyInto(out *KubeConfig) {
 	*out = *in
diff --git a/charts/kueue/README.md b/charts/kueue/README.md
index 0f5109a27..1c5645c8a 100644
--- a/charts/kueue/README.md
+++ b/charts/kueue/README.md
@@ -49,7 +49,7 @@ The following table lists the configurable parameters of the kueue chart and the
 | `enablePrometheus`                                     | enable Prometheus                                      | `false`                                     |
 | `enableCertManager`                                    | enable CertManager                                     | `false`                                     |
 | `controllerManager.kubeRbacProxy.image`                | controllerManager.kubeRbacProxy's image                | `gcr.io/kubebuilder/kube-rbac-proxy:v0.8.0` |
-| `controllerManager.manager.image`                      | controllerManager.manager's image                      | `gcr.io/k8s-staging-kueue/kueue:main`       |
+| `controllerManager.manager.image`                      | controllerManager.manager's image                      | `us-central1-docker.pkg.dev/k8s-staging-images/kueue/kueue:main`       |
 | `controllerManager.manager.resources`                  | controllerManager.manager's resources                  | abbr.                                       |
 | `controllerManager.replicas`                           | ControllerManager's replicaCount                       | `1`                                         |
 | `controllerManager.imagePullSecrets`                   | ControllerManager's imagePullSecrets                   | `[]`                                        |
diff --git a/charts/kueue/templates/manager/manager.yaml b/charts/kueue/templates/manager/manager.yaml
index f1e673b03..042168608 100644
--- a/charts/kueue/templates/manager/manager.yaml
+++ b/charts/kueue/templates/manager/manager.yaml
@@ -56,8 +56,8 @@ spec:
           timeoutSeconds: {{ .Values.controllerManager.readinessProbe.timeoutSeconds }}
           failureThreshold: {{ .Values.controllerManager.readinessProbe.failureThreshold }}
           successThreshold: {{ .Values.controllerManager.readinessProbe.successThreshold }}
-        resources: {{- toYaml .Values.controllerManager.manager.resources | nindent 10
-          }}
+        resources:
+          {{- toYaml .Values.controllerManager.manager.resources | nindent 10 }}
         securityContext:
           {{- toYaml .Values.controllerManager.manager.containerSecurityContext | nindent 10 }}
         volumeMounts:
diff --git a/charts/kueue/values.yaml b/charts/kueue/values.yaml
index 0a744e19e..0fa2ef3f9 100644
--- a/charts/kueue/values.yaml
+++ b/charts/kueue/values.yaml
@@ -21,7 +21,7 @@ controllerManager:
       pullPolicy: IfNotPresent
   manager:
     image:
-      repository: gcr.io/k8s-staging-kueue/kueue
+      repository: us-central1-docker.pkg.dev/k8s-staging-images/kueue/kueue
       # This should be set to 'IfNotPresent' for released version      
       pullPolicy: Always
     podAnnotations: {}
diff --git a/cloudbuild.yaml b/cloudbuild.yaml
index 7f050cda1..52dc2b9f3 100644
--- a/cloudbuild.yaml
+++ b/cloudbuild.yaml
@@ -12,7 +12,7 @@ steps:
       - importer-image-push
       - helm-chart-push
     env:
-      - IMAGE_REGISTRY=gcr.io/$PROJECT_ID
+      - IMAGE_REGISTRY=us-central1-docker.pkg.dev/k8s-staging-images/kueue
       - GIT_TAG=$_GIT_TAG
       - EXTRA_TAG=$_PULL_BASE_REF
       - DOCKER_BUILDX_CMD=/buildx-entrypoint
diff --git a/cmd/experimental/kjobctl/Makefile b/cmd/experimental/kjobctl/Makefile
index 3bfa8dd41..34c842cdf 100644
--- a/cmd/experimental/kjobctl/Makefile
+++ b/cmd/experimental/kjobctl/Makefile
@@ -56,8 +56,8 @@ generate: gomod-download controller-gen ## Generate code containing DeepCopy, De
 	TOOLS_DIR=${TOOLS_DIR} ./hack/update-codegen.sh $(GO_CMD)
 
 .PHONY: verify
-verify: gomod-verify ci-lint fmt-verify manifests generate
-	git --no-pager diff --exit-code config/crd apis client-go
+verify: gomod-verify ci-lint fmt-verify manifests generate generate-kjobctl-docs
+	git --no-pager diff --exit-code config/crd apis client-go docs
 
 .PHONY: gomod-verify
 gomod-verify:
@@ -85,10 +85,14 @@ vet: ## Run go vet against code.
 	$(GO_CMD) vet ./...
 
 .PHONY: test
-test: verify gotestsum gomod-download vet envtest ginkgo ## Run tests.
-	# Unit tests
+test: verify vet test-unit test-integration ## Run all tests.
+
+.PHONY: test-unit
+test-unit: gomod-download gotestsum ## Run unit tests.
 	$(GOTESTSUM) --junitfile $(ARTIFACTS)/junit-unit.xml -- $(GO_TEST_FLAGS) $(shell $(GO_CMD) list ./... | grep -v '/test/') -coverpkg=./... -coverprofile $(ARTIFACTS)/cover.out
-	# Integration tests
+
+.PHONY: test-integration
+test-integration: gomod-download envtest ginkgo ## Run integration tests.
 	KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" \
 	KUEUE_BIN=$(PROJECT_DIR)/bin \
 	ENVTEST_K8S_VERSION=$(ENVTEST_K8S_VERSION) \
@@ -120,6 +124,19 @@ uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified
 kubectl-kjob: ## Build kubectl-kjob binary file to bin directory.
 	$(GO_BUILD_ENV) $(GO_CMD) build -ldflags="$(LD_FLAGS)" -o bin/kubectl-kjob cmd/main.go
 
+.PHONY: kjobctl-docs
+kjobctl-docs: ## Build kjobctl-docs binary file to bin directory.
+	cd $(PROJECT_DIR)/hack/tools && \
+	go mod download && \
+	$(GO_BUILD_ENV) $(GO_CMD) build -ldflags="$(LD_FLAGS)" -o $(PROJECT_DIR)/bin/kjobctl-docs ./kjobctl-docs/main.go
+
+.PHONY: generate-kjobctl-docs
+generate-kjobctl-docs: kjobctl-docs ## Generate kjobctl docs.
+	rm -Rf $(PROJECT_DIR)/docs/commands/*
+	$(PROJECT_DIR)/bin/kjobctl-docs \
+		$(PROJECT_DIR)/hack/tools/kjobctl-docs/templates \
+		$(PROJECT_DIR)/docs/commands
+
 ##@ Dependencies
 
 ## Location to install dependencies to
diff --git a/cmd/experimental/kjobctl/README.md b/cmd/experimental/kjobctl/README.md
index da7dd481d..59ae29696 100644
--- a/cmd/experimental/kjobctl/README.md
+++ b/cmd/experimental/kjobctl/README.md
@@ -2,12 +2,14 @@
 ML/AI/Batch Jobs Made Easy
 
 ## Description
-// TODO(user): An in-depth paragraph about your project and overview of use
+The `kubectl-kjob` plugin, `kjobctl`, allows you to list, describe and create jobs.
+
+Read the [overview](docs/_index.md) to learn more.
 
 ## Getting Started
 
 ### Prerequisites
-- go version v1.22.3+
+- go version v1.22.4+
 - kubectl version v1.27+.
 - Access to a Kubernetes v1.27+ cluster.
 
diff --git a/cmd/experimental/kjobctl/config/samples/application_profile.yaml b/cmd/experimental/kjobctl/config/samples/application_profile.yaml
index 3fec9a0b0..de0a27ecb 100644
--- a/cmd/experimental/kjobctl/config/samples/application_profile.yaml
+++ b/cmd/experimental/kjobctl/config/samples/application_profile.yaml
@@ -8,7 +8,7 @@ spec:
   supportedModes:
     - name: Interactive
       template: sample-pod-template
-      requiredFlags: ["cmd"]
+      requiredFlags: []
     - name: Job
       template: sample-job-template
       requiredFlags: ["cmd"]
@@ -22,12 +22,8 @@ template:
   spec:
     containers:
       - name: sample-container
-        image: gcr.io/k8s-staging-perf-tests/sleep:v0.1.0
-        args: [ "30s" ]
-        resources:
-          requests:
-            cpu: "1"
-            memory: "200Mi"
+        image: busybox:1.28
+        command: ['/bin/sh']
 ---
 apiVersion: kjobctl.x-k8s.io/v1alpha1
 kind: JobTemplate
diff --git a/cmd/experimental/kjobctl/docs/_index.md b/cmd/experimental/kjobctl/docs/_index.md
new file mode 100644
index 000000000..b45f99827
--- /dev/null
+++ b/cmd/experimental/kjobctl/docs/_index.md
@@ -0,0 +1,24 @@
+# Kubectl Kjob Plugin
+
+The `kubectl-kjob` plugin, `kjobctl`, allows you to list, describe and create jobs.
+
+## Syntax
+
+Use the following syntax to run `kubectl kjob` commands from your terminal window:
+
+```shell
+kubectl kjob [OPERATION] [TYPE] [NAME] [flags]
+```
+
+or with shorter syntax `kjobctl`:
+
+```shell
+kjobctl [OPERATION] [TYPE] [NAME] [flags]
+```
+
+You can go to the [commands](commands/_index.md) or run `kubectl kjob help` in the terminal to get the full list of commands, along with all possible flags.
+
+## See Also
+
+* [installation](installation.md)	 - Installation guide for the `kubectl-kjob` plugin, `kjobctl`.
+* [commands](commands/kjobctl.md)	 - Full list of commands, along with all possible flags.
\ No newline at end of file
diff --git a/cmd/experimental/kjobctl/docs/commands/kjobctl.md b/cmd/experimental/kjobctl/docs/commands/kjobctl.md
new file mode 100644
index 000000000..e56273429
--- /dev/null
+++ b/cmd/experimental/kjobctl/docs/commands/kjobctl.md
@@ -0,0 +1,204 @@
+<!--
+The file is auto-generated from the Go source code of the component using the
+[generator](https://github.com/kubernetes-sigs/kueue/tree/main/cmd/experimental/kjobctl/hack/tools/kjobctl-docs).
+-->
+
+# kjobctl
+
+
+## Synopsis
+
+
+ML/AI/Batch Jobs Made Easy
+
+
+## Options
+
+
+<table style="width: 100%; table-layout: fixed;">
+    <colgroup>
+        <col span="1" style="width: 10px;" />
+        <col span="1" />
+    </colgroup>
+    <tbody>
+    <tr>
+        <td colspan="2">--as string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Username to impersonate for the operation. User could be a regular user or a service account in a namespace.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--as-group strings</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Group to impersonate for the operation, this flag can be repeated to specify multiple groups.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--as-uid string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>UID to impersonate for the operation.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--cache-dir string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default: &#34;$HOME/.kube/cache&#34;</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Default cache directory</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--certificate-authority string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Path to a cert file for the certificate authority</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--client-certificate string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Path to a client certificate file for TLS</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--client-key string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Path to a client key file for TLS</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--cluster string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The name of the kubeconfig cluster to use</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--context string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The name of the kubeconfig context to use</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--disable-compression</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If true, opt-out of response compression for all requests to the server</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">-h, --help</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>help for kjobctl</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--insecure-skip-tls-verify</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If true, the server&#39;s certificate will not be checked for validity. This will make your HTTPS connections insecure</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--kubeconfig string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Path to the kubeconfig file to use for CLI requests.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">-n, --namespace string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If present, the namespace scope for this CLI request</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--request-timeout string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default: &#34;0&#34;</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don&#39;t timeout requests.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">-s, --server string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The address and port of the Kubernetes API server</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--tls-server-name string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--token string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Bearer token for authentication to the API server</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--user string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The name of the kubeconfig user to use</p>
+        </td>
+    </tr>
+    </tbody>
+</table>
+
+
+
+## See Also
+
+* [kjobctl create](kjobctl_create/_index.md)	 - Create a task
+* [kjobctl list](kjobctl_list/_index.md)	 - Display resources
+
diff --git a/cmd/experimental/kjobctl/docs/commands/kjobctl_create/_index.md b/cmd/experimental/kjobctl/docs/commands/kjobctl_create/_index.md
new file mode 100644
index 000000000..668abf0c1
--- /dev/null
+++ b/cmd/experimental/kjobctl/docs/commands/kjobctl_create/_index.md
@@ -0,0 +1,237 @@
+<!--
+The file is auto-generated from the Go source code of the component using the
+[generator](https://github.com/kubernetes-sigs/kueue/tree/main/cmd/experimental/kjobctl/hack/tools/kjobctl-docs).
+-->
+
+# kjobctl create
+
+
+## Synopsis
+
+
+Create a task
+
+
+## Examples
+
+```
+  # Create job 
+  kjobctl create job \ 
+	--profile my-application-profile  \
+	--cmd &#34;sleep 5&#34; \
+	--parallelism 4 \
+	--completions 4 \ 
+	--request cpu=500m,ram=4Gi \
+	--localqueue my-local-queue-name
+
+  # Create interactive 
+  kjobctl create interactive \ 
+	--profile my-application-profile  \
+	--pod-running-timeout 30s \
+	--rm
+```
+
+
+## Options
+
+
+<table style="width: 100%; table-layout: fixed;">
+    <colgroup>
+        <col span="1" style="width: 10px;" />
+        <col span="1" />
+    </colgroup>
+    <tbody>
+    <tr>
+        <td colspan="2">-h, --help</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>help for create</p>
+        </td>
+    </tr>
+    </tbody>
+</table>
+
+
+
+## Options inherited from parent commands
+<table style="width: 100%; table-layout: fixed;">
+    <colgroup>
+        <col span="1" style="width: 10px;" />
+        <col span="1" />
+    </colgroup>
+    <tbody>
+    <tr>
+        <td colspan="2">--as string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Username to impersonate for the operation. User could be a regular user or a service account in a namespace.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--as-group strings</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Group to impersonate for the operation, this flag can be repeated to specify multiple groups.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--as-uid string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>UID to impersonate for the operation.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--cache-dir string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default: &#34;$HOME/.kube/cache&#34;</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Default cache directory</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--certificate-authority string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Path to a cert file for the certificate authority</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--client-certificate string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Path to a client certificate file for TLS</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--client-key string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Path to a client key file for TLS</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--cluster string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The name of the kubeconfig cluster to use</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--context string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The name of the kubeconfig context to use</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--disable-compression</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If true, opt-out of response compression for all requests to the server</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--insecure-skip-tls-verify</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If true, the server&#39;s certificate will not be checked for validity. This will make your HTTPS connections insecure</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--kubeconfig string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Path to the kubeconfig file to use for CLI requests.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">-n, --namespace string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If present, the namespace scope for this CLI request</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--request-timeout string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default: &#34;0&#34;</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don&#39;t timeout requests.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">-s, --server string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The address and port of the Kubernetes API server</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--tls-server-name string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--token string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Bearer token for authentication to the API server</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--user string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The name of the kubeconfig user to use</p>
+        </td>
+    </tr>
+    </tbody>
+</table>
+
+
+
+## See Also
+
+* [kjobctl](../kjobctl.md)	 - ML/AI/Batch Jobs Made Easy
+* [kjobctl create interactive](kjobctl_create_interactive.md)	 - Create an interactive shell
+* [kjobctl create job](kjobctl_create_job.md)	 - Create a job
+
diff --git a/cmd/experimental/kjobctl/docs/commands/kjobctl_create/kjobctl_create_interactive.md b/cmd/experimental/kjobctl/docs/commands/kjobctl_create/kjobctl_create_interactive.md
new file mode 100644
index 000000000..d0e91e0b1
--- /dev/null
+++ b/cmd/experimental/kjobctl/docs/commands/kjobctl_create/kjobctl_create_interactive.md
@@ -0,0 +1,329 @@
+<!--
+The file is auto-generated from the Go source code of the component using the
+[generator](https://github.com/kubernetes-sigs/kueue/tree/main/cmd/experimental/kjobctl/hack/tools/kjobctl-docs).
+-->
+
+# kjobctl create interactive
+
+
+## Synopsis
+
+
+Create an interactive shell
+
+```
+kjobctl create interactive --profile APPLICATION_PROFILE_NAME [--cmd COMMAND] [--request RESOURCE_NAME=QUANTITY] [--localqueue LOCAL_QUEUE_NAME] [--pod-running-timeout DURATION] [--rm]
+```
+
+
+## Examples
+
+```
+  # Create interactive 
+  kjobctl create interactive \ 
+	--profile my-application-profile  \
+	--pod-running-timeout 30s \
+	--rm
+```
+
+
+## Options
+
+
+<table style="width: 100%; table-layout: fixed;">
+    <colgroup>
+        <col span="1" style="width: 10px;" />
+        <col span="1" />
+    </colgroup>
+    <tbody>
+    <tr>
+        <td colspan="2">--allow-missing-template-keys&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default: true</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--cmd string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Command which is associated with the resource.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--dry-run string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default: &#34;none&#34;</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Must be &#34;none&#34;, &#34;server&#34;, or &#34;client&#34;. If client strategy, only print the object that would be sent, without sending it. If server strategy, submit server-side request without persisting the resource.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">-h, --help</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>help for interactive</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--localqueue string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Kueue localqueue name which is associated with the resource.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">-o, --output string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Output format. One of: (json, yaml, name, go-template, go-template-file, template, templatefile, jsonpath, jsonpath-as-json, jsonpath-file).</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--pod-running-timeout duration&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default: 1m0s</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The length of time (like 5s, 2m, or 3h, higher than zero) to wait until at least one pod is running.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">-p, --profile string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Application profile contains a template (with defaults set) for running a specific type of application.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--request &lt;comma-separated &#39;key=value&#39; pairs&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default: []</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Request is a set of (resource name, quantity) pairs.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--rm</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Remove pod when interactive session exits.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--show-managed-fields</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If true, keep the managedFields when printing objects in JSON or YAML format.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--template string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].</p>
+        </td>
+    </tr>
+    </tbody>
+</table>
+
+
+
+## Options inherited from parent commands
+<table style="width: 100%; table-layout: fixed;">
+    <colgroup>
+        <col span="1" style="width: 10px;" />
+        <col span="1" />
+    </colgroup>
+    <tbody>
+    <tr>
+        <td colspan="2">--as string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Username to impersonate for the operation. User could be a regular user or a service account in a namespace.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--as-group strings</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Group to impersonate for the operation, this flag can be repeated to specify multiple groups.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--as-uid string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>UID to impersonate for the operation.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--cache-dir string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default: &#34;$HOME/.kube/cache&#34;</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Default cache directory</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--certificate-authority string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Path to a cert file for the certificate authority</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--client-certificate string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Path to a client certificate file for TLS</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--client-key string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Path to a client key file for TLS</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--cluster string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The name of the kubeconfig cluster to use</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--context string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The name of the kubeconfig context to use</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--disable-compression</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If true, opt-out of response compression for all requests to the server</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--insecure-skip-tls-verify</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If true, the server&#39;s certificate will not be checked for validity. This will make your HTTPS connections insecure</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--kubeconfig string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Path to the kubeconfig file to use for CLI requests.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">-n, --namespace string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If present, the namespace scope for this CLI request</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--request-timeout string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default: &#34;0&#34;</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don&#39;t timeout requests.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">-s, --server string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The address and port of the Kubernetes API server</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--tls-server-name string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--token string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Bearer token for authentication to the API server</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--user string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The name of the kubeconfig user to use</p>
+        </td>
+    </tr>
+    </tbody>
+</table>
+
+
+
+## See Also
+
+* [kjobctl_create](_index.md)	 - Create a task
+
diff --git a/cmd/experimental/kjobctl/docs/commands/kjobctl_create/kjobctl_create_job.md b/cmd/experimental/kjobctl/docs/commands/kjobctl_create/kjobctl_create_job.md
new file mode 100644
index 000000000..09c958de7
--- /dev/null
+++ b/cmd/experimental/kjobctl/docs/commands/kjobctl_create/kjobctl_create_job.md
@@ -0,0 +1,332 @@
+<!--
+The file is auto-generated from the Go source code of the component using the
+[generator](https://github.com/kubernetes-sigs/kueue/tree/main/cmd/experimental/kjobctl/hack/tools/kjobctl-docs).
+-->
+
+# kjobctl create job
+
+
+## Synopsis
+
+
+Create a job
+
+```
+kjobctl create job --profile APPLICATION_PROFILE_NAME [--cmd COMMAND] [--request RESOURCE_NAME=QUANTITY] [--localqueue LOCAL_QUEUE_NAME] [--parallelism PARALLELISM] [--completions COMPLETIONS]
+```
+
+
+## Examples
+
+```
+  # Create job 
+  kjobctl create job \ 
+	--profile my-application-profile  \
+	--cmd &#34;sleep 5&#34; \
+	--parallelism 4 \
+	--completions 4 \ 
+	--request cpu=500m,ram=4Gi \
+	--localqueue my-local-queue-name
+```
+
+
+## Options
+
+
+<table style="width: 100%; table-layout: fixed;">
+    <colgroup>
+        <col span="1" style="width: 10px;" />
+        <col span="1" />
+    </colgroup>
+    <tbody>
+    <tr>
+        <td colspan="2">--allow-missing-template-keys&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default: true</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--cmd string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Command which is associated with the resource.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--completions int</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Completions specifies the desired number of successfully finished pods.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--dry-run string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default: &#34;none&#34;</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Must be &#34;none&#34;, &#34;server&#34;, or &#34;client&#34;. If client strategy, only print the object that would be sent, without sending it. If server strategy, submit server-side request without persisting the resource.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">-h, --help</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>help for job</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--localqueue string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Kueue localqueue name which is associated with the resource.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">-o, --output string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Output format. One of: (json, yaml, name, go-template, go-template-file, template, templatefile, jsonpath, jsonpath-as-json, jsonpath-file).</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--parallelism int</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Parallelism specifies the maximum desired number of pods the job should run at any given time.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">-p, --profile string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Application profile contains a template (with defaults set) for running a specific type of application.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--request &lt;comma-separated &#39;key=value&#39; pairs&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default: []</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Request is a set of (resource name, quantity) pairs.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--show-managed-fields</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If true, keep the managedFields when printing objects in JSON or YAML format.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--template string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].</p>
+        </td>
+    </tr>
+    </tbody>
+</table>
+
+
+
+## Options inherited from parent commands
+<table style="width: 100%; table-layout: fixed;">
+    <colgroup>
+        <col span="1" style="width: 10px;" />
+        <col span="1" />
+    </colgroup>
+    <tbody>
+    <tr>
+        <td colspan="2">--as string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Username to impersonate for the operation. User could be a regular user or a service account in a namespace.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--as-group strings</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Group to impersonate for the operation, this flag can be repeated to specify multiple groups.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--as-uid string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>UID to impersonate for the operation.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--cache-dir string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default: &#34;$HOME/.kube/cache&#34;</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Default cache directory</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--certificate-authority string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Path to a cert file for the certificate authority</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--client-certificate string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Path to a client certificate file for TLS</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--client-key string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Path to a client key file for TLS</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--cluster string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The name of the kubeconfig cluster to use</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--context string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The name of the kubeconfig context to use</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--disable-compression</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If true, opt-out of response compression for all requests to the server</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--insecure-skip-tls-verify</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If true, the server&#39;s certificate will not be checked for validity. This will make your HTTPS connections insecure</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--kubeconfig string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Path to the kubeconfig file to use for CLI requests.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">-n, --namespace string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If present, the namespace scope for this CLI request</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--request-timeout string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default: &#34;0&#34;</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don&#39;t timeout requests.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">-s, --server string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The address and port of the Kubernetes API server</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--tls-server-name string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--token string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Bearer token for authentication to the API server</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--user string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The name of the kubeconfig user to use</p>
+        </td>
+    </tr>
+    </tbody>
+</table>
+
+
+
+## See Also
+
+* [kjobctl_create](_index.md)	 - Create a task
+
diff --git a/cmd/experimental/kjobctl/docs/commands/kjobctl_list/_index.md b/cmd/experimental/kjobctl/docs/commands/kjobctl_list/_index.md
new file mode 100644
index 000000000..a14816958
--- /dev/null
+++ b/cmd/experimental/kjobctl/docs/commands/kjobctl_list/_index.md
@@ -0,0 +1,224 @@
+<!--
+The file is auto-generated from the Go source code of the component using the
+[generator](https://github.com/kubernetes-sigs/kueue/tree/main/cmd/experimental/kjobctl/hack/tools/kjobctl-docs).
+-->
+
+# kjobctl list
+
+
+## Synopsis
+
+
+Display resources
+
+
+## Examples
+
+```
+  # List Job 
+  kjobctl list job
+```
+
+
+## Options
+
+
+<table style="width: 100%; table-layout: fixed;">
+    <colgroup>
+        <col span="1" style="width: 10px;" />
+        <col span="1" />
+    </colgroup>
+    <tbody>
+    <tr>
+        <td colspan="2">-h, --help</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>help for list</p>
+        </td>
+    </tr>
+    </tbody>
+</table>
+
+
+
+## Options inherited from parent commands
+<table style="width: 100%; table-layout: fixed;">
+    <colgroup>
+        <col span="1" style="width: 10px;" />
+        <col span="1" />
+    </colgroup>
+    <tbody>
+    <tr>
+        <td colspan="2">--as string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Username to impersonate for the operation. User could be a regular user or a service account in a namespace.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--as-group strings</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Group to impersonate for the operation, this flag can be repeated to specify multiple groups.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--as-uid string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>UID to impersonate for the operation.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--cache-dir string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default: &#34;$HOME/.kube/cache&#34;</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Default cache directory</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--certificate-authority string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Path to a cert file for the certificate authority</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--client-certificate string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Path to a client certificate file for TLS</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--client-key string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Path to a client key file for TLS</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--cluster string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The name of the kubeconfig cluster to use</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--context string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The name of the kubeconfig context to use</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--disable-compression</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If true, opt-out of response compression for all requests to the server</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--insecure-skip-tls-verify</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If true, the server&#39;s certificate will not be checked for validity. This will make your HTTPS connections insecure</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--kubeconfig string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Path to the kubeconfig file to use for CLI requests.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">-n, --namespace string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If present, the namespace scope for this CLI request</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--request-timeout string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default: &#34;0&#34;</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don&#39;t timeout requests.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">-s, --server string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The address and port of the Kubernetes API server</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--tls-server-name string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--token string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Bearer token for authentication to the API server</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--user string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The name of the kubeconfig user to use</p>
+        </td>
+    </tr>
+    </tbody>
+</table>
+
+
+
+## See Also
+
+* [kjobctl](../kjobctl.md)	 - ML/AI/Batch Jobs Made Easy
+* [kjobctl list job](kjobctl_list_job.md)	 - List Job
+
diff --git a/cmd/experimental/kjobctl/docs/commands/kjobctl_list/kjobctl_list_job.md b/cmd/experimental/kjobctl/docs/commands/kjobctl_list/kjobctl_list_job.md
new file mode 100644
index 000000000..d257bbe10
--- /dev/null
+++ b/cmd/experimental/kjobctl/docs/commands/kjobctl_list/kjobctl_list_job.md
@@ -0,0 +1,299 @@
+<!--
+The file is auto-generated from the Go source code of the component using the
+[generator](https://github.com/kubernetes-sigs/kueue/tree/main/cmd/experimental/kjobctl/hack/tools/kjobctl-docs).
+-->
+
+# kjobctl list job
+
+
+## Synopsis
+
+
+List Job
+
+```
+kjobctl list job [--selector key1=value1] [--field-selector key1=value1] [--all-namespaces]
+```
+
+
+## Examples
+
+```
+  # List Job
+  kjobctl list job
+```
+
+
+## Options
+
+
+<table style="width: 100%; table-layout: fixed;">
+    <colgroup>
+        <col span="1" style="width: 10px;" />
+        <col span="1" />
+    </colgroup>
+    <tbody>
+    <tr>
+        <td colspan="2">-A, --all-namespaces</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--allow-missing-template-keys&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default: true</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--field-selector string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Selector (field query) to filter on, supports &#39;=&#39;, &#39;==&#39;, and &#39;!=&#39;.(e.g. --field-selector key1=value1,key2=value2). The server only supports a limited number of field queries per type.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">-h, --help</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>help for job</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">-o, --output string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Output format. One of: (json, yaml, name, go-template, go-template-file, template, templatefile, jsonpath, jsonpath-as-json, jsonpath-file).</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">-p, --profile string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Filter by profile name which is associated with the resource.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">-l, --selector string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Selector (label query) to filter on, supports &#39;=&#39;, &#39;==&#39;, and &#39;!=&#39;.(e.g. -l key1=value1,key2=value2). Matching objects must satisfy all of the specified label constraints.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--show-managed-fields</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If true, keep the managedFields when printing objects in JSON or YAML format.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--template string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].</p>
+        </td>
+    </tr>
+    </tbody>
+</table>
+
+
+
+## Options inherited from parent commands
+<table style="width: 100%; table-layout: fixed;">
+    <colgroup>
+        <col span="1" style="width: 10px;" />
+        <col span="1" />
+    </colgroup>
+    <tbody>
+    <tr>
+        <td colspan="2">--as string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Username to impersonate for the operation. User could be a regular user or a service account in a namespace.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--as-group strings</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Group to impersonate for the operation, this flag can be repeated to specify multiple groups.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--as-uid string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>UID to impersonate for the operation.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--cache-dir string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default: &#34;$HOME/.kube/cache&#34;</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Default cache directory</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--certificate-authority string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Path to a cert file for the certificate authority</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--client-certificate string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Path to a client certificate file for TLS</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--client-key string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Path to a client key file for TLS</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--cluster string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The name of the kubeconfig cluster to use</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--context string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The name of the kubeconfig context to use</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--disable-compression</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If true, opt-out of response compression for all requests to the server</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--insecure-skip-tls-verify</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If true, the server&#39;s certificate will not be checked for validity. This will make your HTTPS connections insecure</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--kubeconfig string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Path to the kubeconfig file to use for CLI requests.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">-n, --namespace string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>If present, the namespace scope for this CLI request</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--request-timeout string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default: &#34;0&#34;</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don&#39;t timeout requests.</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">-s, --server string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The address and port of the Kubernetes API server</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--tls-server-name string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--token string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>Bearer token for authentication to the API server</p>
+        </td>
+    </tr>
+    <tr>
+        <td colspan="2">--user string</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>The name of the kubeconfig user to use</p>
+        </td>
+    </tr>
+    </tbody>
+</table>
+
+
+
+## See Also
+
+* [kjobctl_list](_index.md)	 - Display resources
+
diff --git a/cmd/experimental/kjobctl/docs/installation.md b/cmd/experimental/kjobctl/docs/installation.md
new file mode 100644
index 000000000..375321d51
--- /dev/null
+++ b/cmd/experimental/kjobctl/docs/installation.md
@@ -0,0 +1,81 @@
+# Installation
+
+Installing the `kubectl-kjob` plugin, `kjobctl`.
+
+## Installing From Release Binaries
+
+### 1. Install Kubernetes CRDs
+
+```shell
+kubectl apply --server-side -f https://github.com/kubernetes-sigs/kueue/releases/download/v0.8.0/kubectl-kjob-manifests.yaml
+```
+
+### 2. Download the latest release:
+
+On Linux:
+```shell
+# For AMD64 / x86_64
+[ $(uname -m) = x86_64 ] && curl -Lo ./kubectl-kjob https://github.com/kubernetes-sigs/kjob/releases/download/v0.8.0/kubectl-kjob-linux-amd64
+# For ARM64
+[ $(uname -m) = aarch64 ] && curl -Lo ./kubectl-kjob https://github.com/kubernetes-sigs/kjob/releases/download/v0.8.0/kubectl-kjob-linux-arm64
+```
+
+On Mac:
+```shell
+# For Intel Macs
+[ $(uname -m) = x86_64 ] && curl -Lo ./kubectl-kjob https://github.com/kubernetes-sigs/kjob/releases/download/v0.8.0/kubectl-kjob-darwin-amd64
+# For M1 / ARM Macs
+[ $(uname -m) = arm64 ] && curl -Lo ./kubectl-kjob https://github.com/kubernetes-sigs/kjob/releases/download/v0.8.0/kubectl-kjob-darwin-arm64
+```
+
+### 3. Make the kubectl-kjob binary executable.
+
+```shell
+chmod +x ./kubectl-kjob
+```
+
+### 4. Move the kubectl binary to a file location on your system PATH.
+
+```shell
+sudo mv ./kubectl-kjob /usr/local/bin/kubectl-kjob
+```
+
+## Installing From Source
+
+```bash
+make kubectl-kjob
+sudo mv ./bin/kubectl-kjob /usr/local/bin/kubectl-kjob
+```
+
+## Kjobctl
+
+Additionally, you can create an alias `kjobctl` to allow shorter syntax.
+
+```bash
+echo 'alias kjobctl="kubectl kjob"' >> ~/.bashrc
+# Or if you are using ZSH
+echo 'alias kjobctl="kubectl kjob"' >> ~/.zshrc
+```
+
+## Autocompletion
+
+```bash
+echo '[[ $commands[kubectl-kjob] ]] && source <(kubectl-kjob completion bash)' >> ~/.bashrc
+# Or if you are using ZSH
+echo '[[ $commands[kubectl-kjob] ]] && source <(kubectl-kjob completion zsh)' >> ~/.zshrc
+
+cat <<EOF >kubectl_complete-kjob
+#!/usr/bin/env sh
+
+# Call the __complete command passing it all arguments
+kubectl kjob __complete "\$@"
+EOF
+
+chmod u+x kubectl_complete-kjob
+sudo mv kubectl_complete-kjob /usr/local/bin/kubectl_complete-kjob
+```
+
+## See Also
+
+* [overview](_index.md)	 - `kubectl-kjob` plugin, `kjobctl` overview.
+* [commands](commands/kjobctl.md)	 - Full list of commands, along with all possible flags.
\ No newline at end of file
diff --git a/cmd/experimental/kjobctl/go.mod b/cmd/experimental/kjobctl/go.mod
index b6537cbaf..180734527 100644
--- a/cmd/experimental/kjobctl/go.mod
+++ b/cmd/experimental/kjobctl/go.mod
@@ -1,33 +1,39 @@
 module sigs.k8s.io/kueue/cmd/experimental/kjobctl
 
-go 1.22.3
+go 1.22.4
 
 require (
 	github.com/google/go-cmp v0.6.0
 	github.com/onsi/ginkgo/v2 v2.19.0
 	github.com/onsi/gomega v1.33.1
 	github.com/spf13/cobra v1.8.1
-	k8s.io/api v0.30.2
-	k8s.io/apimachinery v0.30.2
-	k8s.io/cli-runtime v0.30.2
-	k8s.io/client-go v0.30.2
+	k8s.io/api v0.30.3
+	k8s.io/apimachinery v0.30.3
+	k8s.io/cli-runtime v0.30.3
+	k8s.io/client-go v0.30.3
 	k8s.io/klog/v2 v2.120.1
-	k8s.io/utils v0.0.0-20240102154912-e7106e64919e
+	k8s.io/kubectl v0.30.2
+	k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0
 	sigs.k8s.io/controller-runtime v0.18.4
-	sigs.k8s.io/kueue v0.7.0
+	sigs.k8s.io/kueue v0.8.0
 )
 
 require (
 	github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
+	github.com/MakeNowJust/heredoc v1.0.0 // indirect
+	github.com/chai2010/gettext-go v1.0.2 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
-	github.com/emicklei/go-restful/v3 v3.11.0 // indirect
-	github.com/evanphx/json-patch v5.6.0+incompatible // indirect
+	github.com/emicklei/go-restful/v3 v3.12.1 // indirect
+	github.com/evanphx/json-patch v5.9.0+incompatible // indirect
 	github.com/evanphx/json-patch/v5 v5.9.0 // indirect
+	github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
+	github.com/fatih/camelcase v1.0.0 // indirect
+	github.com/fvbommel/sortorder v1.1.0 // indirect
 	github.com/go-errors/errors v1.4.2 // indirect
 	github.com/go-logr/logr v1.4.2 // indirect
-	github.com/go-openapi/jsonpointer v0.20.0 // indirect
-	github.com/go-openapi/jsonreference v0.20.2 // indirect
-	github.com/go-openapi/swag v0.22.4 // indirect
+	github.com/go-openapi/jsonpointer v0.21.0 // indirect
+	github.com/go-openapi/jsonreference v0.21.0 // indirect
+	github.com/go-openapi/swag v0.23.0 // indirect
 	github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/golang/protobuf v1.5.4 // indirect
@@ -37,6 +43,7 @@ require (
 	github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect
 	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
 	github.com/google/uuid v1.6.0 // indirect
+	github.com/gorilla/websocket v1.5.1 // indirect
 	github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
 	github.com/imdario/mergo v0.3.16 // indirect
 	github.com/inconshreveable/mousetrap v1.1.0 // indirect
@@ -44,31 +51,35 @@ require (
 	github.com/json-iterator/go v1.1.12 // indirect
 	github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
 	github.com/mailru/easyjson v0.7.7 // indirect
+	github.com/mitchellh/go-wordwrap v1.0.1 // indirect
+	github.com/moby/spdystream v0.2.0 // indirect
 	github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
 	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
+	github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
 	github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
 	github.com/pkg/errors v0.9.1 // indirect
+	github.com/russross/blackfriday/v2 v2.1.0 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
 	github.com/xlab/treeprint v1.2.0 // indirect
 	go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
 	golang.org/x/net v0.25.0 // indirect
-	golang.org/x/oauth2 v0.12.0 // indirect
+	golang.org/x/oauth2 v0.20.0 // indirect
 	golang.org/x/sync v0.7.0 // indirect
 	golang.org/x/sys v0.20.0 // indirect
 	golang.org/x/term v0.20.0 // indirect
 	golang.org/x/text v0.15.0 // indirect
-	golang.org/x/time v0.3.0 // indirect
+	golang.org/x/time v0.5.0 // indirect
 	golang.org/x/tools v0.21.0 // indirect
-	google.golang.org/appengine v1.6.8 // indirect
-	google.golang.org/protobuf v1.33.0 // indirect
+	google.golang.org/protobuf v1.34.1 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 	k8s.io/apiextensions-apiserver v0.30.1 // indirect
-	k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
+	k8s.io/component-base v0.30.3 // indirect
+	k8s.io/kube-openapi v0.0.0-20240521193020-835d969ad83a // indirect
 	sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
 	sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect
 	sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect
diff --git a/cmd/experimental/kjobctl/go.sum b/cmd/experimental/kjobctl/go.sum
index 522052154..e7bd1e69a 100644
--- a/cmd/experimental/kjobctl/go.sum
+++ b/cmd/experimental/kjobctl/go.sum
@@ -2,64 +2,55 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
 github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
 github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
-github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
-github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230321174746-8dcc6526cfb1 h1:X8MJ0fnN5FPdcGF5Ij2/OW+HgiJrRg3AfHAx1PJtIzM=
-github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230321174746-8dcc6526cfb1/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
-github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
-github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
+github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
+github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
+github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
+github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
-github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
-github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
-github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
-github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
-github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
+github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
+github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
-github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
-github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
-github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
 github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
 github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
-github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU=
+github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
 github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
-github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls=
+github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
 github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
 github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
-github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
-github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM=
+github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
+github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
+github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
 github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
 github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
+github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw=
+github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
 github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
 github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
 github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
 github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
-github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
-github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
 github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
 github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
-github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
-github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ=
-github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA=
-github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
-github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
-github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
-github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
-github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
+github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
+github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
+github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
+github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
+github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
+github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
 github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
 github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
 github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
@@ -76,14 +67,10 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
 github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
 github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
 github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
-github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
 github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
 github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
 github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
 github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
-github.com/google/cel-go v0.17.8 h1:j9m730pMZt1Fc4oKhCLUHfjj6527LuhYcYw0Rl8gqto=
-github.com/google/cel-go v0.17.8/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY=
 github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
 github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -92,7 +79,6 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
 github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
@@ -105,13 +91,11 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaU
 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
+github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
-github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
-github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
-github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
 github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
 github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
 github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
@@ -122,11 +106,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
 github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
@@ -136,6 +117,10 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
 github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
 github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
 github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
+github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
+github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
+github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
+github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
 github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA=
 github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -147,6 +132,8 @@ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/
 github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
 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/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
 github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
 github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
 github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
@@ -166,8 +153,9 @@ github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lne
 github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
 github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
 github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
-github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
-github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
+github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
+github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
+github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
 github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
@@ -175,49 +163,17 @@ github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
 github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
-github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
 github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
-github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
 github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-go.etcd.io/etcd/api/v3 v3.5.11 h1:B54KwXbWDHyD3XYAwprxNzTe7vlhR69LuBgZnMVvS7E=
-go.etcd.io/etcd/api/v3 v3.5.11/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4=
-go.etcd.io/etcd/client/pkg/v3 v3.5.11 h1:bT2xVspdiCj2910T0V+/KHcVKjkUrCZVtk8J2JF2z1A=
-go.etcd.io/etcd/client/pkg/v3 v3.5.11/go.mod h1:seTzl2d9APP8R5Y2hFL3NVlD6qC/dOT+3kvrqPyTas4=
-go.etcd.io/etcd/client/v3 v3.5.11 h1:ajWtgoNSZJ1gmS8k+icvPtqsqEav+iUorF7b0qozgUU=
-go.etcd.io/etcd/client/v3 v3.5.11/go.mod h1:a6xQUEqFJ8vztO1agJh/KQKOMfFI8og52ZconzcDJwE=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0 h1:PzIubN4/sjByhDRHLviCjJuweBXWFZWhghjg7cS28+M=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0/go.mod h1:Ct6zzQEuGK3WpJs2n4dn+wfJYzd/+hNnxMRTWjGn30M=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.0 h1:1eHu3/pUSWaOgltNK3WJFaywKsTIr/PwvHyDmi0lQA0=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.0/go.mod h1:HyABWq60Uy1kjJSa2BVOxUVao8Cdick5AWSKPutqy6U=
-go.opentelemetry.io/otel v1.20.0 h1:vsb/ggIY+hUjD/zCAQHpzTmndPqv/ml2ArbsbfBYTAc=
-go.opentelemetry.io/otel v1.20.0/go.mod h1:oUIGj3D77RwJdM6PPZImDpSZGDvkD9fhesHny69JFrs=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0 h1:DeFD0VgTZ+Cj6hxravYYZE2W4GlneVH81iAOPjZkzk8=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0/go.mod h1:GijYcYmNpX1KazD5JmWGsi4P7dDTTTnfv1UbGn84MnU=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0 h1:gvmNvqrPYovvyRmCSygkUDyL8lC5Tl845MLEwqpxhEU=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0/go.mod h1:vNUq47TGFioo+ffTSnKNdob241vePmtNZnAODKapKd0=
-go.opentelemetry.io/otel/metric v1.20.0 h1:ZlrO8Hu9+GAhnepmRGhSU7/VkpjrNowxRN9GyKR4wzA=
-go.opentelemetry.io/otel/metric v1.20.0/go.mod h1:90DRw3nfK4D7Sm/75yQ00gTJxtkBxX+wu6YaNymbpVM=
-go.opentelemetry.io/otel/sdk v1.20.0 h1:5Jf6imeFZlZtKv9Qbo6qt2ZkmWtdWx/wzcCbNUlAWGM=
-go.opentelemetry.io/otel/sdk v1.20.0/go.mod h1:rmkSx1cZCm/tn16iWDn1GQbLtsW/LvsdEEFzCSRM6V0=
-go.opentelemetry.io/otel/trace v1.20.0 h1:+yxVAPZPbQhbC3OfAkeIVTky6iTFpcr4SiY9om7mXSQ=
-go.opentelemetry.io/otel/trace v1.20.0/go.mod h1:HJSK7F/hA5RlzpZ0zKDCHCDHm556LCDtKaAo6JmBFUU=
-go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
-go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
 go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY=
 go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds=
 go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
@@ -227,18 +183,14 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
-golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
-golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
+golang.org/x/exp v0.0.0-20240530194437-404ba88c7ed0 h1:Mi0bCswbz+9cXmwFAdxoo5GPFMKONUpua6iUdtQS7lk=
+golang.org/x/exp v0.0.0-20240530194437-404ba88c7ed0/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
 golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -247,46 +199,36 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
 golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4=
-golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4=
+golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo=
+golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
 golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
 golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
 golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
 golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
 golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
-golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
+golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -295,7 +237,6 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
 golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -306,22 +247,12 @@ gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw
 gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
-google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY=
-google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4=
-google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q=
-google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
 google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
-google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -330,10 +261,8 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
 google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
-google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
-google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
+google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
@@ -347,36 +276,32 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-k8s.io/api v0.30.2 h1:+ZhRj+28QT4UOH+BKznu4CBgPWgkXO7XAvMcMl0qKvI=
-k8s.io/api v0.30.2/go.mod h1:ULg5g9JvOev2dG0u2hig4Z7tQ2hHIuS+m8MNZ+X6EmI=
+k8s.io/api v0.30.3 h1:ImHwK9DCsPA9uoU3rVh4QHAHHK5dTSv1nxJUapx8hoQ=
+k8s.io/api v0.30.3/go.mod h1:GPc8jlzoe5JG3pb0KJCSLX5oAFIW3/qNJITlDj8BH04=
 k8s.io/apiextensions-apiserver v0.30.1 h1:4fAJZ9985BmpJG6PkoxVRpXv9vmPUOVzl614xarePws=
 k8s.io/apiextensions-apiserver v0.30.1/go.mod h1:R4GuSrlhgq43oRY9sF2IToFh7PVlF1JjfWdoG3pixk4=
-k8s.io/apimachinery v0.30.2 h1:fEMcnBj6qkzzPGSVsAZtQThU62SmQ4ZymlXRC5yFSCg=
-k8s.io/apimachinery v0.30.2/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
-k8s.io/apiserver v0.30.1 h1:BEWEe8bzS12nMtDKXzCF5Q5ovp6LjjYkSp8qOPk8LZ8=
-k8s.io/apiserver v0.30.1/go.mod h1:i87ZnQ+/PGAmSbD/iEKM68bm1D5reX8fO4Ito4B01mo=
-k8s.io/cli-runtime v0.30.2 h1:ooM40eEJusbgHNEqnHziN9ZpLN5U4WcQGsdLKVxpkKE=
-k8s.io/cli-runtime v0.30.2/go.mod h1:Y4g/2XezFyTATQUbvV5WaChoUGhojv/jZAtdp5Zkm0A=
-k8s.io/client-go v0.30.2 h1:sBIVJdojUNPDU/jObC+18tXWcTJVcwyqS9diGdWHk50=
-k8s.io/client-go v0.30.2/go.mod h1:JglKSWULm9xlJLx4KCkfLLQ7XwtlbflV6uFFSHTMgVs=
-k8s.io/component-base v0.30.1 h1:bvAtlPh1UrdaZL20D9+sWxsJljMi0QZ3Lmw+kmZAaxQ=
-k8s.io/component-base v0.30.1/go.mod h1:e/X9kDiOebwlI41AvBHuWdqFriSRrX50CdwA9TFaHLI=
+k8s.io/apimachinery v0.30.3 h1:q1laaWCmrszyQuSQCfNB8cFgCuDAoPszKY4ucAjDwHc=
+k8s.io/apimachinery v0.30.3/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
+k8s.io/cli-runtime v0.30.3 h1:aG69oRzJuP2Q4o8dm+f5WJIX4ZBEwrvdID0+MXyUY6k=
+k8s.io/cli-runtime v0.30.3/go.mod h1:hwrrRdd9P84CXSKzhHxrOivAR9BRnkMt0OeP5mj7X30=
+k8s.io/client-go v0.30.3 h1:bHrJu3xQZNXIi8/MoxYtZBBWQQXwy16zqJwloXXfD3k=
+k8s.io/client-go v0.30.3/go.mod h1:8d4pf8vYu665/kUbsxWAQ/JDBNWqfFeZnvFiVdmx89U=
+k8s.io/component-base v0.30.3 h1:Ci0UqKWf4oiwy8hr1+E3dsnliKnkMLZMVbWzeorlk7s=
+k8s.io/component-base v0.30.3/go.mod h1:C1SshT3rGPCuNtBs14RmVD2xW0EhRSeLvBh7AGk1quA=
 k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
 k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
-k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
-k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
-k8s.io/metrics v0.29.5 h1:5AZBM4pMiq+SHi2/RP1OuL90In3f07BrL610zunKoxA=
-k8s.io/metrics v0.29.5/go.mod h1:Cx7JPEEbjdDpEQ2A1QyXSBd6z5bxlwaSf9rgFJ/adfQ=
-k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ=
-k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
-sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0 h1:/U5vjBbQn3RChhv7P11uhYvCSm5G2GaIi5AIGBS6r4c=
-sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0/go.mod h1:z7+wmGM2dfIiLRfrC6jb5kV2Mq/sK1ZP303cxzkV5Y4=
+k8s.io/kube-openapi v0.0.0-20240521193020-835d969ad83a h1:zD1uj3Jf+mD4zmA7W+goE5TxDkI7OGJjBNBzq5fJtLA=
+k8s.io/kube-openapi v0.0.0-20240521193020-835d969ad83a/go.mod h1:UxDHUPsUwTOOxSU+oXURfFBcAS6JwiRXTYqYwfuGowc=
+k8s.io/kubectl v0.30.2 h1:cgKNIvsOiufgcs4yjvgkK0+aPCfa8pUwzXdJtkbhsH8=
+k8s.io/kubectl v0.30.2/go.mod h1:rz7GHXaxwnigrqob0lJsiA07Df8RE3n1TSaC2CTeuB4=
+k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 h1:jgGTlFYnhF1PM1Ax/lAlxUPE+KfCIXHaathvJg1C3ak=
+k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
 sigs.k8s.io/controller-runtime v0.18.4 h1:87+guW1zhvuPLh1PHybKdYFLU0YJp4FhJRmiHvm5BZw=
 sigs.k8s.io/controller-runtime v0.18.4/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg=
 sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
 sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
-sigs.k8s.io/kueue v0.7.0 h1:Rwg2Ce/0kjZwdov1XdsAFb11QQtOOHx7HCTwFSMd8wc=
-sigs.k8s.io/kueue v0.7.0/go.mod h1:tjzIB8Y1vWwBJRWJsXByRIx89PGUq5/mzeLnYHZoFtk=
+sigs.k8s.io/kueue v0.8.0 h1:fMfZVcqmPFz4YoLwWiYzVwEHvcF4+QuiQBPFtUCW/64=
+sigs.k8s.io/kueue v0.8.0/go.mod h1:rpiskRaOSf4iapxEWFrJ8Ryp5Uij442XSswav3mvdao=
 sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0=
 sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY=
 sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U=
diff --git a/cmd/experimental/kjobctl/hack/tools/go.mod b/cmd/experimental/kjobctl/hack/tools/go.mod
index 34003f265..d3c7ce310 100644
--- a/cmd/experimental/kjobctl/hack/tools/go.mod
+++ b/cmd/experimental/kjobctl/hack/tools/go.mod
@@ -5,70 +5,104 @@ go 1.22.4
 require (
 	github.com/golangci/golangci-lint v1.59.1
 	github.com/onsi/ginkgo/v2 v2.19.0
+	github.com/spf13/cobra v1.8.1
+	github.com/spf13/pflag v1.0.5
 	gotest.tools/gotestsum v1.12.0
-	k8s.io/code-generator v0.30.2
-	sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20240618123038-8290d13680ed
+	k8s.io/code-generator v0.30.3
+	k8s.io/component-base v0.30.3
+	sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20240717190548-1ed345090869
 	sigs.k8s.io/controller-tools v0.15.0
-	sigs.k8s.io/kustomize/kustomize/v5 v5.4.2
+	sigs.k8s.io/kueue/cmd/experimental/kjobctl v0.0.0-00010101000000-000000000000
+	sigs.k8s.io/kustomize/kustomize/v5 v5.4.3
 )
 
+replace sigs.k8s.io/kueue/cmd/experimental/kjobctl => ../..
+
 require (
+	github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
+	github.com/MakeNowJust/heredoc v1.0.0 // indirect
 	github.com/bitfield/gotestdox v0.2.2 // indirect
 	github.com/blang/semver/v4 v4.0.0 // indirect
+	github.com/chai2010/gettext-go v1.0.2 // indirect
 	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
 	github.com/dnephin/pflag v1.0.7 // indirect
+	github.com/emicklei/go-restful/v3 v3.12.1 // indirect
+	github.com/evanphx/json-patch v5.9.0+incompatible // indirect
+	github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
+	github.com/fatih/camelcase v1.0.0 // indirect
 	github.com/fatih/color v1.17.0 // indirect
 	github.com/fsnotify/fsnotify v1.7.0 // indirect
-	github.com/fxamacker/cbor/v2 v2.7.0-beta // indirect
-	github.com/go-errors/errors v1.4.2 // indirect
-	github.com/go-logr/logr v1.4.1 // indirect
-	github.com/go-openapi/jsonpointer v0.19.6 // indirect
-	github.com/go-openapi/jsonreference v0.20.2 // indirect
-	github.com/go-openapi/swag v0.22.4 // indirect
+	github.com/fvbommel/sortorder v1.1.0 // indirect
+	github.com/fxamacker/cbor/v2 v2.7.0 // indirect
+	github.com/go-errors/errors v1.5.1 // indirect
+	github.com/go-logr/logr v1.4.2 // indirect
+	github.com/go-openapi/jsonpointer v0.21.0 // indirect
+	github.com/go-openapi/jsonreference v0.21.0 // indirect
+	github.com/go-openapi/swag v0.23.0 // indirect
 	github.com/gobuffalo/flect v1.0.2 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/golang/protobuf v1.5.4 // indirect
+	github.com/google/btree v1.1.2 // indirect
 	github.com/google/gnostic-models v0.6.8 // indirect
+	github.com/google/go-cmp v0.6.0 // indirect
 	github.com/google/gofuzz v1.2.0 // indirect
-	github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af // indirect
+	github.com/google/pprof v0.0.0-20240711041743-f6c9dda6c6da // indirect
 	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
+	github.com/google/uuid v1.6.0 // indirect
+	github.com/gorilla/websocket v1.5.1 // indirect
+	github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
+	github.com/imdario/mergo v0.3.16 // indirect
 	github.com/inconshreveable/mousetrap v1.1.0 // indirect
 	github.com/josharian/intern v1.0.0 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
+	github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
 	github.com/mailru/easyjson v0.7.7 // indirect
 	github.com/mattn/go-colorable v0.1.13 // indirect
 	github.com/mattn/go-isatty v0.0.20 // indirect
+	github.com/mitchellh/go-wordwrap v1.0.1 // indirect
+	github.com/moby/spdystream v0.4.0 // indirect
+	github.com/moby/term v0.5.0 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
+	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
+	github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
+	github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
 	github.com/pkg/errors v0.9.1 // indirect
+	github.com/russross/blackfriday/v2 v2.1.0 // indirect
 	github.com/spf13/afero v1.11.0 // indirect
-	github.com/spf13/cobra v1.8.0 // indirect
-	github.com/spf13/pflag v1.0.5 // indirect
 	github.com/x448/float16 v0.8.4 // indirect
 	github.com/xlab/treeprint v1.2.0 // indirect
-	go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
-	golang.org/x/mod v0.18.0 // indirect
-	golang.org/x/net v0.26.0 // indirect
+	go.starlark.net v0.0.0-20240705175910-70002002b310 // indirect
+	golang.org/x/mod v0.19.0 // indirect
+	golang.org/x/net v0.27.0 // indirect
+	golang.org/x/oauth2 v0.21.0 // indirect
 	golang.org/x/sync v0.7.0 // indirect
-	golang.org/x/sys v0.21.0 // indirect
-	golang.org/x/term v0.21.0 // indirect
+	golang.org/x/sys v0.22.0 // indirect
+	golang.org/x/term v0.22.0 // indirect
 	golang.org/x/text v0.16.0 // indirect
-	golang.org/x/tools v0.22.0 // indirect
-	google.golang.org/protobuf v1.33.0 // indirect
+	golang.org/x/time v0.5.0 // indirect
+	golang.org/x/tools v0.23.0 // indirect
+	google.golang.org/protobuf v1.34.2 // indirect
 	gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
-	k8s.io/apiextensions-apiserver v0.30.0 // indirect
-	k8s.io/apimachinery v0.31.0-alpha.1 // indirect
-	k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70 // indirect
-	k8s.io/klog/v2 v2.120.1 // indirect
-	k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
-	k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
+	k8s.io/api v0.30.3 // indirect
+	k8s.io/apiextensions-apiserver v0.30.3 // indirect
+	k8s.io/apimachinery v0.31.0-beta.0 // indirect
+	k8s.io/cli-runtime v0.30.3 // indirect
+	k8s.io/client-go v0.30.3 // indirect
+	k8s.io/gengo/v2 v2.0.0-20240404160639-a0386bf69313 // indirect
+	k8s.io/klog/v2 v2.130.1 // indirect
+	k8s.io/kube-openapi v0.0.0-20240709000822-3c01b740850f // indirect
+	k8s.io/kubectl v0.30.3 // indirect
+	k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect
+	sigs.k8s.io/controller-runtime v0.18.4 // indirect
 	sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
-	sigs.k8s.io/kustomize/api v0.17.2 // indirect
-	sigs.k8s.io/kustomize/kyaml v0.17.1 // indirect
+	sigs.k8s.io/kueue v0.8.0 // indirect
+	sigs.k8s.io/kustomize/api v0.17.3 // indirect
+	sigs.k8s.io/kustomize/kyaml v0.17.2 // indirect
 	sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
 	sigs.k8s.io/yaml v1.4.0 // indirect
 )
diff --git a/cmd/experimental/kjobctl/hack/tools/go.sum b/cmd/experimental/kjobctl/hack/tools/go.sum
index 87e403d51..3adb1aaff 100644
--- a/cmd/experimental/kjobctl/hack/tools/go.sum
+++ b/cmd/experimental/kjobctl/hack/tools/go.sum
@@ -1,39 +1,55 @@
+github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
+github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
+github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
+github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
+github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
+github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
 github.com/bitfield/gotestdox v0.2.2 h1:x6RcPAbBbErKLnapz1QeAlf3ospg8efBsedU93CDsnE=
 github.com/bitfield/gotestdox v0.2.2/go.mod h1:D+gwtS0urjBrzguAkTM2wodsTQYFHdpx8eqRJ3N+9pY=
 github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
 github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
-github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
-github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
-github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
+github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
+github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
+github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/dnephin/pflag v1.0.7 h1:oxONGlWxhmUct0YzKTgrpQv9AUA1wtPBn7zuSjJqptk=
 github.com/dnephin/pflag v1.0.7/go.mod h1:uxE91IoWURlOiTUIA8Mq5ZZkAv3dPUfZNaT80Zm7OQE=
+github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU=
+github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls=
+github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM=
+github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
+github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
+github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
 github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
 github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
 github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
 github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
 github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
 github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
-github.com/fxamacker/cbor/v2 v2.7.0-beta h1:m5bO941uTVpSms26QjzEJxUZaC3S/h1pSJexBCu4wAA=
-github.com/fxamacker/cbor/v2 v2.7.0-beta/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
-github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
-github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
-github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
-github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw=
+github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
+github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
+github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
+github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
+github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
+github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
+github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
 github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
 github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
-github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
-github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
-github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
-github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
-github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
-github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
-github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
+github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
+github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
+github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
+github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
+github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
+github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
 github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
 github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
 github.com/gobuffalo/flect v1.0.2 h1:eqjPGSo2WmjgY2XlpGwo2NXgL3RucAKo4k4qQMNA5sA=
@@ -44,6 +60,8 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek
 github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
 github.com/golangci/golangci-lint v1.59.1 h1:CRRLu1JbhK5avLABFJ/OHVSQ0Ie5c4ulsOId1h3TTks=
 github.com/golangci/golangci-lint v1.59.1/go.mod h1:jX5Oif4C7P0j9++YB2MMJmoNrb01NJ8ITqKWNLewThg=
+github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
+github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
 github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
 github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
 github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
@@ -52,10 +70,18 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
 github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM=
-github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
+github.com/google/pprof v0.0.0-20240711041743-f6c9dda6c6da h1:xRmpO92tb8y+Z85iUOMOicpCfaYcv7o3Cg3wKrIpg8g=
+github.com/google/pprof v0.0.0-20240711041743-f6c9dda6c6da/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
+github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
+github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
+github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
+github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
+github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
 github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
 github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@@ -64,13 +90,12 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
 github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
+github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
 github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
 github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
@@ -80,6 +105,12 @@ github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
 github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
 github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
 github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
+github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
+github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8=
+github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
+github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
+github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -87,6 +118,10 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
 github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
+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/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
 github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
 github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
 github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
@@ -95,20 +130,24 @@ github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA
 github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
 github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
 github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
+github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
+github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
 github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
+github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
+github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
+github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
 github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
 github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
 github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
-github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
-github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
+github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
+github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -130,14 +169,14 @@ github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc=
-go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o=
+go.starlark.net v0.0.0-20240705175910-70002002b310 h1:tEAOMoNmN2MqVNi0MMEWpTtPI4YNCXgxmAGtuv3mST0=
+go.starlark.net v0.0.0-20240705175910-70002002b310/go.mod h1:YKMCv9b1WrfWmeqdV5MAuEHWsu5iC+fe6kYl2sQjdI8=
 go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
 go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
 go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
 go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
-go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
-go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
+go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
+go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -156,8 +195,8 @@ golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
 golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
-golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
+golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -171,8 +210,10 @@ golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
 golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
 golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
 golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
-golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
-golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
+golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
+golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
+golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
+golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -184,10 +225,10 @@ golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
 golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -201,8 +242,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
-golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
+golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -213,8 +254,8 @@ golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
 golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
 golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
 golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
-golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
-golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
+golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
+golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
@@ -226,6 +267,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
 golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
+golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
+golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
@@ -236,14 +279,14 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
 golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8=
 golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
 golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
-golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
-golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
+golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
+golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
-google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
@@ -263,32 +306,46 @@ gotest.tools/gotestsum v1.12.0 h1:CmwtaGDkHxrZm4Ib0Vob89MTfpc3GrEFMJKovliPwGk=
 gotest.tools/gotestsum v1.12.0/go.mod h1:fAvqkSptospfSbQw26CTYzNwnsE/ztqLeyhP0h67ARY=
 gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
 gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
-k8s.io/apiextensions-apiserver v0.30.0 h1:jcZFKMqnICJfRxTgnC4E+Hpcq8UEhT8B2lhBcQ+6uAs=
-k8s.io/apiextensions-apiserver v0.30.0/go.mod h1:N9ogQFGcrbWqAY9p2mUAL5mGxsLqwgtUce127VtRX5Y=
-k8s.io/apimachinery v0.31.0-alpha.1 h1:ZWYSLeKpvdx5GLJdIkFDMz7I1qS/Gwb2QiJT2feQpRg=
-k8s.io/apimachinery v0.31.0-alpha.1/go.mod h1:3nAExNh3CrzC6eKT9a32j/rv+uJ8Zod87oOmgUjZNAY=
-k8s.io/code-generator v0.30.2 h1:ZY1+aGkqZVwKIyGsOzquaeZ5rSfE6wZHur8z3jQAaiw=
-k8s.io/code-generator v0.30.2/go.mod h1:RQP5L67QxqgkVquk704CyvWFIq0e6RCMmLTXxjE8dVA=
-k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70 h1:NGrVE502P0s0/1hudf8zjgwki1X/TByhmAoILTarmzo=
-k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70/go.mod h1:VH3AT8AaQOqiGjMF9p0/IM1Dj+82ZwjfxUP1IxaHE+8=
-k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
-k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
-k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
-k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
-k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
-k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
-sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20240618123038-8290d13680ed h1:8gHj5Jc57JFkJX3IwoNddrOqBz3BzdZmJyBxFUSj3Q8=
-sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20240618123038-8290d13680ed/go.mod h1:fEsdUdAGAHkjE4uZalekjZ5rXArxkif7RTfs1p5oRGg=
+k8s.io/api v0.30.3 h1:ImHwK9DCsPA9uoU3rVh4QHAHHK5dTSv1nxJUapx8hoQ=
+k8s.io/api v0.30.3/go.mod h1:GPc8jlzoe5JG3pb0KJCSLX5oAFIW3/qNJITlDj8BH04=
+k8s.io/apiextensions-apiserver v0.30.3 h1:oChu5li2vsZHx2IvnGP3ah8Nj3KyqG3kRSaKmijhB9U=
+k8s.io/apiextensions-apiserver v0.30.3/go.mod h1:uhXxYDkMAvl6CJw4lrDN4CPbONkF3+XL9cacCT44kV4=
+k8s.io/apimachinery v0.31.0-beta.0 h1:KoBE9f7sPz67HclZC/JgH1pIBvOlMZQAwoHQuriE/5E=
+k8s.io/apimachinery v0.31.0-beta.0/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
+k8s.io/cli-runtime v0.30.3 h1:aG69oRzJuP2Q4o8dm+f5WJIX4ZBEwrvdID0+MXyUY6k=
+k8s.io/cli-runtime v0.30.3/go.mod h1:hwrrRdd9P84CXSKzhHxrOivAR9BRnkMt0OeP5mj7X30=
+k8s.io/client-go v0.30.3 h1:bHrJu3xQZNXIi8/MoxYtZBBWQQXwy16zqJwloXXfD3k=
+k8s.io/client-go v0.30.3/go.mod h1:8d4pf8vYu665/kUbsxWAQ/JDBNWqfFeZnvFiVdmx89U=
+k8s.io/code-generator v0.30.3 h1:bmtnLJKagDS5f5uOEpLyJiDfIMKXGMKgOLBdde+w0Mc=
+k8s.io/code-generator v0.30.3/go.mod h1:PFgBiv+miFV7TZYp+RXgROkhA+sWYZ+mtpbMLofMke8=
+k8s.io/component-base v0.30.3 h1:Ci0UqKWf4oiwy8hr1+E3dsnliKnkMLZMVbWzeorlk7s=
+k8s.io/component-base v0.30.3/go.mod h1:C1SshT3rGPCuNtBs14RmVD2xW0EhRSeLvBh7AGk1quA=
+k8s.io/gengo/v2 v2.0.0-20240404160639-a0386bf69313 h1:bKcdZJOPICVmIIuaM9+MXmapE94dn5AYv5ODs1jA43o=
+k8s.io/gengo/v2 v2.0.0-20240404160639-a0386bf69313/go.mod h1:VH3AT8AaQOqiGjMF9p0/IM1Dj+82ZwjfxUP1IxaHE+8=
+k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
+k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
+k8s.io/kube-openapi v0.0.0-20240709000822-3c01b740850f h1:2sXuKesAYbRHxL3aE2PN6zX/gcJr22cjrsej+W784Tc=
+k8s.io/kube-openapi v0.0.0-20240709000822-3c01b740850f/go.mod h1:UxDHUPsUwTOOxSU+oXURfFBcAS6JwiRXTYqYwfuGowc=
+k8s.io/kubectl v0.30.3 h1:YIBBvMdTW0xcDpmrOBzcpUVsn+zOgjMYIu7kAq+yqiI=
+k8s.io/kubectl v0.30.3/go.mod h1:IcR0I9RN2+zzTRUa1BzZCm4oM0NLOawE6RzlDvd1Fpo=
+k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
+k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+sigs.k8s.io/controller-runtime v0.18.4 h1:87+guW1zhvuPLh1PHybKdYFLU0YJp4FhJRmiHvm5BZw=
+sigs.k8s.io/controller-runtime v0.18.4/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg=
+sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20240717190548-1ed345090869 h1:YdkRbWbuTULZdBarJPqdB3/PXgHvw3iANjgBeJiizrQ=
+sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20240717190548-1ed345090869/go.mod h1:lMOTIN14oWZXDAQ4YuBsRCpS/N5EyqrBJPwkcyZqmAk=
 sigs.k8s.io/controller-tools v0.15.0 h1:4dxdABXGDhIa68Fiwaif0vcu32xfwmgQ+w8p+5CxoAI=
 sigs.k8s.io/controller-tools v0.15.0/go.mod h1:8zUSS2T8Hx0APCNRhJWbS3CAQEbIxLa07khzh7pZmXM=
 sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
 sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
-sigs.k8s.io/kustomize/api v0.17.2 h1:E7/Fjk7V5fboiuijoZHgs4aHuexi5Y2loXlVOAVAG5g=
-sigs.k8s.io/kustomize/api v0.17.2/go.mod h1:UWTz9Ct+MvoeQsHcJ5e+vziRRkwimm3HytpZgIYqye0=
-sigs.k8s.io/kustomize/kustomize/v5 v5.4.2 h1:9Zl5Gqg3XMdBEvkR54pVLCBj7FVO7W+VPNDDEzD6AyE=
-sigs.k8s.io/kustomize/kustomize/v5 v5.4.2/go.mod h1:5ypfJVYlPb2MKKeoGknVLxvHemDlQT+szI4+KOhnD6k=
-sigs.k8s.io/kustomize/kyaml v0.17.1 h1:TnxYQxFXzbmNG6gOINgGWQt09GghzgTP6mIurOgrLCQ=
-sigs.k8s.io/kustomize/kyaml v0.17.1/go.mod h1:9V0mCjIEYjlXuCdYsSXvyoy2BTsLESH7TlGV81S282U=
+sigs.k8s.io/kueue v0.8.0 h1:fMfZVcqmPFz4YoLwWiYzVwEHvcF4+QuiQBPFtUCW/64=
+sigs.k8s.io/kueue v0.8.0/go.mod h1:rpiskRaOSf4iapxEWFrJ8Ryp5Uij442XSswav3mvdao=
+sigs.k8s.io/kustomize/api v0.17.3 h1:6GCuHSsxq7fN5yhF2XrC+AAr8gxQwhexgHflOAD/JJU=
+sigs.k8s.io/kustomize/api v0.17.3/go.mod h1:TuDH4mdx7jTfK61SQ/j1QZM/QWR+5rmEiNjvYlhzFhc=
+sigs.k8s.io/kustomize/kustomize/v5 v5.4.3 h1:SJMDq/0HYNTFPgmlBuxsGzdBB6furxhwHKHEfzBbvSw=
+sigs.k8s.io/kustomize/kustomize/v5 v5.4.3/go.mod h1:vhSLBp3H7wx0oeh/hE7CMQVNft42plZxUqxhvVZxb8Q=
+sigs.k8s.io/kustomize/kyaml v0.17.2 h1:+AzvoJUY0kq4QAhH/ydPHHMRLijtUKiyVyh7fOSshr0=
+sigs.k8s.io/kustomize/kyaml v0.17.2/go.mod h1:9V0mCjIEYjlXuCdYsSXvyoy2BTsLESH7TlGV81S282U=
 sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
 sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
 sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
diff --git a/cmd/experimental/kjobctl/hack/tools/kjobctl-docs/generators/doc.go b/cmd/experimental/kjobctl/hack/tools/kjobctl-docs/generators/doc.go
new file mode 100644
index 000000000..ddaf027ba
--- /dev/null
+++ b/cmd/experimental/kjobctl/hack/tools/kjobctl-docs/generators/doc.go
@@ -0,0 +1,374 @@
+/*
+Copyright 2024 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package generators
+
+import (
+	"fmt"
+	"html"
+	"html/template"
+	"io"
+	"os"
+	"os/user"
+	"path/filepath"
+	"sort"
+	"strings"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/pflag"
+)
+
+type Reference struct {
+	NoList           bool
+	Title            string
+	Description      string
+	ShowUseLine      bool
+	UseLine          string
+	ShowExample      bool
+	Example          string
+	Options          []Option
+	InheritedOptions []Option
+	Links            []Link
+}
+
+type Option struct {
+	Name        string
+	Shorthand   string
+	Usage       string
+	ValueType   string
+	DefVal      string
+	NoOptDefVal string
+}
+
+type Link struct {
+	Name        string
+	Description string
+	Path        string
+}
+
+type byName []*cobra.Command
+
+func (s byName) Len() int           { return len(s) }
+func (s byName) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
+func (s byName) Less(i, j int) bool { return s[i].Name() < s[j].Name() }
+
+func GenMarkdownTree(cmd *cobra.Command, templatesDir, outputDir string) error {
+	identity := func(s string) string { return s }
+	emptyStr := func(s string) string { return "" }
+	return GenMarkdownTreeCustom(cmd, templatesDir, outputDir, "", emptyStr, identity)
+}
+
+func GenMarkdownTreeCustom(cmd *cobra.Command, templatesDir, outputDir string, subdir string, filePrepender, linkHandler func(string) string) error {
+	for _, c := range cmd.Commands() {
+		if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() {
+			continue
+		}
+		// CommandPath example: 'kjobctl create localqueue'
+		parts := strings.Split(c.CommandPath(), " ")
+		childSubdir := ""
+		if len(parts) > 1 {
+			childSubdir = parts[0] + "_" + parts[1]
+			fullPath := filepath.Join(outputDir, childSubdir)
+			if _, err := os.Stat(fullPath); os.IsNotExist(err) {
+				if err := os.Mkdir(fullPath, 0770); err != nil {
+					return err
+				}
+			}
+		}
+		if err := GenMarkdownTreeCustom(c, templatesDir, outputDir, childSubdir, filePrepender, linkHandler); err != nil {
+			return err
+		}
+	}
+
+	fullname := strings.ReplaceAll(cmd.CommandPath(), " ", "_") + ".md"
+	indexFile := false
+	if len(subdir) > 0 {
+		parts := strings.Split(cmd.CommandPath(), " ")
+		if len(parts) == 2 {
+			indexFile = true
+			fullname = "_index.md"
+		}
+		fullname = filepath.Join(subdir, fullname)
+	}
+	filename := filepath.Join(outputDir, fullname)
+
+	f, err := os.Create(filename)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+
+	if _, err := io.WriteString(f, filePrepender(filename)); err != nil {
+		return err
+	}
+	if err := GenReference(cmd, templatesDir, f, linkHandler, indexFile); err != nil {
+		return err
+	}
+	return nil
+}
+
+func GenReference(cmd *cobra.Command, templatesDir string, w io.Writer, linkHandler func(string) string, indexFile bool) error {
+	ref := getReference(cmd, linkHandler, indexFile)
+
+	tmpl, err := template.New("main.md").
+		Funcs(template.FuncMap{
+			"html":  htmlFuncMap,
+			"usage": usageFuncMap,
+		}).
+		ParseGlob(fmt.Sprintf("%s/*", templatesDir))
+	if err != nil {
+		return err
+	}
+	if err := tmpl.Execute(w, ref); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func htmlFuncMap(s string) template.HTML {
+	return template.HTML(s)
+}
+
+func usageFuncMap(usage string) template.HTML {
+	usage = html.EscapeString(usage)
+	usage = strings.TrimSuffix(usage, "\\n")
+	usage = strings.ReplaceAll(usage, "\\n", "<br/>")
+	return htmlFuncMap(usage)
+}
+
+func getReference(cmd *cobra.Command, linkHandler func(string) string, indexFile bool) *Reference {
+	cmd.InitDefaultHelpCmd()
+	cmd.InitDefaultHelpFlag()
+
+	ref := &Reference{
+		NoList:           indexFile,
+		Title:            strings.TrimSpace(cmd.CommandPath()),
+		Description:      cmd.Long,
+		Example:          cmd.Example,
+		Options:          getOptions(cmd.NonInheritedFlags()),
+		InheritedOptions: getOptions(cmd.InheritedFlags()),
+		Links:            getLinks(cmd, linkHandler, indexFile),
+	}
+
+	if len(ref.Description) == 0 {
+		ref.Description = cmd.Short
+	}
+
+	if cmd.Runnable() {
+		ref.UseLine = cmd.UseLine()
+	}
+
+	return ref
+}
+
+func getOptions(f *pflag.FlagSet) []Option {
+	var options []Option
+
+	f.VisitAll(func(flag *pflag.Flag) {
+		if len(flag.Deprecated) > 0 || flag.Hidden {
+			return
+		}
+
+		option := Option{
+			Name:        flag.Name,
+			Usage:       flag.Usage,
+			ValueType:   getValueType(flag),
+			DefVal:      getDefaultVal(flag),
+			NoOptDefVal: getNoOptDefVal(flag),
+		}
+
+		if len(flag.ShorthandDeprecated) == 0 {
+			option.Shorthand = flag.Shorthand
+		}
+
+		options = append(options, option)
+	})
+
+	return options
+}
+
+func getValueType(flag *pflag.Flag) string {
+	name := flag.Value.Type()
+	switch name {
+	case "bool":
+		return ""
+	case "float64", "float32":
+		return "float"
+	case "int64", "int32", "int8":
+		return "int"
+	case "uint64", "uint32", "uint8":
+		return "uint"
+	case "stringSlice", "stringArray":
+		return "strings"
+	case "float32Slice", "float64Slice":
+		return "floats"
+	case "intSlice", "int32Slice", "int64Slice":
+		return "ints"
+	case "uintSlice":
+		return "uints"
+	case "boolSlice":
+		return "bools"
+	case "durationSlice":
+		return "durations"
+	case "stringToString":
+		return "<comma-separated 'key=value' pairs>"
+	default:
+		return name
+	}
+}
+
+func getNoOptDefVal(flag *pflag.Flag) string {
+	if len(flag.NoOptDefVal) == 0 {
+		return ""
+	}
+
+	switch flag.Value.Type() {
+	case "string":
+		return fmt.Sprintf("[=\"%s\"]", flag.NoOptDefVal)
+	case "bool":
+		if flag.NoOptDefVal != "true" {
+			return fmt.Sprintf("[=%s]", flag.NoOptDefVal)
+		} else {
+			return ""
+		}
+	default:
+		return fmt.Sprintf("[=%s]", flag.NoOptDefVal)
+	}
+}
+
+func getDefaultVal(flag *pflag.Flag) string {
+	var defaultVal string
+
+	if !defaultIsZeroValue(flag) {
+		defaultVal = flag.DefValue
+		switch flag.Value.Type() {
+		case "string":
+			// There are cases where the string is very-very long, split
+			// it to mutiple lines manually
+			if len(defaultVal) > 40 {
+				defaultVal = strings.ReplaceAll(defaultVal, ",", ",<br />")
+			}
+			// clean up kjobctl cache-dir flag value
+			if strings.Compare(flag.Name, "cache-dir") == 0 {
+				myUser, err := user.Current()
+				if err == nil {
+					noprefix := strings.TrimPrefix(defaultVal, myUser.HomeDir)
+					defaultVal = fmt.Sprintf("$HOME%s", noprefix)
+				}
+			}
+			defaultVal = fmt.Sprintf("\"%s\"", defaultVal)
+		case "stringSlice":
+			// For string slices, the default value should not contain '[' ]r ']'
+			defaultVal = strings.TrimPrefix(defaultVal, "[")
+			defaultVal = strings.TrimSuffix(defaultVal, "]")
+			defaultVal = strings.ReplaceAll(defaultVal, " ", "")
+			defaultVal = fmt.Sprintf("\"%s\"", defaultVal)
+		}
+	}
+
+	return defaultVal
+}
+
+func getLinks(cmd *cobra.Command, linkHandler func(string) string, indexFile bool) []Link {
+	var links []Link
+
+	if cmd.HasParent() {
+		parent := cmd.Parent()
+
+		parts := strings.Split(parent.CommandPath(), " ")
+		commandPath := strings.Join(parts, "_")
+
+		var path string
+		if indexFile {
+			path = "../" + commandPath + ".md"
+		} else {
+			path = "_index.md"
+		}
+
+		link := Link{
+			Name:        commandPath,
+			Path:        linkHandler(path),
+			Description: parent.Short,
+		}
+
+		cmd.VisitParents(func(c *cobra.Command) {
+			if c.DisableAutoGenTag {
+				cmd.DisableAutoGenTag = c.DisableAutoGenTag
+			}
+		})
+
+		links = append(links, link)
+	}
+
+	name := cmd.CommandPath()
+	children := cmd.Commands()
+	sort.Sort(byName(children))
+
+	for _, child := range children {
+		if !child.IsAvailableCommand() || child.IsAdditionalHelpTopicCommand() {
+			continue
+		}
+		cname := name + " " + child.Name()
+		path := strings.ReplaceAll(cname, " ", "_")
+		if indexFile {
+			path = path + ".md"
+		} else {
+			path = path + "/_index.md"
+		}
+
+		link := Link{
+			Name:        cname,
+			Path:        linkHandler(path),
+			Description: child.Short,
+		}
+
+		links = append(links, link)
+	}
+
+	return links
+}
+
+func defaultIsZeroValue(f *pflag.Flag) bool {
+	switch f.Value.Type() {
+	case "bool":
+		return f.DefValue == "false"
+	case "duration":
+		return f.DefValue == "0" || f.DefValue == "0s"
+	case "int", "int8", "int32", "int64", "uint", "uint8", "uint16", "uint32", "count", "float32", "float64":
+		return f.DefValue == "0"
+	case "string":
+		return f.DefValue == ""
+	case "ip", "ipMask", "ipNet":
+		return f.DefValue == "<nil>"
+	case "intSlice", "stringSlice", "stringArray":
+		return f.DefValue == "[]"
+	case "namedCertKey":
+		return f.DefValue == "[]"
+	default:
+		switch f.Value.String() {
+		case "false":
+			return true
+		case "<nil>":
+			return true
+		case "":
+			return true
+		case "0":
+			return true
+		}
+		return false
+	}
+}
diff --git a/cmd/experimental/kjobctl/hack/tools/kjobctl-docs/main.go b/cmd/experimental/kjobctl/hack/tools/kjobctl-docs/main.go
new file mode 100644
index 000000000..0a2fd6050
--- /dev/null
+++ b/cmd/experimental/kjobctl/hack/tools/kjobctl-docs/main.go
@@ -0,0 +1,51 @@
+/*
+Copyright 2024 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package main
+
+import (
+	goflag "flag"
+	"log"
+	"os"
+
+	"github.com/spf13/pflag"
+	cliflag "k8s.io/component-base/cli/flag"
+
+	"sigs.k8s.io/kueue/cmd/experimental/kjobctl/hack/tools/kjobctl-docs/generators"
+	"sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/cmd"
+)
+
+func main() {
+	var (
+		templatesDir string
+		outputDir    string
+	)
+
+	if len(os.Args) == 3 {
+		templatesDir = os.Args[1]
+		outputDir = os.Args[2]
+	} else {
+		log.Fatalf("usage: %s <templates-dir> <output-dir>", os.Args[0])
+	}
+
+	cmd := cmd.NewDefaultKjobctlCmd()
+	pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
+	pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
+
+	if err := generators.GenMarkdownTree(cmd, templatesDir, outputDir); err != nil {
+		panic(err)
+	}
+}
diff --git a/cmd/experimental/kjobctl/hack/tools/kjobctl-docs/templates/main.md b/cmd/experimental/kjobctl/hack/tools/kjobctl-docs/templates/main.md
new file mode 100644
index 000000000..c32425d91
--- /dev/null
+++ b/cmd/experimental/kjobctl/hack/tools/kjobctl-docs/templates/main.md
@@ -0,0 +1,50 @@
+{{ html `<!--
+The file is auto-generated from the Go source code of the component using the
+[generator](https://github.com/kubernetes-sigs/kueue/tree/main/cmd/experimental/kjobctl/hack/tools/kjobctl-docs).
+-->`}}
+
+# {{.Title}}
+
+
+## Synopsis
+
+
+{{.Description}}
+{{- if .UseLine}}
+
+```
+{{.UseLine}}
+```
+{{- end}}
+{{- if .Example}}
+
+
+## Examples
+
+```
+{{.Example}}
+```
+{{- end}}
+{{- if .Options}}
+
+
+## Options
+
+{{template "options" .Options}}
+{{- end}}
+{{- if .InheritedOptions}}
+
+
+## Options inherited from parent commands
+
+{{- template "options" .InheritedOptions}}
+{{- end}}
+{{- if .Links}}
+
+
+## See Also
+{{range .Links}}
+* [{{.Name}}]({{.Path}}){{"\t"}} - {{.Description}}
+{{- end}}
+{{- end}}
+
diff --git a/cmd/experimental/kjobctl/hack/tools/kjobctl-docs/templates/options.html b/cmd/experimental/kjobctl/hack/tools/kjobctl-docs/templates/options.html
new file mode 100644
index 000000000..55280daef
--- /dev/null
+++ b/cmd/experimental/kjobctl/hack/tools/kjobctl-docs/templates/options.html
@@ -0,0 +1,24 @@
+{{define "options"}}
+<table style="width: 100%; table-layout: fixed;">
+    <colgroup>
+        <col span="1" style="width: 10px;" />
+        <col span="1" />
+    </colgroup>
+    <tbody>
+    {{- range .}}
+    <tr>
+        <td colspan="2">{{if .Shorthand}}-{{.Shorthand}}, {{end}}--{{.Name}}
+            {{- if .ValueType}} {{.ValueType}}{{end}}
+            {{- if .NoOptDefVal}} {{.NoOptDefVal}}{{end}}
+            {{- if .DefVal}}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default: {{.DefVal}}{{end}}</td>
+    </tr>
+    <tr>
+        <td></td>
+        <td style="line-height: 130%; word-wrap: break-word;">
+            <p>{{usage .Usage}}</p>
+        </td>
+    </tr>
+    {{- end}}
+    </tbody>
+</table>
+{{end}}
\ No newline at end of file
diff --git a/cmd/experimental/kjobctl/pkg/builder/builder.go b/cmd/experimental/kjobctl/pkg/builder/builder.go
index 933d30556..1ed7113bb 100644
--- a/cmd/experimental/kjobctl/pkg/builder/builder.go
+++ b/cmd/experimental/kjobctl/pkg/builder/builder.go
@@ -19,7 +19,10 @@ package builder
 import (
 	"context"
 	"errors"
+	"fmt"
+	"os"
 	"slices"
+	"time"
 
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -29,6 +32,7 @@ import (
 	"sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1"
 	"sigs.k8s.io/kueue/cmd/experimental/kjobctl/client-go/clientset/versioned"
 	"sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/cmd/util"
+	"sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/constants"
 )
 
 var (
@@ -66,10 +70,12 @@ type Builder struct {
 	profile       *v1alpha1.ApplicationProfile
 	mode          *v1alpha1.SupportedMode
 	volumeBundles []v1alpha1.VolumeBundle
+
+	buildTime time.Time
 }
 
-func NewBuilder(clientGetter util.ClientGetter) *Builder {
-	return &Builder{clientGetter: clientGetter}
+func NewBuilder(clientGetter util.ClientGetter, buildTime time.Time) *Builder {
+	return &Builder{clientGetter: clientGetter, buildTime: buildTime}
 }
 
 func (b *Builder) WithNamespace(namespace string) *Builder {
@@ -236,6 +242,7 @@ func (b *Builder) buildPodSpec(templateSpec corev1.PodSpec) corev1.PodSpec {
 
 		container.VolumeMounts = append(container.VolumeMounts, bundle.Spec.ContainerVolumeMounts...)
 		container.Env = append(container.Env, bundle.Spec.EnvVars...)
+		container.Env = append(container.Env, b.additionalEnvironmentVariables()...)
 	}
 
 	for i := range templateSpec.InitContainers {
@@ -243,11 +250,28 @@ func (b *Builder) buildPodSpec(templateSpec corev1.PodSpec) corev1.PodSpec {
 
 		initContainer.VolumeMounts = append(initContainer.VolumeMounts, bundle.Spec.ContainerVolumeMounts...)
 		initContainer.Env = append(initContainer.Env, bundle.Spec.EnvVars...)
+		initContainer.Env = append(initContainer.Env, b.additionalEnvironmentVariables()...)
 	}
 
 	return templateSpec
 }
 
+func (b *Builder) additionalEnvironmentVariables() []corev1.EnvVar {
+	userID := os.Getenv(constants.SystemEnvVarNameUser)
+	timestamp := b.buildTime.Format(time.RFC3339)
+	taskName := fmt.Sprintf("%s_%s", b.namespace, b.profileName)
+
+	envVars := []corev1.EnvVar{
+		{Name: constants.EnvVarNameUserID, Value: userID},
+		{Name: constants.EnvVarTaskName, Value: taskName},
+		{Name: constants.EnvVarTaskID, Value: fmt.Sprintf("%s_%s_%s", userID, timestamp, taskName)},
+		{Name: constants.EnvVarNameProfile, Value: fmt.Sprintf("%s_%s", b.namespace, b.profileName)},
+		{Name: constants.EnvVarNameTimestamp, Value: timestamp},
+	}
+
+	return envVars
+}
+
 func mergeBundles(bundles []v1alpha1.VolumeBundle) v1alpha1.VolumeBundle {
 	var volumeBundle v1alpha1.VolumeBundle
 	for _, b := range bundles {
diff --git a/cmd/experimental/kjobctl/pkg/builder/interactive_builder.go b/cmd/experimental/kjobctl/pkg/builder/interactive_builder.go
index 8170f4eec..2c049b07e 100644
--- a/cmd/experimental/kjobctl/pkg/builder/interactive_builder.go
+++ b/cmd/experimental/kjobctl/pkg/builder/interactive_builder.go
@@ -58,6 +58,11 @@ func (b *interactiveBuilder) build(ctx context.Context) (runtime.Object, error)
 
 	pod.Spec = b.buildPodSpec(pod.Spec)
 
+	if len(pod.Spec.Containers) > 0 {
+		pod.Spec.Containers[0].TTY = true
+		pod.Spec.Containers[0].Stdin = true
+	}
+
 	if len(b.localQueue) > 0 {
 		pod.ObjectMeta.Labels[kueueconstants.QueueLabel] = b.localQueue
 	}
diff --git a/cmd/experimental/kjobctl/pkg/cmd/cmd.go b/cmd/experimental/kjobctl/pkg/cmd/cmd.go
index 0239c02a6..a34143698 100644
--- a/cmd/experimental/kjobctl/pkg/cmd/cmd.go
+++ b/cmd/experimental/kjobctl/pkg/cmd/cmd.go
@@ -74,7 +74,7 @@ func NewKjobctlCmd(o KjobctlOptions) *cobra.Command {
 	cobra.CheckErr(cmd.RegisterFlagCompletionFunc("cluster", completion.ClustersFunc(clientGetter)))
 	cobra.CheckErr(cmd.RegisterFlagCompletionFunc("user", completion.UsersFunc(clientGetter)))
 
-	cmd.AddCommand(create.NewCreateCmd(clientGetter, o.IOStreams))
+	cmd.AddCommand(create.NewCreateCmd(clientGetter, o.IOStreams, o.Clock))
 	cmd.AddCommand(list.NewListCmd(clientGetter, o.IOStreams, o.Clock))
 
 	return cmd
diff --git a/cmd/experimental/kjobctl/pkg/cmd/create/create.go b/cmd/experimental/kjobctl/pkg/cmd/create/create.go
index 07418bc85..688e452be 100644
--- a/cmd/experimental/kjobctl/pkg/cmd/create/create.go
+++ b/cmd/experimental/kjobctl/pkg/cmd/create/create.go
@@ -19,7 +19,9 @@ package create
 import (
 	"context"
 	"errors"
+	"fmt"
 	"strings"
+	"time"
 
 	"github.com/spf13/cobra"
 	corev1 "k8s.io/api/core/v1"
@@ -31,6 +33,11 @@ import (
 	"k8s.io/cli-runtime/pkg/genericiooptions"
 	"k8s.io/cli-runtime/pkg/printers"
 	"k8s.io/client-go/kubernetes/scheme"
+	restclient "k8s.io/client-go/rest"
+	"k8s.io/client-go/tools/remotecommand"
+	"k8s.io/kubectl/pkg/cmd/attach"
+	"k8s.io/kubectl/pkg/cmd/exec"
+	"k8s.io/utils/clock"
 	"k8s.io/utils/ptr"
 
 	"sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1"
@@ -40,7 +47,7 @@ import (
 )
 
 const (
-	createExample = `  # Create job 
+	createJobExample = `  # Create job 
   kjobctl create job \ 
 	--profile my-application-profile  \
 	--cmd "sleep 5" \
@@ -48,20 +55,31 @@ const (
 	--completions 4 \ 
 	--request cpu=500m,ram=4Gi \
 	--localqueue my-local-queue-name`
+	createInteractiveExample = `  # Create interactive 
+  kjobctl create interactive \ 
+	--profile my-application-profile  \
+	--pod-running-timeout 30s \
+	--rm`
 	profileFlagName     = "profile"
 	commandFlagName     = "cmd"
 	parallelismFlagName = "parallelism"
 	completionsFlagName = "completions"
 	requestFlagName     = "request"
 	localQueueFlagName  = "localqueue"
+	podRunningTimeout   = "pod-running-timeout"
 )
 
 var (
-	invalidApplicationProfileModeErr = errors.New("invalid application profile mode")
+	podRunningTimeoutDefault = 1 * time.Minute
 )
 
 type CreateOptions struct {
+	exec.StreamOptions
+
 	PrintFlags *genericclioptions.PrintFlags
+	Config     *restclient.Config
+	Attach     attach.RemoteAttach
+	AttachFunc func(*CreateOptions, *corev1.Container, remotecommand.TerminalSizeQueue, *corev1.Pod) func() error
 
 	DryRunStrategy util.DryRunStrategy
 
@@ -69,11 +87,13 @@ type CreateOptions struct {
 	ProfileName string
 	ModeName    v1alpha1.ApplicationProfileMode
 
-	Command     []string
-	Parallelism *int32
-	Completions *int32
-	Requests    corev1.ResourceList
-	LocalQueue  string
+	Command              []string
+	Parallelism          *int32
+	Completions          *int32
+	Requests             corev1.ResourceList
+	LocalQueue           string
+	PodRunningTimeout    time.Duration
+	RemoveInteractivePod bool
 
 	UserSpecifiedCommand     string
 	UserSpecifiedParallelism int32
@@ -89,66 +109,104 @@ func NewCreateOptions(streams genericiooptions.IOStreams) *CreateOptions {
 	return &CreateOptions{
 		PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
 		IOStreams:  streams,
+		StreamOptions: exec.StreamOptions{
+			IOStreams: streams,
+		},
+		Attach:     &attach.DefaultRemoteAttach{},
+		AttachFunc: defaultAttachFunc,
 	}
 }
 
-func NewCreateCmd(clientGetter util.ClientGetter, streams genericiooptions.IOStreams) *cobra.Command {
+type modeSubcommand struct {
+	ModeName v1alpha1.ApplicationProfileMode
+	Setup    func(subcmd *cobra.Command, o *CreateOptions)
+}
+
+var createModeSubcommands = map[string]modeSubcommand{
+	"job": {
+		ModeName: v1alpha1.JobMode,
+		Setup: func(subcmd *cobra.Command, o *CreateOptions) {
+			subcmd.Use += " [--parallelism PARALLELISM] [--completions COMPLETIONS]"
+			subcmd.Short = "Create a job"
+			subcmd.Example = createJobExample
+			subcmd.Flags().Int32Var(&o.UserSpecifiedParallelism, parallelismFlagName, 0,
+				"Parallelism specifies the maximum desired number of pods the job should run at any given time.")
+			subcmd.Flags().Int32Var(&o.UserSpecifiedCompletions, completionsFlagName, 0,
+				"Completions specifies the desired number of successfully finished pods.")
+		},
+	},
+	"interactive": {
+		ModeName: v1alpha1.InteractiveMode,
+		Setup: func(subcmd *cobra.Command, o *CreateOptions) {
+			subcmd.Use += " [--pod-running-timeout DURATION] [--rm]"
+			subcmd.Short = "Create an interactive shell"
+			subcmd.Example = createInteractiveExample
+			subcmd.Flags().DurationVar(&o.PodRunningTimeout, podRunningTimeout, podRunningTimeoutDefault,
+				"The length of time (like 5s, 2m, or 3h, higher than zero) to wait until at least one pod is running.")
+			subcmd.Flags().BoolVar(&o.RemoveInteractivePod, "rm", false,
+				"Remove pod when interactive session exits.")
+		},
+	},
+}
+
+func NewCreateCmd(clientGetter util.ClientGetter, streams genericiooptions.IOStreams, clock clock.Clock) *cobra.Command {
 	o := NewCreateOptions(streams)
 
 	cmd := &cobra.Command{
-		Use: "create job|interactive" +
-			" --profile APPLICATION_PROFILE_NAME" +
-			" [--cmd COMMAND]" +
-			" [--parallelism PARALLELISM]" +
-			" [--completions COMPLETIONS]" +
-			" [--request RESOURCE_NAME=QUANTITY]" +
-			" [--localqueue LOCAL_QUEUE_NAME]" +
-			" [--dry-run STRATEGY]",
-		DisableFlagsInUseLine: true,
-		Short:                 "Create a resource",
-		Example:               createExample,
-		Args:                  cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
-		ValidArgs:             []string{"job", "interactive"},
-		Run: func(cmd *cobra.Command, args []string) {
-			cobra.CheckErr(o.Complete(clientGetter, cmd, args))
-			cobra.CheckErr(o.Run(cmd.Context(), clientGetter))
-		},
+		Use:     "create",
+		Short:   "Create a task",
+		Example: fmt.Sprintf("%s\n\n%s", createJobExample, createInteractiveExample),
 	}
 
-	o.PrintFlags.AddFlags(cmd)
+	for modeName, modeSubcommand := range createModeSubcommands {
+		subcmd := &cobra.Command{
+			Use: fmt.Sprintf("%s"+
+				" --profile APPLICATION_PROFILE_NAME"+
+				" [--cmd COMMAND]"+
+				" [--request RESOURCE_NAME=QUANTITY]"+
+				" [--localqueue LOCAL_QUEUE_NAME]", modeName),
+			DisableFlagsInUseLine: true,
+			Args:                  cobra.NoArgs,
+			RunE: func(cmd *cobra.Command, args []string) error {
+				cmd.SilenceUsage = true
+
+				err := o.Complete(clientGetter, cmd)
+				if err != nil {
+					return err
+				}
+
+				return o.Run(cmd.Context(), clientGetter, clock.Now())
+			},
+		}
+
+		o.PrintFlags.AddFlags(subcmd)
 
-	cmd.Flags().StringVarP(&o.ProfileName, profileFlagName, "p", "",
-		"Application profile contains a template (with defaults set) for running a specific type of application.")
-	cmd.Flags().StringVar(&o.UserSpecifiedCommand, commandFlagName, "",
-		"Command which is associated with the resource.")
-	cmd.Flags().Int32Var(&o.UserSpecifiedParallelism, parallelismFlagName, 0,
-		"Parallelism specifies the maximum desired number of pods the job should run at any given time.")
-	cmd.Flags().Int32Var(&o.UserSpecifiedCompletions, completionsFlagName, 0,
-		"Completions specifies the desired number of successfully finished pods the.")
-	cmd.Flags().StringToStringVar(&o.UserSpecifiedRequest, requestFlagName, nil,
-		"Request is a set of (resource name, quantity) pairs.")
-	cmd.Flags().StringVar(&o.LocalQueue, localQueueFlagName, "",
-		"Kueue localqueue name which is associated with the resource.")
+		subcmd.Flags().StringVarP(&o.ProfileName, profileFlagName, "p", "",
+			"Application profile contains a template (with defaults set) for running a specific type of application.")
+		subcmd.Flags().StringVar(&o.UserSpecifiedCommand, commandFlagName, "",
+			"Command which is associated with the resource.")
+		subcmd.Flags().StringToStringVar(&o.UserSpecifiedRequest, requestFlagName, nil,
+			"Request is a set of (resource name, quantity) pairs.")
+		subcmd.Flags().StringVar(&o.LocalQueue, localQueueFlagName, "",
+			"Kueue localqueue name which is associated with the resource.")
+		modeSubcommand.Setup(subcmd, o)
 
-	util.AddDryRunFlag(cmd)
+		util.AddDryRunFlag(subcmd)
 
-	_ = cmd.MarkFlagRequired(profileFlagName)
+		_ = cmd.MarkFlagRequired(profileFlagName)
 
-	cobra.CheckErr(cmd.RegisterFlagCompletionFunc(profileFlagName, completion.ApplicationProfileNameFunc(clientGetter)))
-	cobra.CheckErr(cmd.RegisterFlagCompletionFunc(localQueueFlagName, completion.LocalQueueNameFunc(clientGetter)))
+		cobra.CheckErr(subcmd.RegisterFlagCompletionFunc(profileFlagName, completion.ApplicationProfileNameFunc(clientGetter)))
+		cobra.CheckErr(subcmd.RegisterFlagCompletionFunc(localQueueFlagName, completion.LocalQueueNameFunc(clientGetter)))
+
+		cmd.AddCommand(subcmd)
+	}
 
 	return cmd
 }
 
-func (o *CreateOptions) Complete(clientGetter util.ClientGetter, cmd *cobra.Command, args []string) error {
-	switch args[0] {
-	case "job":
-		o.ModeName = v1alpha1.JobMode
-	case "interactive":
-		o.ModeName = v1alpha1.InteractiveMode
-	default:
-		return invalidApplicationProfileModeErr
-	}
+func (o *CreateOptions) Complete(clientGetter util.ClientGetter, cmd *cobra.Command) error {
+	currentSubcommand := createModeSubcommands[cmd.Name()]
+	o.ModeName = currentSubcommand.ModeName
 
 	var err error
 
@@ -161,11 +219,11 @@ func (o *CreateOptions) Complete(clientGetter util.ClientGetter, cmd *cobra.Comm
 		o.Command = strings.Fields(o.UserSpecifiedCommand)
 	}
 
-	if flag := cmd.Flags().Lookup(parallelismFlagName); flag.Changed {
+	if cmd.Flags().Changed(parallelismFlagName) {
 		o.Parallelism = ptr.To(o.UserSpecifiedParallelism)
 	}
 
-	if flag := cmd.Flags().Lookup(completionsFlagName); flag.Changed {
+	if cmd.Flags().Changed(completionsFlagName) {
 		o.Completions = ptr.To(o.UserSpecifiedCompletions)
 	}
 
@@ -180,6 +238,10 @@ func (o *CreateOptions) Complete(clientGetter util.ClientGetter, cmd *cobra.Comm
 		}
 	}
 
+	if cmd.Flags().Changed(podRunningTimeout) && o.PodRunningTimeout <= 0 {
+		return errors.New("--pod-running-timeout must be higher than zero")
+	}
+
 	o.DryRunStrategy, err = util.GetDryRunStrategy(cmd)
 	if err != nil {
 		return err
@@ -197,11 +259,21 @@ func (o *CreateOptions) Complete(clientGetter util.ClientGetter, cmd *cobra.Comm
 
 	o.PrintObj = printer.PrintObj
 
+	o.Config, err = clientGetter.ToRESTConfig()
+	if err != nil {
+		return err
+	}
+
+	err = setKubernetesDefaults(o.Config)
+	if err != nil {
+		return err
+	}
+
 	return nil
 }
 
-func (o *CreateOptions) Run(ctx context.Context, clientGetter util.ClientGetter) error {
-	obj, err := builder.NewBuilder(clientGetter).
+func (o *CreateOptions) Run(ctx context.Context, clientGetter util.ClientGetter, runTime time.Time) error {
+	obj, err := builder.NewBuilder(clientGetter, runTime).
 		WithNamespace(o.Namespace).
 		WithProfileName(o.ProfileName).
 		WithModeName(o.ModeName).
@@ -222,7 +294,17 @@ func (o *CreateOptions) Run(ctx context.Context, clientGetter util.ClientGetter)
 		}
 	}
 
-	return o.PrintObj(obj, o.Out)
+	err = o.PrintObj(obj, o.Out)
+	if err != nil {
+		return err
+	}
+
+	if o.ModeName == v1alpha1.InteractiveMode {
+		pod := obj.(*corev1.Pod)
+		return o.RunInteractivePod(ctx, clientGetter, pod.Name)
+	}
+
+	return nil
 }
 
 func (o *CreateOptions) createObject(ctx context.Context, clientGetter util.ClientGetter, obj runtime.Object) (runtime.Object, error) {
@@ -268,3 +350,84 @@ func (o *CreateOptions) createObject(ctx context.Context, clientGetter util.Clie
 
 	return createdObj, nil
 }
+
+func (o *CreateOptions) RunInteractivePod(ctx context.Context, clientGetter util.ClientGetter, podName string) error {
+	k8sclient, err := clientGetter.K8sClientset()
+	if err != nil {
+		return err
+	}
+
+	if o.RemoveInteractivePod {
+		defer func() {
+			err = k8sclient.CoreV1().Pods(o.Namespace).Delete(ctx, podName, metav1.DeleteOptions{})
+			if err != nil {
+				fmt.Fprintln(o.ErrOut, err.Error())
+			}
+			fmt.Fprintf(o.Out, "pod \"%s\" deleted\n", podName)
+		}()
+	}
+
+	fmt.Fprintf(o.Out, "waiting for pod \"%s\" to be running...\n", podName)
+	err = waitForPodRunning(ctx, k8sclient, o.Namespace, podName, o.PodRunningTimeout)
+	if err != nil {
+		return err
+	}
+
+	pod, err := k8sclient.CoreV1().Pods(o.Namespace).Get(ctx, podName, metav1.GetOptions{})
+	if err != nil {
+		return err
+	}
+
+	err = attachTTY(o, pod)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func attachTTY(o *CreateOptions, pod *corev1.Pod) error {
+	o.Stdin = true
+	o.TTY = true
+	containerToAttach := &pod.Spec.Containers[0]
+	if !containerToAttach.TTY {
+		return fmt.Errorf("error: Unable to use a TTY - container %s did not allocate one", containerToAttach.Name)
+	}
+
+	tty := o.SetupTTY()
+
+	var sizeQueue remotecommand.TerminalSizeQueue
+	if tty.Raw {
+		// this call spawns a goroutine to monitor/update the terminal size
+		sizeQueue = tty.MonitorSize(tty.GetSize())
+
+		// unset p.Err if it was previously set because both stdout and stderr go over p.Out when tty is true
+		o.ErrOut = nil
+	}
+
+	return tty.Safe(o.AttachFunc(o, containerToAttach, sizeQueue, pod))
+}
+
+func defaultAttachFunc(o *CreateOptions, containerToAttach *corev1.Container, sizeQueue remotecommand.TerminalSizeQueue, pod *corev1.Pod) func() error {
+	return func() error {
+		restClient, err := restclient.RESTClientFor(o.Config)
+		if err != nil {
+			return err
+		}
+
+		req := restClient.Post().
+			Resource("pods").
+			Name(pod.Name).
+			Namespace(pod.Namespace).
+			SubResource("attach")
+		req.VersionedParams(&corev1.PodAttachOptions{
+			Container: containerToAttach.Name,
+			Stdin:     o.Stdin,
+			Stdout:    o.Out != nil,
+			Stderr:    o.ErrOut != nil,
+			TTY:       o.TTY,
+		}, scheme.ParameterCodec)
+
+		return o.Attach.Attach(req.URL(), o.Config, o.In, o.Out, o.ErrOut, o.TTY, sizeQueue)
+	}
+}
diff --git a/cmd/experimental/kjobctl/pkg/cmd/create/helpers.go b/cmd/experimental/kjobctl/pkg/cmd/create/helpers.go
new file mode 100644
index 000000000..c59b5826b
--- /dev/null
+++ b/cmd/experimental/kjobctl/pkg/cmd/create/helpers.go
@@ -0,0 +1,68 @@
+/*
+Copyright 2024 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package create
+
+import (
+	"context"
+	"time"
+
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/apimachinery/pkg/util/wait"
+	"k8s.io/client-go/kubernetes"
+	"k8s.io/client-go/rest"
+
+	"sigs.k8s.io/kueue/cmd/experimental/kjobctl/client-go/clientset/versioned/scheme"
+)
+
+// setKubernetesDefaults sets default values on the provided client config for accessing the
+// Kubernetes API or returns an error if any of the defaults are impossible or invalid.
+// copied from https://github.com/kubernetes/kubectl/blob/a6de79e3d40575480caa71a8e5efffeea6587251/pkg/cmd/util/kubectl_match_version.go#L115
+func setKubernetesDefaults(config *rest.Config) error {
+	// This is allowing the GetOptions to be serialized.
+	config.GroupVersion = &schema.GroupVersion{Group: "", Version: "v1"}
+
+	if config.APIPath == "" {
+		config.APIPath = "/api"
+	}
+	if config.NegotiatedSerializer == nil {
+		// This codec factory ensures the resources are not converted. Therefore, resources
+		// will not be round-tripped through internal versions. Defaulting does not happen
+		// on the client.
+		config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
+	}
+	return rest.SetKubernetesDefaults(config)
+}
+
+// return a condition function that indicates whether the given pod is currently running
+func isPodRunning(ctx context.Context, k8sClient kubernetes.Interface, podName, namespace string) wait.ConditionWithContextFunc {
+	return func(ct context.Context) (bool, error) {
+		pod, err := k8sClient.CoreV1().Pods(namespace).Get(ctx, podName, metav1.GetOptions{})
+		if err != nil {
+			return false, err
+		}
+
+		return pod.Status.Phase == corev1.PodRunning, nil
+	}
+}
+
+// Poll up to timeout seconds for pod to enter running state.
+// Returns an error if the pod never enters the running state.
+func waitForPodRunning(ctx context.Context, k8sClient kubernetes.Interface, namespace, podName string, timeout time.Duration) error {
+	return wait.PollUntilContextTimeout(ctx, time.Second, timeout, true, isPodRunning(ctx, k8sClient, podName, namespace))
+}
diff --git a/cmd/experimental/kjobctl/pkg/constants/constants.go b/cmd/experimental/kjobctl/pkg/constants/constants.go
index 868499447..68c22f3f9 100644
--- a/cmd/experimental/kjobctl/pkg/constants/constants.go
+++ b/cmd/experimental/kjobctl/pkg/constants/constants.go
@@ -19,3 +19,15 @@ package constants
 const (
 	ProfileLabel = "kjobctl.x-k8s.io/profile"
 )
+
+const (
+	SystemEnvVarNameUser = "USER"
+)
+
+const (
+	EnvVarNameUserID    = "USER_ID"
+	EnvVarTaskName      = "TASK_NAME"
+	EnvVarTaskID        = "TASK_ID"
+	EnvVarNameProfile   = "PROFILE"
+	EnvVarNameTimestamp = "TIMESTAMP"
+)
diff --git a/cmd/importer/README.md b/cmd/importer/README.md
index 940f3d067..6d4bf1431 100644
--- a/cmd/importer/README.md
+++ b/cmd/importer/README.md
@@ -161,8 +161,8 @@ Make the created image accessible by your cluster.
 (cd cmd/importer/run-in-cluster && kustomize edit set image importer=<image:tag>)
 ```
 You can use the image that you built in step one or one of images published in
-https://gcr.io/k8s-staging-kueue/importer, for example:
-`gcr.io/k8s-staging-kueue/importer:main-latest`
+https://us-central1-docker.pkg.dev/k8s-staging-images/kueue/importer, for example:
+`us-central1-docker.pkg.dev/k8s-staging-images/kueue/importer:main-latest`
 
 3. Update the importer args in `cmd/importer/run-in-cluster/importer.yaml` as needed.
 
diff --git a/cmd/importer/run-in-cluster/kustomization.yaml b/cmd/importer/run-in-cluster/kustomization.yaml
index 8199fb6f9..2e260aa99 100644
--- a/cmd/importer/run-in-cluster/kustomization.yaml
+++ b/cmd/importer/run-in-cluster/kustomization.yaml
@@ -15,6 +15,6 @@ configMapGenerator:
 
 images:
 - name: importer
-  newName: gcr.io/k8s-staging-kueue/importer
+  newName: us-central1-docker.pkg.dev/k8s-staging-images/kueue/importer
 
 namespace: kueue-importer
diff --git a/cmd/kueuectl/app/create/create_clusterqueue.go b/cmd/kueuectl/app/create/create_clusterqueue.go
index 872949f7c..5e261581f 100644
--- a/cmd/kueuectl/app/create/create_clusterqueue.go
+++ b/cmd/kueuectl/app/create/create_clusterqueue.go
@@ -308,7 +308,7 @@ func (o *ClusterQueueOptions) parseResourceGroups() error {
 func parseUserSpecifiedResourceQuotas(resources []string, quotaType string) ([]v1beta1.ResourceGroup, error) {
 	var resourceGroups []v1beta1.ResourceGroup
 
-	regex := regexp.MustCompile(`^(\w+):((\w+[\.-]?)*\/?\w+=\w+;)*(\w+[\.-]?)*\/?\w+=\w+;?$`)
+	regex := regexp.MustCompile(`^([a-z0-9][a-z0-9\-\.]{0,252}):((\w+[\.-]?)*\/?\w+=\w+;)*(\w+[\.-]?)*\/?\w+=\w+;?$`)
 	for _, r := range resources {
 		if !regex.MatchString(r) {
 			return resourceGroups, errInvalidResourcesSpec
diff --git a/config/components/crd/bases/kueue.x-k8s.io_cohorts.yaml b/config/components/crd/bases/kueue.x-k8s.io_cohorts.yaml
new file mode 100644
index 000000000..7be19cb00
--- /dev/null
+++ b/config/components/crd/bases/kueue.x-k8s.io_cohorts.yaml
@@ -0,0 +1,287 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.15.0
+  name: cohorts.kueue.x-k8s.io
+spec:
+  group: kueue.x-k8s.io
+  names:
+    kind: Cohort
+    listKind: CohortList
+    plural: cohorts
+    singular: cohort
+  scope: Cluster
+  versions:
+  - name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        description: Cohort is the Schema for the cohorts API
+        properties:
+          apiVersion:
+            description: |-
+              APIVersion defines the versioned schema of this representation of an object.
+              Servers should convert recognized schemas to the latest internal value, and
+              may reject unrecognized values.
+              More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
+            type: string
+          kind:
+            description: |-
+              Kind is a string value representing the REST resource this object represents.
+              Servers may infer this from the endpoint the client submits requests to.
+              Cannot be updated.
+              In CamelCase.
+              More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: CohortSpec defines the desired state of Cohort
+            properties:
+              parent:
+                description: |-
+                  Parent references the name of the Cohort's parent, if
+                  any. It satisfies one of three cases:
+                  1) Unset. This Cohort is the root of its Cohort tree.
+                  2) References a non-existent Cohort. We use default Cohort (no borrowing/lending limits).
+                  3) References an existent Cohort.
+
+
+                  If a cycle is created, we disable all members of the
+                  Cohort, including ClusterQueues, until the cycle is
+                  removed.  We prevent further admission while the cycle
+                  exists.
+                maxLength: 253
+                pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                type: string
+              resourceGroups:
+                description: |-
+                  ResourceGroups describes groupings of Resources and
+                  Flavors.  Each ResourceGroup defines a list of Resources
+                  and a list of Flavors which provide quotas for these
+                  Resources. Each Resource and each Flavor may only form part
+                  of one ResourceGroup.  There may be up to 16 ResourceGroups
+                  within a Cohort.
+
+
+                  BorrowingLimit limits how much members of this Cohort
+                  subtree can borrow from the parent subtree.
+
+
+                  LendingLimit limits how much members of this Cohort subtree
+                  can lend to the parent subtree.
+
+
+                  Borrowing and Lending limits must only be set when the
+                  Cohort has a parent.  Otherwise, the Cohort create/update
+                  will be rejected by the webhook.
+                items:
+                  properties:
+                    coveredResources:
+                      description: |-
+                        coveredResources is the list of resources covered by the flavors in this
+                        group.
+                        Examples: cpu, memory, vendor.com/gpu.
+                        The list cannot be empty and it can contain up to 16 resources.
+                      items:
+                        description: ResourceName is the name identifying various
+                          resources in a ResourceList.
+                        type: string
+                      maxItems: 16
+                      minItems: 1
+                      type: array
+                    flavors:
+                      description: |-
+                        flavors is the list of flavors that provide the resources of this group.
+                        Typically, different flavors represent different hardware models
+                        (e.g., gpu models, cpu architectures) or pricing models (on-demand vs spot
+                        cpus).
+                        Each flavor MUST list all the resources listed for this group in the same
+                        order as the .resources field.
+                        The list cannot be empty and it can contain up to 16 flavors.
+                      items:
+                        properties:
+                          name:
+                            description: |-
+                              name of this flavor. The name should match the .metadata.name of a
+                              ResourceFlavor. If a matching ResourceFlavor does not exist, the
+                              ClusterQueue will have an Active condition set to False.
+                            maxLength: 253
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                            type: string
+                          resources:
+                            description: |-
+                              resources is the list of quotas for this flavor per resource.
+                              There could be up to 16 resources.
+                            items:
+                              properties:
+                                borrowingLimit:
+                                  anyOf:
+                                  - type: integer
+                                  - type: string
+                                  description: |-
+                                    borrowingLimit is the maximum amount of quota for the [flavor, resource]
+                                    combination that this ClusterQueue is allowed to borrow from the unused
+                                    quota of other ClusterQueues in the same cohort.
+                                    In total, at a given time, Workloads in a ClusterQueue can consume a
+                                    quantity of quota equal to nominalQuota+borrowingLimit, assuming the other
+                                    ClusterQueues in the cohort have enough unused quota.
+                                    If null, it means that there is no borrowing limit.
+                                    If not null, it must be non-negative.
+                                    borrowingLimit must be null if spec.cohort is empty.
+                                  pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+                                  x-kubernetes-int-or-string: true
+                                lendingLimit:
+                                  anyOf:
+                                  - type: integer
+                                  - type: string
+                                  description: |-
+                                    lendingLimit is the maximum amount of unused quota for the [flavor, resource]
+                                    combination that this ClusterQueue can lend to other ClusterQueues in the same cohort.
+                                    In total, at a given time, ClusterQueue reserves for its exclusive use
+                                    a quantity of quota equals to nominalQuota - lendingLimit.
+                                    If null, it means that there is no lending limit, meaning that
+                                    all the nominalQuota can be borrowed by other clusterQueues in the cohort.
+                                    If not null, it must be non-negative.
+                                    lendingLimit must be null if spec.cohort is empty.
+                                    This field is in alpha stage. To be able to use this field,
+                                    enable the feature gate LendingLimit, which is disabled by default.
+                                  pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+                                  x-kubernetes-int-or-string: true
+                                name:
+                                  description: name of this resource.
+                                  type: string
+                                nominalQuota:
+                                  anyOf:
+                                  - type: integer
+                                  - type: string
+                                  description: |-
+                                    nominalQuota is the quantity of this resource that is available for
+                                    Workloads admitted by this ClusterQueue at a point in time.
+                                    The nominalQuota must be non-negative.
+                                    nominalQuota should represent the resources in the cluster available for
+                                    running jobs (after discounting resources consumed by system components
+                                    and pods not managed by kueue). In an autoscaled cluster, nominalQuota
+                                    should account for resources that can be provided by a component such as
+                                    Kubernetes cluster-autoscaler.
+
+
+                                    If the ClusterQueue belongs to a cohort, the sum of the quotas for each
+                                    (flavor, resource) combination defines the maximum quantity that can be
+                                    allocated by a ClusterQueue in the cohort.
+                                  pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+                                  x-kubernetes-int-or-string: true
+                              required:
+                              - name
+                              - nominalQuota
+                              type: object
+                            maxItems: 16
+                            minItems: 1
+                            type: array
+                            x-kubernetes-list-map-keys:
+                            - name
+                            x-kubernetes-list-type: map
+                        required:
+                        - name
+                        - resources
+                        type: object
+                      maxItems: 16
+                      minItems: 1
+                      type: array
+                      x-kubernetes-list-map-keys:
+                      - name
+                      x-kubernetes-list-type: map
+                  required:
+                  - coveredResources
+                  - flavors
+                  type: object
+                  x-kubernetes-validations:
+                  - message: flavors must have the same number of resources as the
+                      coveredResources
+                    rule: self.flavors.all(x, size(x.resources) == size(self.coveredResources))
+                maxItems: 16
+                type: array
+                x-kubernetes-list-type: atomic
+            type: object
+          status:
+            description: CohortStatus defines the observed state of Cohort
+            properties:
+              conditions:
+                items:
+                  description: "Condition contains details for one aspect of the current
+                    state of this API Resource.\n---\nThis struct is intended for
+                    direct use as an array at the field path .status.conditions.  For
+                    example,\n\n\n\ttype FooStatus struct{\n\t    // Represents the
+                    observations of a foo's current state.\n\t    // Known .status.conditions.type
+                    are: \"Available\", \"Progressing\", and \"Degraded\"\n\t    //
+                    +patchMergeKey=type\n\t    // +patchStrategy=merge\n\t    // +listType=map\n\t
+                    \   // +listMapKey=type\n\t    Conditions []metav1.Condition `json:\"conditions,omitempty\"
+                    patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t
+                    \   // other fields\n\t}"
+                  properties:
+                    lastTransitionTime:
+                      description: |-
+                        lastTransitionTime is the last time the condition transitioned from one status to another.
+                        This should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.
+                      format: date-time
+                      type: string
+                    message:
+                      description: |-
+                        message is a human readable message indicating details about the transition.
+                        This may be an empty string.
+                      maxLength: 32768
+                      type: string
+                    observedGeneration:
+                      description: |-
+                        observedGeneration represents the .metadata.generation that the condition was set based upon.
+                        For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
+                        with respect to the current state of the instance.
+                      format: int64
+                      minimum: 0
+                      type: integer
+                    reason:
+                      description: |-
+                        reason contains a programmatic identifier indicating the reason for the condition's last transition.
+                        Producers of specific condition types may define expected values and meanings for this field,
+                        and whether the values are considered a guaranteed API.
+                        The value should be a CamelCase string.
+                        This field may not be empty.
+                      maxLength: 1024
+                      minLength: 1
+                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+                      type: string
+                    status:
+                      description: status of the condition, one of True, False, Unknown.
+                      enum:
+                      - "True"
+                      - "False"
+                      - Unknown
+                      type: string
+                    type:
+                      description: |-
+                        type of condition in CamelCase or in foo.example.com/CamelCase.
+                        ---
+                        Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be
+                        useful (see .node.status.conditions), the ability to deconflict is important.
+                        The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
+                      maxLength: 316
+                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - message
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+                x-kubernetes-list-map-keys:
+                - type
+                x-kubernetes-list-type: map
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
diff --git a/config/components/manager/kustomization.yaml b/config/components/manager/kustomization.yaml
index b7b7487da..b124989ab 100644
--- a/config/components/manager/kustomization.yaml
+++ b/config/components/manager/kustomization.yaml
@@ -16,5 +16,5 @@ apiVersion: kustomize.config.k8s.io/v1beta1
 kind: Kustomization
 images:
 - name: controller
-  newName: gcr.io/k8s-staging-kueue/kueue
+  newName: us-central1-docker.pkg.dev/k8s-staging-images/kueue/kueue
   newTag: main
diff --git a/go.mod b/go.mod
index 963d8330f..ee7220c0e 100644
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,7 @@ require (
 	github.com/go-logr/logr v1.4.2
 	github.com/google/go-cmp v0.6.0
 	github.com/kubeflow/mpi-operator v0.5.0
-	github.com/kubeflow/training-operator v1.7.0
+	github.com/kubeflow/training-operator v1.8.0
 	github.com/onsi/ginkgo/v2 v2.19.0
 	github.com/onsi/gomega v1.33.1
 	github.com/open-policy-agent/cert-controller v0.10.1
@@ -16,17 +16,17 @@ require (
 	github.com/ray-project/kuberay/ray-operator v1.1.1
 	github.com/spf13/cobra v1.8.1
 	go.uber.org/zap v1.27.0
-	k8s.io/api v0.30.2
-	k8s.io/apimachinery v0.30.2
-	k8s.io/apiserver v0.29.6
+	k8s.io/api v0.30.3
+	k8s.io/apimachinery v0.30.3
+	k8s.io/apiserver v0.29.7
 	k8s.io/autoscaler/cluster-autoscaler/apis v0.0.0-20240325113845-0130d33747bb
-	k8s.io/cli-runtime v0.29.6
-	k8s.io/client-go v0.29.6
-	k8s.io/component-base v0.29.6
-	k8s.io/component-helpers v0.29.6
+	k8s.io/cli-runtime v0.29.7
+	k8s.io/client-go v0.29.7
+	k8s.io/component-base v0.29.7
+	k8s.io/component-helpers v0.29.7
 	k8s.io/klog/v2 v2.120.1
 	k8s.io/kube-openapi v0.0.0-20240521193020-835d969ad83a
-	k8s.io/metrics v0.29.6
+	k8s.io/metrics v0.29.7
 	k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0
 	sigs.k8s.io/controller-runtime v0.17.3
 	sigs.k8s.io/jobset v0.5.2
@@ -131,10 +131,10 @@ require (
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 	k8s.io/apiextensions-apiserver v0.29.2 // indirect
-	k8s.io/code-generator v0.29.6 // indirect
+	k8s.io/code-generator v0.29.7 // indirect
 	k8s.io/gengo v0.0.0-20240404160639-a0386bf69313 // indirect
 	k8s.io/gengo/v2 v2.0.0-20240404160639-a0386bf69313 // indirect
-	k8s.io/kms v0.29.6 // indirect
+	k8s.io/kms v0.29.7 // indirect
 	sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 // indirect
 	sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
 	sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect
diff --git a/go.sum b/go.sum
index 41a248879..3b19574b0 100644
--- a/go.sum
+++ b/go.sum
@@ -148,8 +148,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/kubeflow/mpi-operator v0.5.0 h1:XvBwyXXQ9103DNMa22sxsaQlaktvaT2LY/g0UniGn5U=
 github.com/kubeflow/mpi-operator v0.5.0/go.mod h1:SeZQJW8KJxSTWD++eQYKRFpoDg1v8yrdC6fjx2/3mG0=
-github.com/kubeflow/training-operator v1.7.0 h1:Zh61GlOWrlRi4UFOtJeV+/5REo/OndhwQ25KYd0llzc=
-github.com/kubeflow/training-operator v1.7.0/go.mod h1:BZCLX1h06wY3YSeSZZcGYAqI9/nVi7isVCRkfgZe9nE=
+github.com/kubeflow/training-operator v1.8.0 h1:cHXIz7BV3Ayp7W5Rqe20/ukmVEzraI+O/XRYKBHQcrg=
+github.com/kubeflow/training-operator v1.8.0/go.mod h1:T6I15h1S09ncH5C6St/QEC7Dy6dpHZA5sPFo+VoJAvE=
 github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
 github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
 github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
@@ -383,26 +383,26 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-k8s.io/api v0.30.2 h1:+ZhRj+28QT4UOH+BKznu4CBgPWgkXO7XAvMcMl0qKvI=
-k8s.io/api v0.30.2/go.mod h1:ULg5g9JvOev2dG0u2hig4Z7tQ2hHIuS+m8MNZ+X6EmI=
+k8s.io/api v0.30.3 h1:ImHwK9DCsPA9uoU3rVh4QHAHHK5dTSv1nxJUapx8hoQ=
+k8s.io/api v0.30.3/go.mod h1:GPc8jlzoe5JG3pb0KJCSLX5oAFIW3/qNJITlDj8BH04=
 k8s.io/apiextensions-apiserver v0.29.2 h1:UK3xB5lOWSnhaCk0RFZ0LUacPZz9RY4wi/yt2Iu+btg=
 k8s.io/apiextensions-apiserver v0.29.2/go.mod h1:aLfYjpA5p3OwtqNXQFkhJ56TB+spV8Gc4wfMhUA3/b8=
-k8s.io/apimachinery v0.30.2 h1:fEMcnBj6qkzzPGSVsAZtQThU62SmQ4ZymlXRC5yFSCg=
-k8s.io/apimachinery v0.30.2/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
-k8s.io/apiserver v0.29.6 h1:JxgDbpgahOgqoDOf+zVl2mI+rQcHcLQnK6YhhtsjbNs=
-k8s.io/apiserver v0.29.6/go.mod h1:HrQwfPWxhwEa+n8/+5YwSF5yT2WXbeyFjqq6KEXHTX8=
+k8s.io/apimachinery v0.30.3 h1:q1laaWCmrszyQuSQCfNB8cFgCuDAoPszKY4ucAjDwHc=
+k8s.io/apimachinery v0.30.3/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
+k8s.io/apiserver v0.29.7 h1:yvdZAZJ6Bmih8Iu8CqUB74otyPP0OM3XKzYzAFiWsY4=
+k8s.io/apiserver v0.29.7/go.mod h1:MjEld3ySZrQ4eOzf6OKANT/v8GvM3sb1e5vozXoIirs=
 k8s.io/autoscaler/cluster-autoscaler/apis v0.0.0-20240325113845-0130d33747bb h1:ycQ/tSpcJEUHHx0pv6MXdq4NcRflCvFX6SMwmKROiis=
 k8s.io/autoscaler/cluster-autoscaler/apis v0.0.0-20240325113845-0130d33747bb/go.mod h1:LPhCVj3E5Lp9W6HGVlW664m/X+KN2firfF3wtBBji54=
-k8s.io/cli-runtime v0.29.6 h1:nPbmS6ICW223S0BWTV+sK5xClWe89QB/n16/c5cJwT8=
-k8s.io/cli-runtime v0.29.6/go.mod h1:5BzzwnVhtqVJvatDZmSZ6OtiSGqbdn0hKzpRbV3uf5o=
-k8s.io/client-go v0.29.6 h1:5E2ebuB/p0F0THuQatyvhDvPL2SIeqwTPrtnrwKob/8=
-k8s.io/client-go v0.29.6/go.mod h1:jHZcrQqDplyv20v7eu+iFM4gTpglZSZoMVcKrh8sRGg=
-k8s.io/code-generator v0.29.6 h1:Z8T9VMR0mr7V5GG66c6GVAZrIiEy2uFoQwbeVeWLqPA=
-k8s.io/code-generator v0.29.6/go.mod h1:7TYnI0dYItL2cKuhhgPSuF3WED9uMdELgbVXFfn/joE=
-k8s.io/component-base v0.29.6 h1:XkVJI67FvBgNb/3kKqvaGKokxUrIR0RrksCPNI+JYCs=
-k8s.io/component-base v0.29.6/go.mod h1:kIahZm8aw9lV8Vw17LF89REmeBrv5+QEl3v7HsrmITY=
-k8s.io/component-helpers v0.29.6 h1:kG/tK0gXPXj6n3Oxn5Eul8nYzer3SejZI3ClwiWkreQ=
-k8s.io/component-helpers v0.29.6/go.mod h1:Ltb44cbXci9fy9rytWwYsu8vHfi4fjyQdSwk6UlCR4E=
+k8s.io/cli-runtime v0.29.7 h1:6IxyxaIm3N31+PKXb1K7Tpf+100mm9hd9HMMYWMH2QE=
+k8s.io/cli-runtime v0.29.7/go.mod h1:0pcclC4k3rkzYNAvw3zeiPNtg8Buv0orK+5MuhEKFBU=
+k8s.io/client-go v0.29.7 h1:vTtiFrGBKlcBhxaeZC4eDrqui1e108nsTyue/KU63IY=
+k8s.io/client-go v0.29.7/go.mod h1:69BvVqdRozgR/9TP45u/oO0tfrdbP+I8RqrcCJQshzg=
+k8s.io/code-generator v0.29.7 h1:NEwmKOJVNObCh3upBLEojL1QuJMzGplOTYZnee4h0TY=
+k8s.io/code-generator v0.29.7/go.mod h1:7TYnI0dYItL2cKuhhgPSuF3WED9uMdELgbVXFfn/joE=
+k8s.io/component-base v0.29.7 h1:zXLJvZjvvDWdYmZCwZYk95E1Fd2oRXUz71mQukkRk5I=
+k8s.io/component-base v0.29.7/go.mod h1:ddLTpIrjazaRI1EG83M41GNcYEAdskuQmx4JOOSXCOg=
+k8s.io/component-helpers v0.29.7 h1:zLFeGg/Ab6QRC69xv08Syfnzc9ghgccp0gr5okb/r6M=
+k8s.io/component-helpers v0.29.7/go.mod h1:fBB9g4OrGCxo2+px6+kU4BPQ56WnBbL8n2NY6jIaMNY=
 k8s.io/gengo v0.0.0-20240404160639-a0386bf69313 h1:wBIDZID8ju9pwOiLlV22YYKjFGtiNSWgHf5CnKLRUuM=
 k8s.io/gengo v0.0.0-20240404160639-a0386bf69313/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
 k8s.io/gengo/v2 v2.0.0-20240404160639-a0386bf69313 h1:bKcdZJOPICVmIIuaM9+MXmapE94dn5AYv5ODs1jA43o=
@@ -410,14 +410,14 @@ k8s.io/gengo/v2 v2.0.0-20240404160639-a0386bf69313/go.mod h1:VH3AT8AaQOqiGjMF9p0
 k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
 k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
 k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
-k8s.io/kms v0.29.6 h1:Aa+4zZDqUaFacjNGzCHIC0ilqnEhA1qHqvyn9igirPQ=
-k8s.io/kms v0.29.6/go.mod h1:vWVImKkJd+1BQY4tBwdfSwjQBiLrnbNtHADcDEDQFtk=
+k8s.io/kms v0.29.7 h1:4ELQdx7T4EPKbN/QMj6SeZizrEKapza5YF8e5XtZPv0=
+k8s.io/kms v0.29.7/go.mod h1:vWVImKkJd+1BQY4tBwdfSwjQBiLrnbNtHADcDEDQFtk=
 k8s.io/kube-aggregator v0.28.1 h1:rvG4llYnQKHjj6YjjoBPEJxfD1uH0DJwkrJTNKGAaCs=
 k8s.io/kube-aggregator v0.28.1/go.mod h1:JaLizMe+AECSpO2OmrWVsvnG0V3dX1RpW+Wq/QHbu18=
 k8s.io/kube-openapi v0.0.0-20240521193020-835d969ad83a h1:zD1uj3Jf+mD4zmA7W+goE5TxDkI7OGJjBNBzq5fJtLA=
 k8s.io/kube-openapi v0.0.0-20240521193020-835d969ad83a/go.mod h1:UxDHUPsUwTOOxSU+oXURfFBcAS6JwiRXTYqYwfuGowc=
-k8s.io/metrics v0.29.6 h1:kjMGPYxtCi4OO0fUar76y0CiUoeGYDNmUV0LXJIis4Q=
-k8s.io/metrics v0.29.6/go.mod h1:vqGzOaYGuNSSAI7GM1+v6L5z8aAUSzui1W0eQB3wVJY=
+k8s.io/metrics v0.29.7 h1:/oMPdVL7dt+lF8W6lXTg9gIKz1dDKgVBfDnJwgyJrhk=
+k8s.io/metrics v0.29.7/go.mod h1:5AiYPn1Crd25wtTh7OxHg9Rm2t9THSXJVp3Lb2k7MB8=
 k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 h1:jgGTlFYnhF1PM1Ax/lAlxUPE+KfCIXHaathvJg1C3ak=
 k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 h1:2770sDpzrjjsAtVhSeUFseziht227YAWYHLGNM8QPwY=
diff --git a/hack/dump_cache.sh b/hack/dump_cache.sh
index 007469d53..33668a2a3 100755
--- a/hack/dump_cache.sh
+++ b/hack/dump_cache.sh
@@ -22,7 +22,7 @@ set -o pipefail
 
 NAMESPACE=${NAMESPACE:-kueue-system}
 LEASE_NAME=${LEASE_NAME:-c1f6bfd2.kueue.x-k8s.io}
-DEBUG_IMAGE=${DEBUG_IMAGE:-gcr.io/k8s-staging-kueue/debug:main}
+DEBUG_IMAGE=${DEBUG_IMAGE:-us-central1-docker.pkg.dev/k8s-staging-images/kueue/debug:main}
 
 leader=$(kubectl get lease -n ${NAMESPACE} ${LEASE_NAME} -o jsonpath='{.spec.holderIdentity}' | cut -d '_' -f 1)
 
diff --git a/hack/generate_krew.sh b/hack/generate_krew.sh
index 9c46e844a..cb83ad730 100755
--- a/hack/generate_krew.sh
+++ b/hack/generate_krew.sh
@@ -18,50 +18,8 @@ set -o errexit
 set -o nounset
 set -o pipefail
 
-# This script generates a Krew-compatible plugin manifest.
+# Resolve the absolute path of the directory containing the script
+SCRIPT_DIR=$(realpath "$(dirname "${BASH_SOURCE[0]}")")
+REPO_ROOT="$SCRIPT_DIR/.."
 
-VERSION=${VERSION:-$(git describe --tags | sed 's/^v//g')}
-
-# Generate the manifest for a single platform.
-function generate_platform {
-    cat <<EOF
-  - selector:
-      matchLabels:
-        os: "${1}"
-        arch: "${2}"
-    uri: https://github.com/kubernetes-sigs/kueue/releases/download/v${VERSION}/kubectl-kueue-${1}-${2}.tar.gz
-    sha256: $(curl -L https://github.com/kubernetes-sigs/kueue/releases/download/v${VERSION}/kubectl-kueue-${1}-${2}.tar.gz | shasum -a 256 - | awk '{print $1}')
-    bin: "${3}"
-    files:
-    - from: "*"
-      to: "."
-EOF
-}
-
-# shellcheck disable=SC2129
-cat <<EOF > kueue.yaml
-apiVersion: krew.googlecontainertools.github.com/v1alpha2
-kind: Plugin
-metadata:
-  name: kueue
-spec:
-  version: "v${VERSION}"
-  shortDescription: Controls Kueue queueing manager.
-  homepage: https://kueue.sigs.k8s.io/docs/reference/kubectl-kueue/
-  description: |
-    The kubectl-kueue plugin, kueuectl, allows you to list, create, resume
-    and stop kueue resources such as clusterqueues, localqueues and workloads.
-
-    See the documentation for more information: https://kueue.sigs.k8s.io/docs/reference/kubectl-kueue/
-  caveats: |
-    Requires the Kueue operator to be installed:
-      https://kueue.sigs.k8s.io/docs/installation/
-  platforms:
-EOF
-
-generate_platform linux amd64 ./kubectl-kueue >> kueue.yaml
-generate_platform linux arm64 ./kubectl-kueue >> kueue.yaml
-generate_platform darwin amd64 ./kubectl-kueue >> kueue.yaml
-generate_platform darwin arm64 ./kubectl-kueue >> kueue.yaml
-
-echo "To publish to the krew index, create a pull request on https://github.com/kubernetes-sigs/krew-index/tree/master/plugins to update kueue.yaml with the newly generated kueue.yaml."
\ No newline at end of file
+docker run --rm -v "$REPO_ROOT":/home/app ghcr.io/rajatjindal/krew-release-bot:v0.0.46 krew-release-bot template --tag "$1" --template-file .krew.yaml > "$REPO_ROOT"/kueue.yaml
\ No newline at end of file
diff --git a/hack/internal/tools/go.mod b/hack/internal/tools/go.mod
index e6ebab425..d4fedcf91 100644
--- a/hack/internal/tools/go.mod
+++ b/hack/internal/tools/go.mod
@@ -3,7 +3,7 @@ module sigs.k8s.io/kueue/internal/tools
 go 1.22.4
 
 require (
-	github.com/gohugoio/hugo v0.128.2
+	github.com/gohugoio/hugo v0.129.0
 	github.com/golangci/golangci-lint v1.59.1
 	github.com/mikefarah/yq/v4 v4.44.2
 	github.com/onsi/ginkgo/v2 v2.19.0
@@ -11,8 +11,8 @@ require (
 	github.com/spf13/pflag v1.0.5
 	gotest.tools/gotestsum v1.12.0
 	helm.sh/helm/v3 v3.15.3
-	k8s.io/code-generator v0.30.2
-	k8s.io/component-base v0.30.2
+	k8s.io/code-generator v0.30.3
+	k8s.io/component-base v0.30.3
 	sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20240605185440-12cc8d59fabe
 	sigs.k8s.io/controller-tools v0.15.0
 	sigs.k8s.io/kind v0.23.0
@@ -119,12 +119,12 @@ require (
 	gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
-	k8s.io/api v0.30.2 // indirect
+	k8s.io/api v0.30.3 // indirect
 	k8s.io/apiextensions-apiserver v0.30.1 // indirect
-	k8s.io/apimachinery v0.30.2 // indirect
+	k8s.io/apimachinery v0.30.3 // indirect
 	k8s.io/apiserver v0.30.1 // indirect
 	k8s.io/cli-runtime v0.30.0 // indirect
-	k8s.io/client-go v0.30.2 // indirect
+	k8s.io/client-go v0.30.3 // indirect
 	k8s.io/gengo/v2 v2.0.0-20240404160639-a0386bf69313 // indirect
 	k8s.io/klog/v2 v2.120.1 // indirect
 	k8s.io/kube-openapi v0.0.0-20240521193020-835d969ad83a // indirect
diff --git a/hack/internal/tools/go.sum b/hack/internal/tools/go.sum
index faf8c5210..1c32b9c65 100644
--- a/hack/internal/tools/go.sum
+++ b/hack/internal/tools/go.sum
@@ -95,8 +95,8 @@ github.com/goccy/go-yaml v1.11.3 h1:B3W9IdWbvrUu2OYQGwvU1nZtvMQJPBKgBUuweJjLj6I=
 github.com/goccy/go-yaml v1.11.3/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU=
 github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
-github.com/gohugoio/hugo v0.128.2 h1:VEQ5HqqCG881q1c9VBrt4NyqrSb+1SHMzoX+KzweWe4=
-github.com/gohugoio/hugo v0.128.2/go.mod h1:Fe6p5/9TZ35+272Mjj0Q5WAOvmKGNWOhaoZhoQgJCCA=
+github.com/gohugoio/hugo v0.129.0 h1:AWyne6qC/fg/XNTLHpuaefXHkukzAWBmSkersovh8tI=
+github.com/gohugoio/hugo v0.129.0/go.mod h1:PBbF9ucsywUwysYkwUEYfK5IWH045VVdxKz7KZ7kYyY=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
 github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -465,22 +465,22 @@ helm.sh/helm/v3 v3.15.3 h1:HcZDaVFe9uHa6hpsR54mJjYyRy4uz/pc6csg27nxFOc=
 helm.sh/helm/v3 v3.15.3/go.mod h1:FzSIP8jDQaa6WAVg9F+OkKz7J0ZmAga4MABtTbsb9WQ=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-k8s.io/api v0.30.2 h1:+ZhRj+28QT4UOH+BKznu4CBgPWgkXO7XAvMcMl0qKvI=
-k8s.io/api v0.30.2/go.mod h1:ULg5g9JvOev2dG0u2hig4Z7tQ2hHIuS+m8MNZ+X6EmI=
+k8s.io/api v0.30.3 h1:ImHwK9DCsPA9uoU3rVh4QHAHHK5dTSv1nxJUapx8hoQ=
+k8s.io/api v0.30.3/go.mod h1:GPc8jlzoe5JG3pb0KJCSLX5oAFIW3/qNJITlDj8BH04=
 k8s.io/apiextensions-apiserver v0.30.1 h1:4fAJZ9985BmpJG6PkoxVRpXv9vmPUOVzl614xarePws=
 k8s.io/apiextensions-apiserver v0.30.1/go.mod h1:R4GuSrlhgq43oRY9sF2IToFh7PVlF1JjfWdoG3pixk4=
-k8s.io/apimachinery v0.30.2 h1:fEMcnBj6qkzzPGSVsAZtQThU62SmQ4ZymlXRC5yFSCg=
-k8s.io/apimachinery v0.30.2/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
+k8s.io/apimachinery v0.30.3 h1:q1laaWCmrszyQuSQCfNB8cFgCuDAoPszKY4ucAjDwHc=
+k8s.io/apimachinery v0.30.3/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
 k8s.io/apiserver v0.30.1 h1:BEWEe8bzS12nMtDKXzCF5Q5ovp6LjjYkSp8qOPk8LZ8=
 k8s.io/apiserver v0.30.1/go.mod h1:i87ZnQ+/PGAmSbD/iEKM68bm1D5reX8fO4Ito4B01mo=
 k8s.io/cli-runtime v0.30.0 h1:0vn6/XhOvn1RJ2KJOC6IRR2CGqrpT6QQF4+8pYpWQ48=
 k8s.io/cli-runtime v0.30.0/go.mod h1:vATpDMATVTMA79sZ0YUCzlMelf6rUjoBzlp+RnoM+cg=
-k8s.io/client-go v0.30.2 h1:sBIVJdojUNPDU/jObC+18tXWcTJVcwyqS9diGdWHk50=
-k8s.io/client-go v0.30.2/go.mod h1:JglKSWULm9xlJLx4KCkfLLQ7XwtlbflV6uFFSHTMgVs=
-k8s.io/code-generator v0.30.2 h1:ZY1+aGkqZVwKIyGsOzquaeZ5rSfE6wZHur8z3jQAaiw=
-k8s.io/code-generator v0.30.2/go.mod h1:RQP5L67QxqgkVquk704CyvWFIq0e6RCMmLTXxjE8dVA=
-k8s.io/component-base v0.30.2 h1:pqGBczYoW1sno8q9ObExUqrYSKhtE5rW3y6gX88GZII=
-k8s.io/component-base v0.30.2/go.mod h1:yQLkQDrkK8J6NtP+MGJOws+/PPeEXNpwFixsUI7h/OE=
+k8s.io/client-go v0.30.3 h1:bHrJu3xQZNXIi8/MoxYtZBBWQQXwy16zqJwloXXfD3k=
+k8s.io/client-go v0.30.3/go.mod h1:8d4pf8vYu665/kUbsxWAQ/JDBNWqfFeZnvFiVdmx89U=
+k8s.io/code-generator v0.30.3 h1:bmtnLJKagDS5f5uOEpLyJiDfIMKXGMKgOLBdde+w0Mc=
+k8s.io/code-generator v0.30.3/go.mod h1:PFgBiv+miFV7TZYp+RXgROkhA+sWYZ+mtpbMLofMke8=
+k8s.io/component-base v0.30.3 h1:Ci0UqKWf4oiwy8hr1+E3dsnliKnkMLZMVbWzeorlk7s=
+k8s.io/component-base v0.30.3/go.mod h1:C1SshT3rGPCuNtBs14RmVD2xW0EhRSeLvBh7AGk1quA=
 k8s.io/gengo/v2 v2.0.0-20240404160639-a0386bf69313 h1:bKcdZJOPICVmIIuaM9+MXmapE94dn5AYv5ODs1jA43o=
 k8s.io/gengo/v2 v2.0.0-20240404160639-a0386bf69313/go.mod h1:VH3AT8AaQOqiGjMF9p0/IM1Dj+82ZwjfxUP1IxaHE+8=
 k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
diff --git a/hack/multiplatform-build.sh b/hack/multiplatform-build.sh
index 6425db3f7..fe674d4f3 100755
--- a/hack/multiplatform-build.sh
+++ b/hack/multiplatform-build.sh
@@ -45,9 +45,9 @@ for PLATFORM in ${PLATFORMS} ; do
   FULL_NAME=${BUILD_NAME}-${GOOS}-${GOARCH}
   ${GO_BUILD_ENV} ${GO_CMD} build -ldflags="${LD_FLAGS}" -o ${BUILD_PATH}/${FULL_NAME}${EXTENSION} $1
 
-  mkdir -p ${BUILD_PATH}/tmp/${FULL_NAME}
-  cp ${ROOT_PATH}/LICENSE ${BUILD_PATH}/tmp/${FULL_NAME}
-  cp ${BUILD_PATH}/${FULL_NAME}${EXTENSION} ${BUILD_PATH}/tmp/${FULL_NAME}/${BUILD_NAME}${EXTENSION}
-  (cd ${BUILD_PATH}/tmp && tar -czf ${BUILD_PATH}/${FULL_NAME}.tar.gz ${FULL_NAME})
+  mkdir -p ${BUILD_PATH}/tmp
+  cp ${ROOT_PATH}/LICENSE ${BUILD_PATH}/tmp
+  cp ${BUILD_PATH}/${FULL_NAME}${EXTENSION} ${BUILD_PATH}/tmp/${BUILD_NAME}${EXTENSION}
+  (cd ${BUILD_PATH}/tmp && tar -czf ${BUILD_PATH}/${FULL_NAME}.tar.gz *)
   rm -R ${BUILD_PATH}/tmp
 done
diff --git a/hack/push-chart.sh b/hack/push-chart.sh
index 21b6e031d..1bdead6a8 100755
--- a/hack/push-chart.sh
+++ b/hack/push-chart.sh
@@ -18,8 +18,11 @@ DEST_CHART_DIR=${DEST_CHART_DIR:-bin/}
 
 EXTRA_TAG=${EXTRA_TAG:-$(git branch --show-current)} 
 GIT_TAG=${GIT_TAG:-$(git describe --tags --dirty --always)}
-HELM_CHART_REPO=${HELM_CHART_REPO:-gcr.io/k8s-staging-kueue/charts}
-IMAGE_REPO=${IMAGE_REPO:-gcr.io/k8s-staging-kueue/kueue}
+
+STAGING_IMAGE_REGISTRY=${STAGING_IMAGE_REGISTRY:-us-central1-docker.pkg.dev/k8s-staging-images}
+IMAGE_REGISTRY=${IMAGE_REGISTRY:-${STAGING_IMAGE_REGISTRY}/kueue}
+HELM_CHART_REPO=${HELM_CHART_REPO:-${STAGING_IMAGE_REGISTRY}/charts}
+IMAGE_REPO=${IMAGE_REPO:-${IMAGE_REGISTRY}/kueue}
 
 HELM=${HELM:-./bin/helm}
 YQ=${YQ:-./bin/yq}
diff --git a/keps/1833-metrics-for-local-queue/README.md b/keps/1833-metrics-for-local-queue/README.md
new file mode 100644
index 000000000..907650812
--- /dev/null
+++ b/keps/1833-metrics-for-local-queue/README.md
@@ -0,0 +1,171 @@
+# KEP-1833: Enable Prometheus Metrics for Local Queues
+
+<!-- toc -->
+- [Summary](#summary)
+- [Motivation](#motivation)
+  - [Goals](#goals)
+  - [Non-Goals](#non-goals)
+- [Proposal](#proposal)
+  - [User Stories (Optional)](#user-stories-optional)
+    - [Story 1](#story-1)
+    - [Story 2](#story-2)
+    - [Story 3](#story-3)
+- [Design Details](#design-details)
+  - [API changes:](#api-changes)
+  - [List of metrics for Local Queues:](#list-of-metrics-for-local-queues)
+  - [Test Plan](#test-plan)
+    - [Unit Tests](#unit-tests)
+    - [Integration tests](#integration-tests)
+  - [Graduation Criteria](#graduation-criteria)
+- [Implementation History](#implementation-history)
+- [Drawbacks](#drawbacks)
+<!-- /toc -->
+
+## Summary
+
+The enhancement aims to introduce the exposure of local queue metrics to users, providing detailed insights into workload 
+processing specific to individual namespaces / tenants.
+
+## Motivation
+
+Metrics related to local queues are invaluable for batch users, providing essential visibility and historical trends 
+about their workloads. Currently, while metrics are available for only ClusterQueues, they do not provide batch users with 
+the necessary insights into their specific workloads.
+
+### Goals
+
+1. Introduce the API changes required to enable Local Queue metrics. 
+2. List the Prometheus metrics that would be exposed for Local Queues.  
+
+### Non-Goals
+
+1. Discuss the implementation details on where these metrics need to be collected in codebase.
+2. Discuss on metric visibility and RBAC required to enable the metrics securely for namespace admins.  
+
+## Proposal
+
+The proposal extends to enable collection of metrics for local queues that would be useful
+for batch users and cluster administrators. 
+
+### User Stories (Optional)
+
+#### Story 1
+
+As a batch user of Kueue, I want to access metrics for local queues running workloads restricted to my namespace so that 
+I can monitor and analyze the performance and trends of my workloads.
+
+#### Story 2
+
+As an administrator of Kueue, I want to enable batch users specific to a namespace to collect metrics for their workloads 
+within their namespace so that they can have visibility and insights into their own workload metrics.
+
+#### Story 3
+
+As an administrator of Kueue, I want to filter and gain insights on fine-grained metrics relevant to a local queue by 
+namespace for specific tenants so that I can effectively manage and optimize resource usage and performance for different tenants.
+
+## Design Details
+
+### API changes:
+
+The [Configuration API](https://github.com/kubernetes-sigs/kueue/blob/7ec127b05c8a0c8268e623de61914472dc5bff29/apis/config/v1beta1/configuration_types.go#L30)
+currently provides the ability to enable collection of metrics for cluster queues. This API will be extended to include options for enabling metrics 
+collection for local queues.
+
+The `ControllerMetrics` that contain the option to configure metrics, will be extended as follows:
+
+```go
+type ControllerManager struct {
+	...
+
+	// Metrics contains the controller metrics configuration
+	// +optional
+	Metrics ControllerMetrics `json:"metrics,omitempty"`
+	...
+}
+
+// ControllerMetrics defines the metrics configs.
+type ControllerMetrics struct {
+	...
+	
+	// LocalQueueMetrics is a configuration that provides enabling LocalQueue metrics and its options.
+	// +optional
+	LocalQueueMetrics *LocalQueueMetrics `json:"localQueueMetrics,omitempty"`
+}
+
+// LocalQueueMetrics defines the configuration options for local queue metrics.
+// If left empty, then metrics will expose for all local queues across namespaces.
+type LocalQueueMetrics struct {
+	// Enable is a knob to allow metrics to be exposed for local queues. Defaults to false.
+	Enable bool `json:"enable,omitempty`
+	
+	// NamespaceSelector can be used to select namespaces in which the local queues should
+	// report metrics.
+	NamespaceSelector *metav1.LabelSelector `json:"namespaceSelector,omitempty"`
+	
+	// LocalQueueSelector can be used to choose the local queues that need metrics to be collected. 
+	LocalQueueSelector *metav1.LabelSelector `json:"localQueueSelector,omitempty"`
+}
+```
+
+To reduce cardinality, and enable selection of metrics for local queues, the following
+knobs will be available for `LocalQueueMetrics`:
+
+| `Enable` | `NamespaceSelector` | `LocalQueueSelector` | Description                                                                                                        |
+|----------|---------------------|----------------------|--------------------------------------------------------------------------------------------------------------------|
+| False    | -                   | -                    | Metrics will not be exposed.                                                                                       |
+| True     | -                   | -                    | Metrics for all local queues will be exposed.                                                                      |
+| True     | Specified           | -                    | All LocalQueues in the specific namespaces that match the selector have metrics enabled.                           |
+| True     | -                   | Specified            | All LocalQueues matching the label selector have metrics enabled.                                                  |
+| True     | Specified           | Specified            | Both the selectors are applied to local queues (logical AND) to filter the ones whose metrics have to be enabled.  |
+| False    | Specified           | Specified            | The selectors are disregarded, metrics will not be exposed.                                                        |
+
+### List of metrics for Local Queues:
+
+In the first iteration, following are the list of metrics that would contain information on Local Queue statuses:
+
+| Metrics Name                                   | Prometheus Type | Description                                                                                         | 
+|------------------------------------------------|-----------------|-----------------------------------------------------------------------------------------------------|
+| local_queue_pending_workloads                  | Gauge           | The number of pending workloads.                                                                    |
+| local_queue_reserved_workloads_total           | Counter         | Total number of workloads in the LocalQueue reserving quota.                                        | 
+| local_queue_admitted_workloads_total           | Counter         | Total number of admitted workloads.                                                                 |
+| local_queue_resource_usage                     | Gauge           | Total quantity of used quota per resource for a Local Queue.                                        |
+| local_queue_evicted_workloads_total            | Counter         | The total number of evicted workloads in Local Queue.                                               |
+| local_queue_reserved_wait_time_seconds         | Histogram       | The time between a workload was created or re-queued until it got quota reservation in local queue. |
+| local_queue_admission_checks_wait_time_seconds | Histogram       | The time from when a workload got the quota reservation until admission in local queue.             |
+| local_queue_admission_wait_time_seconds        | Histogram       | The time between a workload was created or re-queued until admission.                               |
+| local_queue_status                             | Gauge           | Reports the status of the ClusterQueue.                                                             |
+
+Each of these metrics will be augmented with relevant Prometheus labels, indicating the local queue name, namespace, 
+and any other unique identifiers as required during implementation. They will be exported in the controller namespace, 
+alongside cluster queue metrics, at the same endpoint.
+
+### Test Plan
+
+[X] I/we understand the owners of the involved components may require updates to
+existing tests to make this code solid enough prior to committing the changes necessary
+to implement this enhancement.
+
+#### Unit Tests
+
+There are existing unit tests for prometheus metrics: https://github.com/kubernetes-sigs/kueue/blob/main/pkg/metrics/metrics_test.go.
+However, unit tests to ensure coverage for any additional local queue metrics will be added.
+
+- `pkg/metrics/`: `2024-07-19` - `48.2%`
+
+#### Integration tests
+
+The integration will address the following scenarios:
+
+1. Metrics for local queues are accurately reported throughout the lifecycle of workloads in local queues.
+2. Metrics are removed when a local queue is deleted from the cache.
+
+### Graduation Criteria
+
+## Implementation History
+
+## Drawbacks
+
+If not implemented correctly, in certain scenarios enabling local queue metrics for all namespaces across all local queues can lead to issues 
+with cardinality and system overload. To mitigate this, configuration options are provided to selectively enable metrics 
+reporting for specific local queues.
diff --git a/keps/1833-metrics-for-local-queue/kep.yaml b/keps/1833-metrics-for-local-queue/kep.yaml
new file mode 100644
index 000000000..18596b00e
--- /dev/null
+++ b/keps/1833-metrics-for-local-queue/kep.yaml
@@ -0,0 +1,22 @@
+title:
+kep-number: 1833
+authors:
+  - "@varshaprasad96"
+status: provisional
+creation-date: 2024-07-02
+reviewers:
+  - "@PBundyra"
+  - "@astefanutti"
+  - "@alculquicondor"
+  - "@tenzen-y"
+
+approvers:
+  - "@alculquicondor"
+  - "@tenzen-y"
+
+# The target maturity stage in the current dev cycle for this KEP.
+stage: alpha
+
+# The milestone at which this feature was, or is targeted to be, at each stage.
+milestone:
+  alpha: v0.9
diff --git a/pkg/cache/clusterqueue.go b/pkg/cache/clusterqueue.go
index 219989ab3..f2fc3b3e4 100644
--- a/pkg/cache/clusterqueue.go
+++ b/pkg/cache/clusterqueue.go
@@ -200,15 +200,10 @@ func (c *clusterQueue) update(in *kueue.ClusterQueue, resourceFlavors map[kueue.
 		for _, rg := range c.ResourceGroups {
 			for _, fName := range rg.Flavors {
 				for rName := range rg.CoveredResources {
-					rQuota := c.QuotaFor(resources.FlavorResource{Flavor: fName, Resource: rName})
+					fr := resources.FlavorResource{Flavor: fName, Resource: rName}
+					rQuota := c.QuotaFor(fr)
 					if rQuota.LendingLimit != nil {
-						if guaranteedQuota == nil {
-							guaranteedQuota = make(resources.FlavorResourceQuantities)
-						}
-						if guaranteedQuota[fName] == nil {
-							guaranteedQuota[fName] = make(map[corev1.ResourceName]int64)
-						}
-						guaranteedQuota[fName][rName] = rQuota.Nominal - *rQuota.LendingLimit
+						guaranteedQuota.Add(fr, rQuota.Nominal-*rQuota.LendingLimit)
 					}
 				}
 			}
diff --git a/pkg/cache/snapshot.go b/pkg/cache/snapshot.go
index 6ff3e0a4b..6c4d4c873 100644
--- a/pkg/cache/snapshot.go
+++ b/pkg/cache/snapshot.go
@@ -20,7 +20,6 @@ import (
 	"maps"
 
 	"github.com/go-logr/logr"
-	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/util/sets"
 	"k8s.io/klog/v2"
 
@@ -168,34 +167,22 @@ func (c *ClusterQueueSnapshot) accumulateResources(cohort *CohortSnapshot) {
 	}
 	for _, rg := range c.ResourceGroups {
 		for _, fName := range rg.Flavors {
-			res := cohort.RequestableResources[fName]
-			if res == nil {
-				res = make(map[corev1.ResourceName]int64, len(rg.CoveredResources))
-				cohort.RequestableResources[fName] = res
-			}
 			for rName := range rg.CoveredResources {
-				rQuota := c.QuotaFor(resources.FlavorResource{Flavor: fName, Resource: rName})
+				fr := resources.FlavorResource{Flavor: fName, Resource: rName}
+				rQuota := c.QuotaFor(fr)
 				// When feature LendingLimit enabled, cohort.RequestableResources indicates
 				// the sum of cq.NominalQuota and other cqs' LendingLimit (if not nil).
 				// If LendingLimit is not nil, we should count the lendingLimit as the requestable
 				// resource because we can't borrow more quota than lendingLimit.
 				if features.Enabled(features.LendingLimit) && rQuota.LendingLimit != nil {
-					res[rName] += *rQuota.LendingLimit
+					cohort.RequestableResources.Add(fr, *rQuota.LendingLimit)
 				} else {
-					res[rName] += rQuota.Nominal
+					cohort.RequestableResources.Add(fr, rQuota.Nominal)
 				}
 			}
 		}
 	}
-	if cohort.Usage == nil {
-		cohort.Usage = make(resources.FlavorResourceQuantities, len(c.Usage))
-	}
 	for fName, resUsages := range c.Usage {
-		used := cohort.Usage[fName]
-		if used == nil {
-			used = make(map[corev1.ResourceName]int64, len(resUsages))
-			cohort.Usage[fName] = used
-		}
 		for res, val := range resUsages {
 			// Similar to cohort.RequestableResources, we accumulate the usage above the guaranteed resources,
 			// here we should remove the guaranteed quota as well for that part can not be borrowed.
@@ -204,7 +191,7 @@ func (c *ClusterQueueSnapshot) accumulateResources(cohort *CohortSnapshot) {
 			if val < 0 {
 				val = 0
 			}
-			used[res] += val
+			cohort.Usage.Add(resources.FlavorResource{Flavor: fName, Resource: res}, val)
 		}
 	}
 }
diff --git a/pkg/scheduler/scheduler.go b/pkg/scheduler/scheduler.go
index f4eab64aa..049238a70 100644
--- a/pkg/scheduler/scheduler.go
+++ b/pkg/scheduler/scheduler.go
@@ -452,7 +452,7 @@ func (s *Scheduler) getAssignments(log logr.Logger, wl *workload.Info, snap *cac
 	cq := snap.ClusterQueues[wl.ClusterQueue]
 	flvAssigner := flavorassigner.New(wl, cq, snap.ResourceFlavors, s.fairSharing.Enable)
 	fullAssignment := flvAssigner.Assign(log, nil)
-	var faPreemtionTargets []*preemption.Target
+	var faPreemptionTargets []*preemption.Target
 
 	arm := fullAssignment.RepresentativeMode()
 	if arm == flavorassigner.Fit {
@@ -460,12 +460,12 @@ func (s *Scheduler) getAssignments(log logr.Logger, wl *workload.Info, snap *cac
 	}
 
 	if arm == flavorassigner.Preempt {
-		faPreemtionTargets = s.preemptor.GetTargets(log, *wl, fullAssignment, snap)
+		faPreemptionTargets = s.preemptor.GetTargets(log, *wl, fullAssignment, snap)
 	}
 
 	// if the feature gate is not enabled or we can preempt
-	if !features.Enabled(features.PartialAdmission) || len(faPreemtionTargets) > 0 {
-		return fullAssignment, faPreemtionTargets
+	if !features.Enabled(features.PartialAdmission) || len(faPreemptionTargets) > 0 {
+		return fullAssignment, faPreemptionTargets
 	}
 
 	if wl.CanBePartiallyAdmitted() {
diff --git a/pkg/webhooks/workload_webhook.go b/pkg/webhooks/workload_webhook.go
index f86b8bc90..333415d29 100644
--- a/pkg/webhooks/workload_webhook.go
+++ b/pkg/webhooks/workload_webhook.go
@@ -249,7 +249,7 @@ func validateReclaimablePods(obj *kueue.Workload, basePath *field.Path) field.Er
 	for i := range obj.Spec.PodSets {
 		name := obj.Spec.PodSets[i].Name
 		knowPodSets[name] = &obj.Spec.PodSets[i]
-		knowPodSetNames = append(knowPodSetNames, name)
+		knowPodSetNames[i] = name
 	}
 
 	var ret field.ErrorList
diff --git a/site/content/en/docs/concepts/cluster_queue.md b/site/content/en/docs/concepts/cluster_queue.md
index c86cbebce..59c29798d 100644
--- a/site/content/en/docs/concepts/cluster_queue.md
+++ b/site/content/en/docs/concepts/cluster_queue.md
@@ -231,9 +231,11 @@ semantics:
 - For each pod set resource in a Workload, a ClusterQueue can only borrow quota
   for one flavor.
 
-**Note:** Within a Cohort, Kueue prioritizes scheduling workloads that will fit under `nominalQuota`.
+{{% alert title="Note" color="primary" %}}
+Within a Cohort, Kueue prioritizes scheduling workloads that will fit under `nominalQuota`.
 By default, if multiple workloads require `borrowing`, Kueue will try to schedule workloads with higher [priority](/docs/concepts/workload#priority) first.
 If the feature gate `PrioritySortingWithinCohort=false` is set, Kueue will try to schedule workloads with the earliest `.metadata.creationTimestamp`.
+{{% /alert %}}
 
 You can influence some semantics of flavor selection and borrowing
 by setting a [`flavorFungibility`](/docs/concepts/cluster_queue#flavorfungibility) in ClusterQueue.
diff --git a/site/content/en/docs/concepts/resource_flavor.md b/site/content/en/docs/concepts/resource_flavor.md
index 1ca7672cb..b11ad455e 100644
--- a/site/content/en/docs/concepts/resource_flavor.md
+++ b/site/content/en/docs/concepts/resource_flavor.md
@@ -16,8 +16,10 @@ Resources in a cluster are typically not homogeneous. Resources could differ in:
 A ResourceFlavor is an object that represents these resource variations and
 allows you to associate them with cluster nodes through labels, taints and tolerations.
 
-**Note**: If the resources in your cluster are homogeneous, you can use 
+{{% alert title="Note" color="primary" %}}
+If the resources in your cluster are homogeneous, you can use 
 an [empty ResourceFlavor](#empty-resourceflavor) instead of adding labels to custom ResourceFlavors.
+{{% /alert %}}
 
 A sample ResourceFlavor looks like the following:
 
diff --git a/site/content/en/docs/reference/kubectl-kueue/installation.md b/site/content/en/docs/reference/kubectl-kueue/installation.md
index e4869b72b..833508c2c 100644
--- a/site/content/en/docs/reference/kubectl-kueue/installation.md
+++ b/site/content/en/docs/reference/kubectl-kueue/installation.md
@@ -7,6 +7,12 @@ description: >
   Installing the kubectl-kueue plugin, kueuectl.
 ---
 
+## Installing via Krew
+
+```shell
+kubectl krew install kueue
+```
+
 ## Installing From Release Binaries
 
 ### 1. Download the latest release:
diff --git a/site/content/en/docs/reference/kueue-alpha.v1alpha1.md b/site/content/en/docs/reference/kueue-alpha.v1alpha1.md
index 7620453cd..e759b679f 100644
--- a/site/content/en/docs/reference/kueue-alpha.v1alpha1.md
+++ b/site/content/en/docs/reference/kueue-alpha.v1alpha1.md
@@ -74,6 +74,116 @@ description: Generated API reference documentation for kueue.x-k8s.io/v1alpha1.
 </tbody>
 </table>
 
+## `Cohort`     {#kueue-x-k8s-io-v1alpha1-Cohort}
+    
+
+**Appears in:**
+
+
+
+<p>Cohort is the Schema for the cohorts API</p>
+
+
+<table class="table">
+<thead><tr><th width="30%">Field</th><th>Description</th></tr></thead>
+<tbody>
+    
+  
+<tr><td><code>spec</code> <B>[Required]</B><br/>
+<a href="#kueue-x-k8s-io-v1alpha1-CohortSpec"><code>CohortSpec</code></a>
+</td>
+<td>
+   <span class="text-muted">No description provided.</span></td>
+</tr>
+<tr><td><code>status</code> <B>[Required]</B><br/>
+<a href="#kueue-x-k8s-io-v1alpha1-CohortStatus"><code>CohortStatus</code></a>
+</td>
+<td>
+   <span class="text-muted">No description provided.</span></td>
+</tr>
+</tbody>
+</table>
+
+## `CohortSpec`     {#kueue-x-k8s-io-v1alpha1-CohortSpec}
+    
+
+**Appears in:**
+
+- [Cohort](#kueue-x-k8s-io-v1alpha1-Cohort)
+
+
+<p>CohortSpec defines the desired state of Cohort</p>
+
+
+<table class="table">
+<thead><tr><th width="30%">Field</th><th>Description</th></tr></thead>
+<tbody>
+    
+  
+<tr><td><code>parent</code> <B>[Required]</B><br/>
+<code>string</code>
+</td>
+<td>
+   <p>Parent references the name of the Cohort's parent, if
+any. It satisfies one of three cases:</p>
+<ol>
+<li>Unset. This Cohort is the root of its Cohort tree.</li>
+<li>References a non-existent Cohort. We use default Cohort (no borrowing/lending limits).</li>
+<li>References an existent Cohort.</li>
+</ol>
+<p>If a cycle is created, we disable all members of the
+Cohort, including ClusterQueues, until the cycle is
+removed.  We prevent further admission while the cycle
+exists.</p>
+</td>
+</tr>
+<tr><td><code>resourceGroups</code> <B>[Required]</B><br/>
+<a href="#kueue-x-k8s-io-v1beta1-ResourceGroup"><code>[]ResourceGroup</code></a>
+</td>
+<td>
+   <p>ResourceGroups describes groupings of Resources and
+Flavors.  Each ResourceGroup defines a list of Resources
+and a list of Flavors which provide quotas for these
+Resources. Each Resource and each Flavor may only form part
+of one ResourceGroup.  There may be up to 16 ResourceGroups
+within a Cohort.</p>
+<p>BorrowingLimit limits how much members of this Cohort
+subtree can borrow from the parent subtree.</p>
+<p>LendingLimit limits how much members of this Cohort subtree
+can lend to the parent subtree.</p>
+<p>Borrowing and Lending limits must only be set when the
+Cohort has a parent.  Otherwise, the Cohort create/update
+will be rejected by the webhook.</p>
+</td>
+</tr>
+</tbody>
+</table>
+
+## `CohortStatus`     {#kueue-x-k8s-io-v1alpha1-CohortStatus}
+    
+
+**Appears in:**
+
+- [Cohort](#kueue-x-k8s-io-v1alpha1-Cohort)
+
+
+<p>CohortStatus defines the observed state of Cohort</p>
+
+
+<table class="table">
+<thead><tr><th width="30%">Field</th><th>Description</th></tr></thead>
+<tbody>
+    
+  
+<tr><td><code>conditions</code> <B>[Required]</B><br/>
+<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#condition-v1-meta"><code>[]k8s.io/apimachinery/pkg/apis/meta/v1.Condition</code></a>
+</td>
+<td>
+   <span class="text-muted">No description provided.</span></td>
+</tr>
+</tbody>
+</table>
+
 ## `KubeConfig`     {#kueue-x-k8s-io-v1alpha1-KubeConfig}
     
 
diff --git a/site/content/en/docs/tasks/manage/setup_job_admission_policy.md b/site/content/en/docs/tasks/manage/setup_job_admission_policy.md
index 9bba72032..f6616c0a0 100644
--- a/site/content/en/docs/tasks/manage/setup_job_admission_policy.md
+++ b/site/content/en/docs/tasks/manage/setup_job_admission_policy.md
@@ -13,6 +13,8 @@ This page shows how you can set up for Kueue a Job Admission Policy using the Ku
 Ensure the following conditions are met:
 
 - A Kubernetes cluster is running.
+- The `ValidatingAdmissionPolicy` [feature gate](https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/) 
+is enabled. In Kubernetes 1.30 or newer, the feature gate is enabled by default.
 - The kubectl command-line tool can communicate with your cluster.
 - [Kueue is installed](/docs/installation).
 
diff --git a/site/content/en/docs/tasks/manage/setup_wait_for_pods_ready.md b/site/content/en/docs/tasks/manage/setup_wait_for_pods_ready.md
index 3d20527ca..7d135a9be 100644
--- a/site/content/en/docs/tasks/manage/setup_wait_for_pods_ready.md
+++ b/site/content/en/docs/tasks/manage/setup_wait_for_pods_ready.md
@@ -115,9 +115,10 @@ We create two jobs which both require all their pods to be running at the same
 time to complete. The cluster has enough resources to support running one of the
 jobs at the same time, but not both.
 
-> **Note**
-> In this example we use a cluster with autoscaling disabled in order to simulate
+{{% alert title="Note" color="primary" %}}
+In this example we use a cluster with autoscaling disabled in order to simulate
 issues with resource provisioning to satisfy the configured cluster quota.
+{{% /alert %}}
 
 ### 1. Preparation
 
diff --git a/site/content/en/docs/tasks/run/jobs.md b/site/content/en/docs/tasks/run/jobs.md
index 9d5d2e811..446829cb8 100644
--- a/site/content/en/docs/tasks/run/jobs.md
+++ b/site/content/en/docs/tasks/run/jobs.md
@@ -214,4 +214,6 @@ For example, a Job defined by the following manifest:
 
 When queued in a ClusterQueue with only 9 CPUs available, it will be admitted with `parallelism=9`. Note that the number of completions doesn't change.
 
-**NOTE:** PartialAdmission is an `Alpha` feature disabled by default, check the [Change the feature gates configuration](/docs/installation/#change-the-feature-gates-configuration) section of the [Installation](/docs/installation/) for details.
+{{% alert title="Note" color="primary" %}}
+PartialAdmission is an `Alpha` feature disabled by default, check the [Change the feature gates configuration](/docs/installation/#change-the-feature-gates-configuration) section of the [Installation](/docs/installation/) for details.
+{{% /alert %}}
\ No newline at end of file
diff --git a/site/content/en/docs/tasks/run/jobsets.md b/site/content/en/docs/tasks/run/jobsets.md
index 9556b441d..43bb5af3c 100644
--- a/site/content/en/docs/tasks/run/jobsets.md
+++ b/site/content/en/docs/tasks/run/jobsets.md
@@ -17,6 +17,11 @@ This guide is for [batch users](/docs/tasks#batch-user) that have a basic unders
 
 2. See [JobSet Installation](https://jobset.sigs.k8s.io/docs/installation/) for installation and configuration details of JobSet Operator.
 
+{{% alert title="Note" color="note" %}}
+In order to use JobSet you need to restart Kueue after the installation.
+You can do it by running: `kubectl delete pods -lcontrol-plane=controller-manager -nkueue-system`.
+{{% /alert %}}
+
 ## JobSet definition
 
 When running [JobSets](https://jobset.sigs.k8s.io/docs/concepts/) on
diff --git a/site/content/en/docs/tasks/run/kubeflow/mpijobs.md b/site/content/en/docs/tasks/run/kubeflow/mpijobs.md
index 5c686685f..bdac3541a 100644
--- a/site/content/en/docs/tasks/run/kubeflow/mpijobs.md
+++ b/site/content/en/docs/tasks/run/kubeflow/mpijobs.md
@@ -16,7 +16,12 @@ Check [administer cluster quotas](/docs/tasks/manage/administer_cluster_quotas)
 
 Check [the MPI Operator installation guide](https://github.com/kubeflow/mpi-operator#installation).
 
-You can [modify kueue configurations from installed releases](/docs/installation#install-a-custom-configured-released-version) to include MPIJobs as an allowed workload.  
+You can [modify kueue configurations from installed releases](/docs/installation#install-a-custom-configured-released-version) to include MPIJobs as an allowed workload.
+
+{{% alert title="Note" color="note" %}}
+In order to use MPIJob you need to restart Kueue after the installation.
+You can do it by running: `kubectl delete pods -lcontrol-plane=controller-manager -nkueue-system`.
+{{% /alert %}}
 
 ## MPI Operator definition
 
diff --git a/site/content/en/docs/tasks/run/kubeflow/mxjobs.md b/site/content/en/docs/tasks/run/kubeflow/mxjobs.md
index c84e4b24c..7a563636f 100644
--- a/site/content/en/docs/tasks/run/kubeflow/mxjobs.md
+++ b/site/content/en/docs/tasks/run/kubeflow/mxjobs.md
@@ -20,6 +20,11 @@ Note that the minimum requirement training-operator version is v1.7.0.
 
 You can [modify kueue configurations from installed releases](/docs/installation#install-a-custom-configured-released-version) to include MXJobs as an allowed workload.
 
+{{% alert title="Note" color="note" %}}
+In order to use Training Operator you need to restart Kueue after the installation.
+You can do it by running: `kubectl delete pods -lcontrol-plane=controller-manager -nkueue-system`.
+{{% /alert %}}
+
 ## MXJob definition
 
 ### a. Queue selection
diff --git a/site/content/en/docs/tasks/run/kubeflow/paddlejobs.md b/site/content/en/docs/tasks/run/kubeflow/paddlejobs.md
index e532d0a02..29afae65f 100644
--- a/site/content/en/docs/tasks/run/kubeflow/paddlejobs.md
+++ b/site/content/en/docs/tasks/run/kubeflow/paddlejobs.md
@@ -20,6 +20,11 @@ Note that the minimum requirement training-operator version is v1.7.0.
 
 You can [modify kueue configurations from installed releases](/docs/installation#install-a-custom-configured-released-version) to include PaddleJobs as an allowed workload.
 
+{{% alert title="Note" color="note" %}}
+In order to use Training Operator you need to restart Kueue after the installation.
+You can do it by running: `kubectl delete pods -lcontrol-plane=controller-manager -nkueue-system`.
+{{% /alert %}}
+
 ## PaddleJob definition
 
 ### a. Queue selection
diff --git a/site/content/en/docs/tasks/run/kubeflow/pytorchjobs.md b/site/content/en/docs/tasks/run/kubeflow/pytorchjobs.md
index e80be95b7..d6c6cd94d 100644
--- a/site/content/en/docs/tasks/run/kubeflow/pytorchjobs.md
+++ b/site/content/en/docs/tasks/run/kubeflow/pytorchjobs.md
@@ -20,6 +20,11 @@ Note that the minimum requirement training-operator version is v1.7.0.
 
 You can [modify kueue configurations from installed releases](/docs/installation#install-a-custom-configured-released-version) to include PyTorchJobs as an allowed workload.
 
+{{% alert title="Note" color="note" %}}
+In order to use Training Operator you need to restart Kueue after the installation.
+You can do it by running: `kubectl delete pods -lcontrol-plane=controller-manager -nkueue-system`.
+{{% /alert %}}
+
 ## PyTorchJob definition
 
 ### a. Queue selection
diff --git a/site/content/en/docs/tasks/run/kubeflow/tfjobs.md b/site/content/en/docs/tasks/run/kubeflow/tfjobs.md
index 24a696b52..4b4816751 100644
--- a/site/content/en/docs/tasks/run/kubeflow/tfjobs.md
+++ b/site/content/en/docs/tasks/run/kubeflow/tfjobs.md
@@ -20,6 +20,11 @@ Note that the minimum requirement training-operator version is v1.7.0.
 
 You can [modify kueue configurations from installed releases](/docs/installation#install-a-custom-configured-released-version) to include TFJobs as an allowed workload.
 
+{{% alert title="Note" color="note" %}}
+In order to use Training Operator you need to restart Kueue after the installation.
+You can do it by running: `kubectl delete pods -lcontrol-plane=controller-manager -nkueue-system`.
+{{% /alert %}}
+
 ## TFJob definition
 
 ### a. Queue selection
diff --git a/site/content/en/docs/tasks/run/kubeflow/xgboostjobs.md b/site/content/en/docs/tasks/run/kubeflow/xgboostjobs.md
index 285709dba..9bff5547c 100644
--- a/site/content/en/docs/tasks/run/kubeflow/xgboostjobs.md
+++ b/site/content/en/docs/tasks/run/kubeflow/xgboostjobs.md
@@ -20,6 +20,11 @@ Note that the minimum requirement training-operator version is v1.7.0.
 
 You can [modify kueue configurations from installed releases](/docs/installation#install-a-custom-configured-released-version) to include XGBoostJobs as an allowed workload.
 
+{{% alert title="Note" color="note" %}}
+In order to use Training Operator you need to restart Kueue after the installation.
+You can do it by running: `kubectl delete pods -lcontrol-plane=controller-manager -nkueue-system`.
+{{% /alert %}}
+
 ## XGBoostJob definition
 
 ### a. Queue selection
diff --git a/site/content/en/docs/tasks/run/plain_pods.md b/site/content/en/docs/tasks/run/plain_pods.md
index 314daf70b..f5c7ad40a 100644
--- a/site/content/en/docs/tasks/run/plain_pods.md
+++ b/site/content/en/docs/tasks/run/plain_pods.md
@@ -140,8 +140,10 @@ When a Kueue needs to preempt a workload that represents a Pod group, kueue send
 delete requests for all of the Pods in the group. It is the responsibility of the
 user or controller that created the original Pods to create replacement Pods.
 
-**NOTE:** We recommend using the kubernetes Job API or similar CRDs such as
+{{% alert title="Note" color="primary" %}}
+We recommend using the kubernetes Job API or similar CRDs such as
 JobSet, MPIJob, RayJob (see more [here](/docs/tasks/#batch-user)).
+{{% /alert %}}
 
 ### Termination
 
diff --git a/site/content/en/docs/tasks/run/rayclusters.md b/site/content/en/docs/tasks/run/rayclusters.md
index d82358163..e894d8447 100644
--- a/site/content/en/docs/tasks/run/rayclusters.md
+++ b/site/content/en/docs/tasks/run/rayclusters.md
@@ -19,6 +19,11 @@ This guide is for [batch users](/docs/tasks#batch-user) that have a basic unders
 
 3. See [KubeRay Installation](https://ray-project.github.io/kuberay/deploy/installation/) for installation and configuration details of KubeRay.
 
+{{% alert title="Note" color="note" %}}
+In order to use RayCluster you need to restart Kueue after the installation.
+You can do it by running: `kubectl delete pods -lcontrol-plane=controller-manager -nkueue-system`.
+{{% /alert %}}
+
 ## RayCluster definition
 
 When running [RayClusters](https://docs.ray.io/en/latest/cluster/getting-started.html) on
diff --git a/site/content/en/docs/tasks/run/rayjobs.md b/site/content/en/docs/tasks/run/rayjobs.md
index 9011cbf88..84d123ef0 100644
--- a/site/content/en/docs/tasks/run/rayjobs.md
+++ b/site/content/en/docs/tasks/run/rayjobs.md
@@ -18,6 +18,11 @@ This guide is for [batch users](/docs/tasks#batch-user) that have a basic unders
 
 2. See [KubeRay Installation](https://ray-project.github.io/kuberay/deploy/installation/) for installation and configuration details of KubeRay.
 
+{{% alert title="Note" color="note" %}}
+In order to use RayJob you need to restart Kueue after the installation.
+You can do it by running: `kubectl delete pods -lcontrol-plane=controller-manager -nkueue-system`.
+{{% /alert %}}
+
 ## RayJob definition
 
 When running [RayJobs](https://ray-project.github.io/kuberay/guidance/rayjob/) on
diff --git a/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/common_types.go b/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/common_types.go
index b880486f7..42fd1d0da 100644
--- a/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/common_types.go
+++ b/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/common_types.go
@@ -226,7 +226,8 @@ type RunPolicy struct {
 // SchedulingPolicy encapsulates various scheduling policies of the distributed training
 // job, for example `minAvailable` for gang-scheduling.
 type SchedulingPolicy struct {
-	MinAvailable           *int32                                 `json:"minAvailable,omitempty"`
+	MinAvailable *int32 `json:"minAvailable,omitempty"`
+	// +kubebuilder:validation:XValidation:rule="self == oldSelf", message="spec.runPolicy.schedulingPolicy.queue is immutable"
 	Queue                  string                                 `json:"queue,omitempty"`
 	MinResources           *map[v1.ResourceName]resource.Quantity `json:"minResources,omitempty"`
 	PriorityClass          string                                 `json:"priorityClass,omitempty"`
diff --git a/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/defaulting_utils.go b/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/defaulting_utils.go
index ed6717822..5b3a67085 100644
--- a/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/defaulting_utils.go
+++ b/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/defaulting_utils.go
@@ -4,7 +4,7 @@ import (
 	"strings"
 
 	corev1 "k8s.io/api/core/v1"
-	"k8s.io/utils/pointer"
+	"k8s.io/utils/ptr"
 )
 
 func getDefaultContainerIndex(spec *corev1.PodSpec, defaultContainerName string) int {
@@ -41,7 +41,7 @@ func setDefaultRestartPolicy(replicaSpec *ReplicaSpec, defaultRestartPolicy Rest
 
 func setDefaultReplicas(replicaSpec *ReplicaSpec, replicas int32) {
 	if replicaSpec != nil && replicaSpec.Replicas == nil {
-		replicaSpec.Replicas = pointer.Int32(replicas)
+		replicaSpec.Replicas = ptr.To[int32](replicas)
 	}
 }
 
diff --git a/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/openapi_generated.go b/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/openapi_generated.go
index c1a49e2ae..4932ff386 100644
--- a/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/openapi_generated.go
+++ b/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/openapi_generated.go
@@ -199,14 +199,12 @@ func schema_pkg_apis_kubefloworg_v1_JobCondition(ref common.ReferenceCallback) c
 					"lastUpdateTime": {
 						SchemaProps: spec.SchemaProps{
 							Description: "The last time this condition was updated.",
-							Default:     map[string]interface{}{},
 							Ref:         ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
 						},
 					},
 					"lastTransitionTime": {
 						SchemaProps: spec.SchemaProps{
 							Description: "Last time the condition transitioned from one status to another.",
-							Default:     map[string]interface{}{},
 							Ref:         ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
 						},
 					},
@@ -1115,8 +1113,7 @@ func schema_pkg_apis_kubefloworg_v1_SchedulingPolicy(ref common.ReferenceCallbac
 								Allows: true,
 								Schema: &spec.Schema{
 									SchemaProps: spec.SchemaProps{
-										Default: map[string]interface{}{},
-										Ref:     ref("k8s.io/apimachinery/pkg/api/resource.Quantity"),
+										Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"),
 									},
 								},
 							},
diff --git a/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/paddlepaddle_validation.go b/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/paddlepaddle_validation.go
deleted file mode 100644
index 995763b30..000000000
--- a/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/paddlepaddle_validation.go
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2022 The Kubeflow Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package v1
-
-import (
-	"fmt"
-
-	apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation"
-)
-
-func ValidateV1PaddleJob(paddleJob *PaddleJob) error {
-	if errors := apimachineryvalidation.NameIsDNS1035Label(paddleJob.ObjectMeta.Name, false); errors != nil {
-		return fmt.Errorf("PaddleJob name is invalid: %v", errors)
-	}
-	if err := validatePaddleReplicaSpecs(paddleJob.Spec.PaddleReplicaSpecs); err != nil {
-		return err
-	}
-	return nil
-}
-
-func validatePaddleReplicaSpecs(specs map[ReplicaType]*ReplicaSpec) error {
-	if specs == nil {
-		return fmt.Errorf("PaddleJobSpec is not valid")
-	}
-	for rType, value := range specs {
-		if value == nil || len(value.Template.Spec.Containers) == 0 {
-			return fmt.Errorf("PaddleJobSpec is not valid: containers definition expected in %v", rType)
-		}
-		// Make sure the replica type is valid.
-		validReplicaTypes := []ReplicaType{PaddleJobReplicaTypeMaster, PaddleJobReplicaTypeWorker}
-
-		isValidReplicaType := false
-		for _, t := range validReplicaTypes {
-			if t == rType {
-				isValidReplicaType = true
-				break
-			}
-		}
-
-		if !isValidReplicaType {
-			return fmt.Errorf("PaddleReplicaType is %v but must be one of %v", rType, validReplicaTypes)
-		}
-
-		//Make sure the image is defined in the container
-		defaultContainerPresent := false
-		for _, container := range value.Template.Spec.Containers {
-			if container.Image == "" {
-				msg := fmt.Sprintf("PaddleJobSpec is not valid: Image is undefined in the container of %v", rType)
-				return fmt.Errorf(msg)
-			}
-			if container.Name == PaddleJobDefaultContainerName {
-				defaultContainerPresent = true
-			}
-		}
-		//Make sure there has at least one container named "paddle"
-		if !defaultContainerPresent {
-			msg := fmt.Sprintf("PaddleJobSpec is not valid: There is no container named %s in %v", PaddleJobDefaultContainerName, rType)
-			return fmt.Errorf(msg)
-		}
-
-	}
-
-	return nil
-}
diff --git a/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/pytorch_validation.go b/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/pytorch_validation.go
deleted file mode 100644
index 752b8196d..000000000
--- a/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/pytorch_validation.go
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2018 The Kubeflow Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package v1
-
-import (
-	"fmt"
-
-	apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation"
-)
-
-func ValidateV1PyTorchJob(pytorchJob *PyTorchJob) error {
-	if errors := apimachineryvalidation.NameIsDNS1035Label(pytorchJob.ObjectMeta.Name, false); errors != nil {
-		return fmt.Errorf("PyTorchJob name is invalid: %v", errors)
-	}
-	if err := validatePyTorchReplicaSpecs(pytorchJob.Spec.PyTorchReplicaSpecs); err != nil {
-		return err
-	}
-	if err := validateNprocPerNode(pytorchJob); err != nil {
-		return err
-	}
-	return nil
-}
-
-func validateNprocPerNode(pytorchJob *PyTorchJob) error {
-	if pytorchJob.Spec.NprocPerNode != nil && pytorchJob.Spec.ElasticPolicy != nil && pytorchJob.Spec.ElasticPolicy.NProcPerNode != nil {
-		return fmt.Errorf(".spec.elasticPolicy.nProcPerNode is deprecated, use .spec.nprocPerNode instead")
-	}
-	return nil
-}
-
-func validatePyTorchReplicaSpecs(specs map[ReplicaType]*ReplicaSpec) error {
-	if specs == nil {
-		return fmt.Errorf("PyTorchJobSpec is not valid")
-	}
-	for rType, value := range specs {
-		if value == nil || len(value.Template.Spec.Containers) == 0 {
-			return fmt.Errorf("PyTorchJobSpec is not valid: containers definition expected in %v", rType)
-		}
-		// Make sure the replica type is valid.
-		validReplicaTypes := []ReplicaType{PyTorchJobReplicaTypeMaster, PyTorchJobReplicaTypeWorker}
-
-		isValidReplicaType := false
-		for _, t := range validReplicaTypes {
-			if t == rType {
-				isValidReplicaType = true
-				break
-			}
-		}
-
-		if !isValidReplicaType {
-			return fmt.Errorf("PyTorchReplicaType is %v but must be one of %v", rType, validReplicaTypes)
-		}
-
-		//Make sure the image is defined in the container
-		defaultContainerPresent := false
-		for _, container := range value.Template.Spec.Containers {
-			if container.Image == "" {
-				msg := fmt.Sprintf("PyTorchJobSpec is not valid: Image is undefined in the container of %v", rType)
-				return fmt.Errorf(msg)
-			}
-			if container.Name == PyTorchJobDefaultContainerName {
-				defaultContainerPresent = true
-			}
-		}
-		//Make sure there has at least one container named "pytorch"
-		if !defaultContainerPresent {
-			msg := fmt.Sprintf("PyTorchJobSpec is not valid: There is no container named %s in %v", PyTorchJobDefaultContainerName, rType)
-			return fmt.Errorf(msg)
-		}
-		if rType == PyTorchJobReplicaTypeMaster {
-			if value.Replicas != nil && int(*value.Replicas) != 1 {
-				return fmt.Errorf("PyTorchJobSpec is not valid: There must be only 1 master replica")
-			}
-		}
-
-	}
-
-	return nil
-
-}
diff --git a/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/tensorflow_types.go b/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/tensorflow_types.go
index 64da30582..7ee0a81d3 100644
--- a/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/tensorflow_types.go
+++ b/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/tensorflow_types.go
@@ -122,9 +122,14 @@ const (
 	TFJobReplicaTypeEval ReplicaType = "Evaluator"
 )
 
+// IsChiefOrMaster returns true if the type is Master or Chief.
+func IsChiefOrMaster(typ ReplicaType) bool {
+	return typ == TFJobReplicaTypeChief || typ == TFJobReplicaTypeMaster
+}
+
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 // +resource:path=tfjobs
-//+kubebuilder:object:root=true
+// +kubebuilder:object:root=true
 
 // TFJobList is a list of TFJobs.
 type TFJobList struct {
diff --git a/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/tensorflow_validation.go b/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/tensorflow_validation.go
deleted file mode 100644
index a73721ae6..000000000
--- a/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/tensorflow_validation.go
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2018 The Kubeflow Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package v1
-
-import (
-	"fmt"
-
-	log "github.com/sirupsen/logrus"
-	apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation"
-)
-
-func ValidateV1TFJob(tfjob *TFJob) error {
-	if errors := apimachineryvalidation.NameIsDNS1035Label(tfjob.ObjectMeta.Name, false); errors != nil {
-		return fmt.Errorf("TFJob name is invalid: %v", errors)
-	}
-	if err := validateV1TFReplicaSpecs(tfjob.Spec.TFReplicaSpecs); err != nil {
-		return err
-	}
-	return nil
-}
-
-// IsChieforMaster returns true if the type is Master or Chief.
-func IsChieforMaster(typ ReplicaType) bool {
-	return typ == TFJobReplicaTypeChief || typ == TFJobReplicaTypeMaster
-}
-
-// IsWorker returns true if the type is Worker.
-func IsWorker(typ ReplicaType) bool {
-	return typ == TFJobReplicaTypeWorker
-}
-
-// IsEvaluator returns true if the type is Evaluator.
-func IsEvaluator(typ ReplicaType) bool {
-	return typ == TFJobReplicaTypeEval
-}
-
-func validateV1TFReplicaSpecs(specs map[ReplicaType]*ReplicaSpec) error {
-	if specs == nil {
-		return fmt.Errorf("TFJobSpec is not valid")
-	}
-	foundChief := 0
-	for rType, value := range specs {
-		if value == nil || len(value.Template.Spec.Containers) == 0 {
-			return fmt.Errorf("TFJobSpec is not valid: containers definition expected in %v", rType)
-		}
-		if IsChieforMaster(rType) {
-			foundChief++
-		}
-		// Make sure the image is defined in the container.
-		numNamedTensorflow := 0
-		for _, container := range value.Template.Spec.Containers {
-			if container.Image == "" {
-				msg := fmt.Sprintf("TFJobSpec is not valid: Image is undefined in the container of %v", rType)
-				log.Error(msg)
-				return fmt.Errorf(msg)
-			}
-			if container.Name == TFJobDefaultContainerName {
-				numNamedTensorflow++
-			}
-		}
-		// Make sure there has at least one container named "tensorflow".
-		if numNamedTensorflow == 0 {
-			msg := fmt.Sprintf("TFJobSpec is not valid: There is no container named %s in %v", TFJobDefaultContainerName, rType)
-			log.Error(msg)
-			return fmt.Errorf(msg)
-		}
-	}
-	if foundChief > 1 {
-		return fmt.Errorf("TFJobSpec is not valid: more than 1 chief/master found")
-	}
-	return nil
-}
diff --git a/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/xgboost_validation.go b/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/xgboost_validation.go
deleted file mode 100644
index b862c52c8..000000000
--- a/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/xgboost_validation.go
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2021 The Kubeflow Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package v1
-
-import (
-	"fmt"
-
-	apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation"
-)
-
-func ValidateV1XGBoostJob(xgboostJob *XGBoostJob) error {
-	if errors := apimachineryvalidation.NameIsDNS1035Label(xgboostJob.ObjectMeta.Name, false); errors != nil {
-		return fmt.Errorf("XGBoostJob name is invalid: %v", errors)
-	}
-	if err := validateXGBoostReplicaSpecs(xgboostJob.Spec.XGBReplicaSpecs); err != nil {
-		return err
-	}
-	return nil
-}
-
-func validateXGBoostReplicaSpecs(specs map[ReplicaType]*ReplicaSpec) error {
-	if specs == nil {
-		return fmt.Errorf("XGBoostJobSpec is not valid")
-	}
-	masterExists := false
-	for rType, value := range specs {
-		if value == nil || len(value.Template.Spec.Containers) == 0 {
-			return fmt.Errorf("XGBoostJobSpec is not valid: containers definition expected in %v", rType)
-		}
-		// Make sure the replica type is valid.
-		validReplicaTypes := []ReplicaType{XGBoostJobReplicaTypeMaster, XGBoostJobReplicaTypeWorker}
-
-		isValidReplicaType := false
-		for _, t := range validReplicaTypes {
-			if t == rType {
-				isValidReplicaType = true
-				break
-			}
-		}
-
-		if !isValidReplicaType {
-			return fmt.Errorf("XGBoostReplicaType is %v but must be one of %v", rType, validReplicaTypes)
-		}
-
-		//Make sure the image is defined in the container
-		defaultContainerPresent := false
-		for _, container := range value.Template.Spec.Containers {
-			if container.Image == "" {
-				msg := fmt.Sprintf("XGBoostReplicaType is not valid: Image is undefined in the container of %v", rType)
-				return fmt.Errorf(msg)
-			}
-			if container.Name == XGBoostJobDefaultContainerName {
-				defaultContainerPresent = true
-			}
-		}
-		//Make sure there has at least one container named "xgboost"
-		if !defaultContainerPresent {
-			msg := fmt.Sprintf("XGBoostReplicaType is not valid: There is no container named %s in %v", XGBoostJobDefaultContainerName, rType)
-			return fmt.Errorf(msg)
-		}
-		if rType == XGBoostJobReplicaTypeMaster {
-			masterExists = true
-			if value.Replicas != nil && int(*value.Replicas) != 1 {
-				return fmt.Errorf("XGBoostReplicaType is not valid: There must be only 1 master replica")
-			}
-		}
-
-	}
-
-	if !masterExists {
-		return fmt.Errorf("XGBoostReplicaType is not valid: Master ReplicaSpec must be present")
-	}
-	return nil
-
-}
diff --git a/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/zz_generated.deepcopy.go b/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/zz_generated.deepcopy.go
index 1f8a89ff8..7bb7b8690 100644
--- a/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/zz_generated.deepcopy.go
+++ b/vendor/github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1/zz_generated.deepcopy.go
@@ -1,5 +1,4 @@
 //go:build !ignore_autogenerated
-// +build !ignore_autogenerated
 
 // Copyright 2023 The Kubeflow Authors
 //
@@ -134,7 +133,8 @@ func (in *JobStatus) DeepCopyInto(out *JobStatus) {
 			if val == nil {
 				(*out)[key] = nil
 			} else {
-				in, out := &val, &outVal
+				inVal := (*in)[key]
+				in, out := &inVal, &outVal
 				*out = new(ReplicaStatus)
 				(*in).DeepCopyInto(*out)
 			}
@@ -245,7 +245,8 @@ func (in *MPIJobSpec) DeepCopyInto(out *MPIJobSpec) {
 			if val == nil {
 				(*out)[key] = nil
 			} else {
-				in, out := &val, &outVal
+				inVal := (*in)[key]
+				in, out := &inVal, &outVal
 				*out = new(ReplicaSpec)
 				(*in).DeepCopyInto(*out)
 			}
@@ -336,7 +337,8 @@ func (in *MXJobSpec) DeepCopyInto(out *MXJobSpec) {
 			if val == nil {
 				(*out)[key] = nil
 			} else {
-				in, out := &val, &outVal
+				inVal := (*in)[key]
+				in, out := &inVal, &outVal
 				*out = new(ReplicaSpec)
 				(*in).DeepCopyInto(*out)
 			}
@@ -483,7 +485,8 @@ func (in *PaddleJobSpec) DeepCopyInto(out *PaddleJobSpec) {
 			if val == nil {
 				(*out)[key] = nil
 			} else {
-				in, out := &val, &outVal
+				inVal := (*in)[key]
+				in, out := &inVal, &outVal
 				*out = new(ReplicaSpec)
 				(*in).DeepCopyInto(*out)
 			}
@@ -578,7 +581,8 @@ func (in *PyTorchJobSpec) DeepCopyInto(out *PyTorchJobSpec) {
 			if val == nil {
 				(*out)[key] = nil
 			} else {
-				in, out := &val, &outVal
+				inVal := (*in)[key]
+				in, out := &inVal, &outVal
 				*out = new(ReplicaSpec)
 				(*in).DeepCopyInto(*out)
 			}
@@ -815,7 +819,8 @@ func (in *TFJobSpec) DeepCopyInto(out *TFJobSpec) {
 			if val == nil {
 				(*out)[key] = nil
 			} else {
-				in, out := &val, &outVal
+				inVal := (*in)[key]
+				in, out := &inVal, &outVal
 				*out = new(ReplicaSpec)
 				(*in).DeepCopyInto(*out)
 			}
@@ -905,7 +910,8 @@ func (in *XGBoostJobSpec) DeepCopyInto(out *XGBoostJobSpec) {
 			if val == nil {
 				(*out)[key] = nil
 			} else {
-				in, out := &val, &outVal
+				inVal := (*in)[key]
+				in, out := &inVal, &outVal
 				*out = new(ReplicaSpec)
 				(*in).DeepCopyInto(*out)
 			}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index e5b6fd54d..50b12f26a 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -177,8 +177,8 @@ github.com/json-iterator/go
 # github.com/kubeflow/mpi-operator v0.5.0
 ## explicit; go 1.22
 github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1
-# github.com/kubeflow/training-operator v1.7.0
-## explicit; go 1.20
+# github.com/kubeflow/training-operator v1.8.0
+## explicit; go 1.22
 github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1
 # github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de
 ## explicit
@@ -636,7 +636,7 @@ gopkg.in/yaml.v2
 # gopkg.in/yaml.v3 v3.0.1
 ## explicit
 gopkg.in/yaml.v3
-# k8s.io/api v0.30.2
+# k8s.io/api v0.30.3
 ## explicit; go 1.22.0
 k8s.io/api/admission/v1
 k8s.io/api/admission/v1beta1
@@ -703,7 +703,7 @@ k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset
 k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/scheme
 k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1
 k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1beta1
-# k8s.io/apimachinery v0.30.2
+# k8s.io/apimachinery v0.30.3
 ## explicit; go 1.22.0
 k8s.io/apimachinery/pkg/api/equality
 k8s.io/apimachinery/pkg/api/errors
@@ -766,7 +766,7 @@ k8s.io/apimachinery/pkg/version
 k8s.io/apimachinery/pkg/watch
 k8s.io/apimachinery/third_party/forked/golang/json
 k8s.io/apimachinery/third_party/forked/golang/reflect
-# k8s.io/apiserver v0.29.6
+# k8s.io/apiserver v0.29.7
 ## explicit; go 1.21
 k8s.io/apiserver/pkg/admission
 k8s.io/apiserver/pkg/admission/cel
@@ -917,13 +917,13 @@ k8s.io/apiserver/plugin/pkg/authorizer/webhook
 # k8s.io/autoscaler/cluster-autoscaler/apis v0.0.0-20240325113845-0130d33747bb
 ## explicit; go 1.21
 k8s.io/autoscaler/cluster-autoscaler/apis/provisioningrequest/autoscaling.x-k8s.io/v1beta1
-# k8s.io/cli-runtime v0.29.6
+# k8s.io/cli-runtime v0.29.7
 ## explicit; go 1.21
 k8s.io/cli-runtime/pkg/genericclioptions
 k8s.io/cli-runtime/pkg/genericiooptions
 k8s.io/cli-runtime/pkg/printers
 k8s.io/cli-runtime/pkg/resource
-# k8s.io/client-go v0.29.6
+# k8s.io/client-go v0.29.7
 ## explicit; go 1.21
 k8s.io/client-go/applyconfigurations/admissionregistration/v1
 k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1
@@ -1243,7 +1243,7 @@ k8s.io/client-go/util/jsonpath
 k8s.io/client-go/util/keyutil
 k8s.io/client-go/util/retry
 k8s.io/client-go/util/workqueue
-# k8s.io/code-generator v0.29.6
+# k8s.io/code-generator v0.29.7
 ## explicit; go 1.21
 k8s.io/code-generator
 k8s.io/code-generator/cmd/applyconfiguration-gen
@@ -1281,7 +1281,7 @@ k8s.io/code-generator/cmd/set-gen
 k8s.io/code-generator/pkg/namer
 k8s.io/code-generator/pkg/util
 k8s.io/code-generator/third_party/forked/golang/reflect
-# k8s.io/component-base v0.29.6
+# k8s.io/component-base v0.29.7
 ## explicit; go 1.21
 k8s.io/component-base/cli/flag
 k8s.io/component-base/config
@@ -1304,7 +1304,7 @@ k8s.io/component-base/metrics/testutil
 k8s.io/component-base/tracing
 k8s.io/component-base/tracing/api/v1
 k8s.io/component-base/version
-# k8s.io/component-helpers v0.29.6
+# k8s.io/component-helpers v0.29.7
 ## explicit; go 1.21
 k8s.io/component-helpers/scheduling/corev1
 k8s.io/component-helpers/scheduling/corev1/nodeaffinity
@@ -1335,7 +1335,7 @@ k8s.io/klog/v2/internal/dbg
 k8s.io/klog/v2/internal/serialize
 k8s.io/klog/v2/internal/severity
 k8s.io/klog/v2/internal/sloghandler
-# k8s.io/kms v0.29.6
+# k8s.io/kms v0.29.7
 ## explicit; go 1.21
 k8s.io/kms/apis/v1beta1
 k8s.io/kms/apis/v2
@@ -1366,7 +1366,7 @@ k8s.io/kube-openapi/pkg/validation/errors
 k8s.io/kube-openapi/pkg/validation/spec
 k8s.io/kube-openapi/pkg/validation/strfmt
 k8s.io/kube-openapi/pkg/validation/strfmt/bson
-# k8s.io/metrics v0.29.6
+# k8s.io/metrics v0.29.7
 ## explicit; go 1.21
 k8s.io/metrics/pkg/apis/metrics
 k8s.io/metrics/pkg/apis/metrics/install



Test patch:
diff --git a/cmd/experimental/kjobctl/pkg/builder/builder_test.go b/cmd/experimental/kjobctl/pkg/builder/builder_test.go
index cf665d063..95ab3ad4b 100644
--- a/cmd/experimental/kjobctl/pkg/builder/builder_test.go
+++ b/cmd/experimental/kjobctl/pkg/builder/builder_test.go
@@ -20,10 +20,10 @@ import (
 	"context"
 	"errors"
 	"testing"
+	"time"
 
 	"github.com/google/go-cmp/cmp"
 	"github.com/google/go-cmp/cmp/cmpopts"
-	batchv1 "k8s.io/api/batch/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
@@ -33,9 +33,12 @@ import (
 	"sigs.k8s.io/kueue/cmd/experimental/kjobctl/client-go/clientset/versioned/fake"
 	cmdtesting "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/cmd/testing"
 	"sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/constants"
+	"sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/testing/wrappers"
 )
 
 func TestBuilder(t *testing.T) {
+	testStartTime := time.Now()
+
 	testCases := map[string]struct {
 		namespace   string
 		profile     string
@@ -61,15 +64,9 @@ func TestBuilder(t *testing.T) {
 			namespace: metav1.NamespaceDefault,
 			profile:   "profile",
 			kjobctlObjs: []runtime.Object{
-				&v1alpha1.ApplicationProfile{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "profile",
-						Namespace: metav1.NamespaceDefault,
-					},
-					Spec: v1alpha1.ApplicationProfileSpec{
-						SupportedModes: []v1alpha1.SupportedMode{{Name: v1alpha1.JobMode}},
-					},
-				},
+				wrappers.MakeApplicationProfile("profile", metav1.NamespaceDefault).
+					WithSupportedMode(v1alpha1.SupportedMode{Name: v1alpha1.JobMode}).
+					Obj(),
 			},
 			wantErr: noApplicationProfileModeSpecifiedErr,
 		},
@@ -78,15 +75,9 @@ func TestBuilder(t *testing.T) {
 			profile:   "profile",
 			mode:      v1alpha1.JobMode,
 			kjobctlObjs: []runtime.Object{
-				&v1alpha1.ApplicationProfile{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "profile",
-						Namespace: metav1.NamespaceDefault,
-					},
-					Spec: v1alpha1.ApplicationProfileSpec{
-						SupportedModes: []v1alpha1.SupportedMode{{Name: v1alpha1.InteractiveMode}},
-					},
-				},
+				wrappers.MakeApplicationProfile("profile", metav1.NamespaceDefault).
+					WithSupportedMode(v1alpha1.SupportedMode{Name: v1alpha1.InteractiveMode}).
+					Obj(),
 			},
 			wantErr: applicationProfileModeNotConfiguredErr,
 		},
@@ -95,15 +86,9 @@ func TestBuilder(t *testing.T) {
 			profile:   "profile",
 			mode:      "Invalid",
 			kjobctlObjs: []runtime.Object{
-				&v1alpha1.ApplicationProfile{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "profile",
-						Namespace: metav1.NamespaceDefault,
-					},
-					Spec: v1alpha1.ApplicationProfileSpec{
-						SupportedModes: []v1alpha1.SupportedMode{{Name: v1alpha1.InteractiveMode}},
-					},
-				},
+				wrappers.MakeApplicationProfile("profile", metav1.NamespaceDefault).
+					WithSupportedMode(v1alpha1.SupportedMode{Name: v1alpha1.InteractiveMode}).
+					Obj(),
 			},
 			wantErr: invalidApplicationProfileModeErr,
 		},
@@ -112,18 +97,12 @@ func TestBuilder(t *testing.T) {
 			profile:   "profile",
 			mode:      v1alpha1.JobMode,
 			kjobctlObjs: []runtime.Object{
-				&v1alpha1.ApplicationProfile{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "profile",
-						Namespace: metav1.NamespaceDefault,
-					},
-					Spec: v1alpha1.ApplicationProfileSpec{
-						SupportedModes: []v1alpha1.SupportedMode{{
-							Name:          v1alpha1.JobMode,
-							RequiredFlags: []v1alpha1.Flag{v1alpha1.CmdFlag},
-						}},
-					},
-				},
+				wrappers.MakeApplicationProfile("profile", metav1.NamespaceDefault).
+					WithSupportedMode(v1alpha1.SupportedMode{
+						Name:          v1alpha1.JobMode,
+						RequiredFlags: []v1alpha1.Flag{v1alpha1.CmdFlag},
+					}).
+					Obj(),
 			},
 			wantErr: noCommandSpecifiedErr,
 		},
@@ -132,18 +111,12 @@ func TestBuilder(t *testing.T) {
 			profile:   "profile",
 			mode:      v1alpha1.JobMode,
 			kjobctlObjs: []runtime.Object{
-				&v1alpha1.ApplicationProfile{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "profile",
-						Namespace: metav1.NamespaceDefault,
-					},
-					Spec: v1alpha1.ApplicationProfileSpec{
-						SupportedModes: []v1alpha1.SupportedMode{{
-							Name:          v1alpha1.JobMode,
-							RequiredFlags: []v1alpha1.Flag{v1alpha1.ParallelismFlag},
-						}},
-					},
-				},
+				wrappers.MakeApplicationProfile("profile", metav1.NamespaceDefault).
+					WithSupportedMode(v1alpha1.SupportedMode{
+						Name:          v1alpha1.JobMode,
+						RequiredFlags: []v1alpha1.Flag{v1alpha1.ParallelismFlag},
+					}).
+					Obj(),
 			},
 			wantErr: noParallelismSpecifiedErr,
 		},
@@ -152,18 +125,12 @@ func TestBuilder(t *testing.T) {
 			profile:   "profile",
 			mode:      v1alpha1.JobMode,
 			kjobctlObjs: []runtime.Object{
-				&v1alpha1.ApplicationProfile{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "profile",
-						Namespace: metav1.NamespaceDefault,
-					},
-					Spec: v1alpha1.ApplicationProfileSpec{
-						SupportedModes: []v1alpha1.SupportedMode{{
-							Name:          v1alpha1.JobMode,
-							RequiredFlags: []v1alpha1.Flag{v1alpha1.CompletionsFlag},
-						}},
-					},
-				},
+				wrappers.MakeApplicationProfile("profile", metav1.NamespaceDefault).
+					WithSupportedMode(v1alpha1.SupportedMode{
+						Name:          v1alpha1.JobMode,
+						RequiredFlags: []v1alpha1.Flag{v1alpha1.CompletionsFlag},
+					}).
+					Obj(),
 			},
 			wantErr: noCompletionsSpecifiedErr,
 		},
@@ -172,18 +139,12 @@ func TestBuilder(t *testing.T) {
 			profile:   "profile",
 			mode:      v1alpha1.JobMode,
 			kjobctlObjs: []runtime.Object{
-				&v1alpha1.ApplicationProfile{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "profile",
-						Namespace: metav1.NamespaceDefault,
-					},
-					Spec: v1alpha1.ApplicationProfileSpec{
-						SupportedModes: []v1alpha1.SupportedMode{{
-							Name:          v1alpha1.JobMode,
-							RequiredFlags: []v1alpha1.Flag{v1alpha1.RequestFlag},
-						}},
-					},
-				},
+				wrappers.MakeApplicationProfile("profile", metav1.NamespaceDefault).
+					WithSupportedMode(v1alpha1.SupportedMode{
+						Name:          v1alpha1.JobMode,
+						RequiredFlags: []v1alpha1.Flag{v1alpha1.RequestFlag},
+					}).
+					Obj(),
 			},
 			wantErr: noRequestsSpecifiedErr,
 		},
@@ -192,18 +153,12 @@ func TestBuilder(t *testing.T) {
 			profile:   "profile",
 			mode:      v1alpha1.JobMode,
 			kjobctlObjs: []runtime.Object{
-				&v1alpha1.ApplicationProfile{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "profile",
-						Namespace: metav1.NamespaceDefault,
-					},
-					Spec: v1alpha1.ApplicationProfileSpec{
-						SupportedModes: []v1alpha1.SupportedMode{{
-							Name:          v1alpha1.JobMode,
-							RequiredFlags: []v1alpha1.Flag{v1alpha1.LocalQueueFlag},
-						}},
-					},
-				},
+				wrappers.MakeApplicationProfile("profile", metav1.NamespaceDefault).
+					WithSupportedMode(v1alpha1.SupportedMode{
+						Name:          v1alpha1.JobMode,
+						RequiredFlags: []v1alpha1.Flag{v1alpha1.LocalQueueFlag},
+					}).
+					Obj(),
 			},
 			wantErr: noLocalQueueSpecifiedErr,
 		},
@@ -212,38 +167,17 @@ func TestBuilder(t *testing.T) {
 			profile:   "profile",
 			mode:      v1alpha1.JobMode,
 			kjobctlObjs: []runtime.Object{
-				&v1alpha1.JobTemplate{
-					ObjectMeta: metav1.ObjectMeta{
-						Namespace: metav1.NamespaceDefault,
-						Name:      "job-template",
-					},
-				},
-				&v1alpha1.ApplicationProfile{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "profile",
-						Namespace: metav1.NamespaceDefault,
-					},
-					Spec: v1alpha1.ApplicationProfileSpec{
-						SupportedModes: []v1alpha1.SupportedMode{{
-							Name:     v1alpha1.JobMode,
-							Template: "job-template",
-						}},
-					},
-				},
-			},
-			wantObj: &batchv1.Job{
-				TypeMeta: metav1.TypeMeta{
-					Kind:       "Job",
-					APIVersion: "batch/v1",
-				},
-				ObjectMeta: metav1.ObjectMeta{
-					GenerateName: "profile-",
-					Namespace:    metav1.NamespaceDefault,
-					Labels: map[string]string{
-						constants.ProfileLabel: "profile",
-					},
-				},
+				wrappers.MakeJobTemplate("job-template", metav1.NamespaceDefault).Obj(),
+				wrappers.MakeApplicationProfile("profile", metav1.NamespaceDefault).
+					WithSupportedMode(v1alpha1.SupportedMode{
+						Name:     v1alpha1.JobMode,
+						Template: "job-template",
+					}).
+					Obj(),
 			},
+			wantObj: wrappers.MakeJob("", metav1.NamespaceDefault).GenerateName("profile-").
+				Label(constants.ProfileLabel, "profile").
+				Obj(),
 		},
 	}
 	for name, tc := range testCases {
@@ -253,7 +187,7 @@ func TestBuilder(t *testing.T) {
 
 			tcg := cmdtesting.NewTestClientGetter().
 				WithKjobctlClientset(fake.NewSimpleClientset(tc.kjobctlObjs...))
-			gotObjs, gotErr := NewBuilder(tcg).
+			gotObjs, gotErr := NewBuilder(tcg, testStartTime).
 				WithNamespace(tc.namespace).
 				WithProfileName(tc.profile).
 				WithModeName(tc.mode).
diff --git a/cmd/experimental/kjobctl/pkg/builder/interactive_builder_test.go b/cmd/experimental/kjobctl/pkg/builder/interactive_builder_test.go
index 20b9478df..5e5ad0455 100644
--- a/cmd/experimental/kjobctl/pkg/builder/interactive_builder_test.go
+++ b/cmd/experimental/kjobctl/pkg/builder/interactive_builder_test.go
@@ -19,7 +19,10 @@ package builder
 import (
 	"context"
 	"errors"
+	"fmt"
+	"os"
 	"testing"
+	"time"
 
 	"github.com/google/go-cmp/cmp"
 	"github.com/google/go-cmp/cmp/cmpopts"
@@ -28,98 +31,47 @@ import (
 	"k8s.io/apimachinery/pkg/api/resource"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/runtime/schema"
 	k8sfake "k8s.io/client-go/kubernetes/fake"
 
 	"sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1"
 	kjobctlfake "sigs.k8s.io/kueue/cmd/experimental/kjobctl/client-go/clientset/versioned/fake"
 	cmdtesting "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/cmd/testing"
 	"sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/constants"
+	"sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/testing/wrappers"
 	kueueconstants "sigs.k8s.io/kueue/pkg/controller/constants"
 )
 
 func TestInteractiveBuilder(t *testing.T) {
-	testPodTemplate := &corev1.PodTemplate{
-		ObjectMeta: metav1.ObjectMeta{
-			Namespace: metav1.NamespaceDefault,
-			Name:      "job-template",
-			Labels:    map[string]string{"foo": "bar"},
-		},
-		Template: corev1.PodTemplateSpec{
-			Spec: corev1.PodSpec{
-				InitContainers: []corev1.Container{
-					{
-						Name:      "ic1",
-						Command:   []string{""},
-						Resources: corev1.ResourceRequirements{},
-						Env: []corev1.EnvVar{
-							{Name: "e0", Value: "default-value0"},
-						},
-						VolumeMounts: []corev1.VolumeMount{
-							{Name: "vm0", MountPath: "/etc/default-config0"},
-						},
-					},
-				},
-				Containers: []corev1.Container{
-					{
-						Name:    "c1",
-						Command: []string{""},
-						Resources: corev1.ResourceRequirements{
-							Requests: corev1.ResourceList{
-								corev1.ResourceCPU: resource.MustParse("1"),
-							},
-						},
-						Env: []corev1.EnvVar{
-							{Name: "e1", Value: "default-value1"},
-							{Name: "e2", Value: "default-value2"},
-						},
-						VolumeMounts: []corev1.VolumeMount{
-							{Name: "vm1", MountPath: "/etc/default-config1"},
-							{Name: "vm2", MountPath: "/etc/default-config2"},
-						},
-					},
-					{
-						Name:    "c2",
-						Command: []string{""},
-						Resources: corev1.ResourceRequirements{
-							Requests: corev1.ResourceList{
-								corev1.ResourceCPU: resource.MustParse("2"),
-							},
-						},
-						Env: []corev1.EnvVar{
-							{Name: "e1", Value: "default-value1"},
-							{Name: "e2", Value: "default-value2"},
-						},
-						VolumeMounts: []corev1.VolumeMount{
-							{Name: "vm1", MountPath: "/etc/default-config1"},
-							{Name: "vm2", MountPath: "/etc/default-config2"},
-						},
-					},
-				},
-				Volumes: []corev1.Volume{
-					{
-						Name: "v1",
-						VolumeSource: corev1.VolumeSource{
-							ConfigMap: &corev1.ConfigMapVolumeSource{
-								LocalObjectReference: corev1.LocalObjectReference{
-									Name: "default-config1",
-								},
-							},
-						},
-					},
-					{
-						Name: "v2",
-						VolumeSource: corev1.VolumeSource{
-							ConfigMap: &corev1.ConfigMapVolumeSource{
-								LocalObjectReference: corev1.LocalObjectReference{
-									Name: "default-config2",
-								},
-							},
-						},
-					},
-				},
-			},
-		},
-	}
+	testStartTime := time.Now()
+	userID := os.Getenv(constants.SystemEnvVarNameUser)
+
+	testPodTemplateWrapper := wrappers.MakePodTemplate("pod-template", metav1.NamespaceDefault).
+		WithInitContainer(
+			*wrappers.MakeContainer("ic1", "").
+				WithEnvVar(corev1.EnvVar{Name: "e0", Value: "default-value0"}).
+				WithVolumeMount(corev1.VolumeMount{Name: "vm0", MountPath: "/etc/default-config0"}).
+				Obj(),
+		).
+		WithContainer(
+			*wrappers.MakeContainer("c1", "").
+				WithRequest(corev1.ResourceCPU, resource.MustParse("1")).
+				WithEnvVar(corev1.EnvVar{Name: "e1", Value: "default-value1"}).
+				WithEnvVar(corev1.EnvVar{Name: "e2", Value: "default-value2"}).
+				WithVolumeMount(corev1.VolumeMount{Name: "vm1", MountPath: "/etc/default-config1"}).
+				WithVolumeMount(corev1.VolumeMount{Name: "vm2", MountPath: "/etc/default-config2"}).
+				Obj(),
+		).
+		WithContainer(*wrappers.MakeContainer("c2", "").
+			WithRequest(corev1.ResourceCPU, resource.MustParse("2")).
+			WithEnvVar(corev1.EnvVar{Name: "e1", Value: "default-value1"}).
+			WithEnvVar(corev1.EnvVar{Name: "e2", Value: "default-value2"}).
+			WithVolumeMount(corev1.VolumeMount{Name: "vm1", MountPath: "/etc/default-config1"}).
+			WithVolumeMount(corev1.VolumeMount{Name: "vm2", MountPath: "/etc/default-config2"}).
+			Obj(),
+		).
+		WithVolume("v1", "default-config1").
+		WithVolume("v2", "default-config2")
 
 	testCases := map[string]struct {
 		namespace   string
@@ -133,204 +85,88 @@ func TestInteractiveBuilder(t *testing.T) {
 		wantObj     runtime.Object
 		wantErr     error
 	}{
-		"should build job without replacements": {
+		"shouldn't build pod because template not found": {
 			namespace: metav1.NamespaceDefault,
 			profile:   "profile",
 			mode:      v1alpha1.InteractiveMode,
-			k8sObjs:   []runtime.Object{testPodTemplate},
 			kjobctlObjs: []runtime.Object{
-				&v1alpha1.ApplicationProfile{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "profile",
-						Namespace: metav1.NamespaceDefault,
-					},
-					Spec: v1alpha1.ApplicationProfileSpec{
-						SupportedModes: []v1alpha1.SupportedMode{{
-							Name:     v1alpha1.InteractiveMode,
-							Template: "job-template",
-						}},
-					},
-				},
-			},
-			wantObj: &corev1.Pod{
-				TypeMeta: metav1.TypeMeta{
-					Kind:       "Pod",
-					APIVersion: "v1",
-				},
-				ObjectMeta: metav1.ObjectMeta{
-					GenerateName: "profile-",
-					Namespace:    metav1.NamespaceDefault,
-					Labels: map[string]string{
-						constants.ProfileLabel: "profile",
-					},
-				},
-				Spec: testPodTemplate.Template.Spec,
+				wrappers.MakeApplicationProfile("profile", metav1.NamespaceDefault).
+					WithSupportedMode(v1alpha1.SupportedMode{Name: v1alpha1.InteractiveMode, Template: "pod-template"}).
+					Obj(),
 			},
+			wantErr: apierrors.NewNotFound(schema.GroupResource{Resource: "podtemplates"}, "pod-template"),
 		},
-		"should build job with replacements": {
+		"should build job without replacements": {
 			namespace: metav1.NamespaceDefault,
 			profile:   "profile",
 			mode:      v1alpha1.InteractiveMode,
-			command:   []string{"sleep"},
-			requests: corev1.ResourceList{
-				corev1.ResourceCPU: resource.MustParse("3"),
+			k8sObjs:   []runtime.Object{testPodTemplateWrapper.Clone().Obj()},
+			kjobctlObjs: []runtime.Object{
+				wrappers.MakeApplicationProfile("profile", metav1.NamespaceDefault).
+					WithSupportedMode(v1alpha1.SupportedMode{Name: v1alpha1.InteractiveMode, Template: "pod-template"}).
+					Obj(),
 			},
+			wantObj: wrappers.MakePod("", metav1.NamespaceDefault).GenerateName("profile-").
+				Label(constants.ProfileLabel, "profile").
+				Spec(
+					testPodTemplateWrapper.Clone().
+						WithEnvVar(corev1.EnvVar{Name: constants.EnvVarNameUserID, Value: userID}).
+						WithEnvVar(corev1.EnvVar{Name: constants.EnvVarTaskName, Value: "default_profile"}).
+						WithEnvVar(corev1.EnvVar{
+							Name:  constants.EnvVarTaskID,
+							Value: fmt.Sprintf("%s_%s_default_profile", userID, testStartTime.Format(time.RFC3339)),
+						}).
+						WithEnvVar(corev1.EnvVar{Name: "PROFILE", Value: "default_profile"}).
+						WithEnvVar(corev1.EnvVar{Name: "TIMESTAMP", Value: testStartTime.Format(time.RFC3339)}).
+						TTY().
+						Stdin().
+						Obj().Template.Spec,
+				).
+				Obj(),
+		},
+		"should build job with replacements": {
+			namespace:  metav1.NamespaceDefault,
+			profile:    "profile",
+			mode:       v1alpha1.InteractiveMode,
+			command:    []string{"sleep"},
+			requests:   corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("3")},
 			localQueue: "lq1",
-			k8sObjs: []runtime.Object{
-				testPodTemplate,
-			},
+			k8sObjs:    []runtime.Object{testPodTemplateWrapper.Clone().Obj()},
 			kjobctlObjs: []runtime.Object{
-				&v1alpha1.ApplicationProfile{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "profile",
-						Namespace: metav1.NamespaceDefault,
-					},
-					Spec: v1alpha1.ApplicationProfileSpec{
-						SupportedModes: []v1alpha1.SupportedMode{{
-							Name:     v1alpha1.InteractiveMode,
-							Template: "job-template",
-						}},
-						VolumeBundles: []v1alpha1.VolumeBundleReference{"vb1", "vb2"},
-					},
-				},
-				&v1alpha1.VolumeBundle{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "vb1",
-						Namespace: metav1.NamespaceDefault,
-					},
-					Spec: v1alpha1.VolumeBundleSpec{
-						Volumes: []corev1.Volume{
-							{
-								Name: "v3",
-								VolumeSource: corev1.VolumeSource{
-									ConfigMap: &corev1.ConfigMapVolumeSource{
-										LocalObjectReference: corev1.LocalObjectReference{
-											Name: "config3",
-										},
-									},
-								},
-							},
-						},
-						ContainerVolumeMounts: []corev1.VolumeMount{
-							{Name: "vm3", MountPath: "/etc/config3"},
-						},
-						EnvVars: []corev1.EnvVar{
-							{Name: "e3", Value: "value3"},
-						},
-					},
-				},
-				&v1alpha1.VolumeBundle{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "vb2",
-						Namespace: metav1.NamespaceDefault,
-					},
-					Spec: v1alpha1.VolumeBundleSpec{},
-				},
-			},
-			wantObj: &corev1.Pod{
-				TypeMeta: metav1.TypeMeta{
-					Kind:       "Pod",
-					APIVersion: "v1",
-				},
-				ObjectMeta: metav1.ObjectMeta{
-					GenerateName: "profile-",
-					Namespace:    metav1.NamespaceDefault,
-					Labels: map[string]string{
-						constants.ProfileLabel:    "profile",
-						kueueconstants.QueueLabel: "lq1",
-					},
-				},
-				Spec: corev1.PodSpec{
-					InitContainers: []corev1.Container{
-						{
-							Name:      "ic1",
-							Command:   []string{""},
-							Resources: corev1.ResourceRequirements{},
-							Env: []corev1.EnvVar{
-								{Name: "e0", Value: "default-value0"},
-								{Name: "e3", Value: "value3"},
-							},
-							VolumeMounts: []corev1.VolumeMount{
-								{Name: "vm0", MountPath: "/etc/default-config0"},
-								{Name: "vm3", MountPath: "/etc/config3"},
-							},
-						},
-					},
-					Containers: []corev1.Container{
-						{
-							Name:    "c1",
-							Command: []string{"sleep"},
-							Resources: corev1.ResourceRequirements{
-								Requests: corev1.ResourceList{
-									corev1.ResourceCPU: resource.MustParse("3"),
-								},
-							},
-							Env: []corev1.EnvVar{
-								{Name: "e1", Value: "default-value1"},
-								{Name: "e2", Value: "default-value2"},
-								{Name: "e3", Value: "value3"},
-							},
-							VolumeMounts: []corev1.VolumeMount{
-								{Name: "vm1", MountPath: "/etc/default-config1"},
-								{Name: "vm2", MountPath: "/etc/default-config2"},
-								{Name: "vm3", MountPath: "/etc/config3"},
-							},
-						},
-						{
-							Name:    "c2",
-							Command: []string{""},
-							Resources: corev1.ResourceRequirements{
-								Requests: corev1.ResourceList{
-									corev1.ResourceCPU: resource.MustParse("2"),
-								},
-							},
-							Env: []corev1.EnvVar{
-								{Name: "e1", Value: "default-value1"},
-								{Name: "e2", Value: "default-value2"},
-								{Name: "e3", Value: "value3"},
-							},
-							VolumeMounts: []corev1.VolumeMount{
-								{Name: "vm1", MountPath: "/etc/default-config1"},
-								{Name: "vm2", MountPath: "/etc/default-config2"},
-								{Name: "vm3", MountPath: "/etc/config3"},
-							},
-						},
-					},
-					Volumes: []corev1.Volume{
-						{
-							Name: "v1",
-							VolumeSource: corev1.VolumeSource{
-								ConfigMap: &corev1.ConfigMapVolumeSource{
-									LocalObjectReference: corev1.LocalObjectReference{
-										Name: "default-config1",
-									},
-								},
-							},
-						},
-						{
-							Name: "v2",
-							VolumeSource: corev1.VolumeSource{
-								ConfigMap: &corev1.ConfigMapVolumeSource{
-									LocalObjectReference: corev1.LocalObjectReference{
-										Name: "default-config2",
-									},
-								},
-							},
-						},
-						{
-							Name: "v3",
-							VolumeSource: corev1.VolumeSource{
-								ConfigMap: &corev1.ConfigMapVolumeSource{
-									LocalObjectReference: corev1.LocalObjectReference{
-										Name: "config3",
-									},
-								},
-							},
-						},
-					},
-				},
+				wrappers.MakeApplicationProfile("profile", metav1.NamespaceDefault).
+					WithSupportedMode(v1alpha1.SupportedMode{Name: v1alpha1.InteractiveMode, Template: "pod-template"}).
+					WithVolumeBundleReferences("vb1", "vb2").
+					Obj(),
+				wrappers.MakeVolumeBundle("vb1", metav1.NamespaceDefault).
+					WithVolume("v3", "config3").
+					WithVolumeMount(corev1.VolumeMount{Name: "vm3", MountPath: "/etc/config3"}).
+					WithEnvVar(corev1.EnvVar{Name: "e3", Value: "value3"}).
+					Obj(),
+				wrappers.MakeVolumeBundle("vb2", metav1.NamespaceDefault).Obj(),
 			},
-			wantErr: nil,
+			wantObj: wrappers.MakePod("", metav1.NamespaceDefault).GenerateName("profile-").
+				Label(constants.ProfileLabel, "profile").
+				Label(kueueconstants.QueueLabel, "lq1").
+				Spec(
+					testPodTemplateWrapper.Clone().
+						Command([]string{"sleep"}).
+						WithRequest(corev1.ResourceCPU, resource.MustParse("3")).
+						WithVolume("v3", "config3").
+						WithVolumeMount(corev1.VolumeMount{Name: "vm3", MountPath: "/etc/config3"}).
+						WithEnvVar(corev1.EnvVar{Name: "e3", Value: "value3"}).
+						WithEnvVar(corev1.EnvVar{Name: constants.EnvVarNameUserID, Value: userID}).
+						WithEnvVar(corev1.EnvVar{Name: constants.EnvVarTaskName, Value: "default_profile"}).
+						WithEnvVar(corev1.EnvVar{
+							Name:  constants.EnvVarTaskID,
+							Value: fmt.Sprintf("%s_%s_default_profile", userID, testStartTime.Format(time.RFC3339)),
+						}).
+						WithEnvVar(corev1.EnvVar{Name: "PROFILE", Value: "default_profile"}).
+						WithEnvVar(corev1.EnvVar{Name: "TIMESTAMP", Value: testStartTime.Format(time.RFC3339)}).
+						TTY().
+						Stdin().
+						Obj().Template.Spec,
+				).
+				Obj(),
 		},
 	}
 	for name, tc := range testCases {
@@ -342,7 +178,7 @@ func TestInteractiveBuilder(t *testing.T) {
 				WithKjobctlClientset(kjobctlfake.NewSimpleClientset(tc.kjobctlObjs...)).
 				WithK8sClientset(k8sfake.NewSimpleClientset(tc.k8sObjs...))
 
-			gotObjs, gotErr := NewBuilder(tcg).
+			gotObjs, gotErr := NewBuilder(tcg, testStartTime).
 				WithNamespace(tc.namespace).
 				WithProfileName(tc.profile).
 				WithModeName(tc.mode).
diff --git a/cmd/experimental/kjobctl/pkg/builder/job_builder_test.go b/cmd/experimental/kjobctl/pkg/builder/job_builder_test.go
index 0314b27c4..8ffeb17f7 100644
--- a/cmd/experimental/kjobctl/pkg/builder/job_builder_test.go
+++ b/cmd/experimental/kjobctl/pkg/builder/job_builder_test.go
@@ -19,11 +19,13 @@ package builder
 import (
 	"context"
 	"errors"
+	"fmt"
+	"os"
 	"testing"
+	"time"
 
 	"github.com/google/go-cmp/cmp"
 	"github.com/google/go-cmp/cmp/cmpopts"
-	batchv1 "k8s.io/api/batch/v1"
 	corev1 "k8s.io/api/core/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/api/resource"
@@ -36,98 +38,42 @@ import (
 	kjobctlfake "sigs.k8s.io/kueue/cmd/experimental/kjobctl/client-go/clientset/versioned/fake"
 	cmdtesting "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/cmd/testing"
 	"sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/constants"
+	"sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/testing/wrappers"
 	kueueconstants "sigs.k8s.io/kueue/pkg/controller/constants"
 )
 
 func TestJobBuilder(t *testing.T) {
-	testJobTemplate := &v1alpha1.JobTemplate{
-		ObjectMeta: metav1.ObjectMeta{
-			Namespace: metav1.NamespaceDefault,
-			Name:      "job-template",
-			Labels:    map[string]string{"foo": "bar"},
-		},
-		Template: v1alpha1.JobTemplateSpec{
-			Spec: batchv1.JobSpec{
-				Parallelism: ptr.To[int32](1),
-				Completions: ptr.To[int32](1),
-				Template: corev1.PodTemplateSpec{
-					Spec: corev1.PodSpec{
-						InitContainers: []corev1.Container{
-							{
-								Name:      "ic1",
-								Command:   []string{""},
-								Resources: corev1.ResourceRequirements{},
-								Env: []corev1.EnvVar{
-									{Name: "e0", Value: "default-value0"},
-								},
-								VolumeMounts: []corev1.VolumeMount{
-									{Name: "vm0", MountPath: "/etc/default-config0"},
-								},
-							},
-						},
-						Containers: []corev1.Container{
-							{
-								Name:    "c1",
-								Command: []string{""},
-								Resources: corev1.ResourceRequirements{
-									Requests: corev1.ResourceList{
-										corev1.ResourceCPU: resource.MustParse("1"),
-									},
-								},
-								Env: []corev1.EnvVar{
-									{Name: "e1", Value: "default-value1"},
-									{Name: "e2", Value: "default-value2"},
-								},
-								VolumeMounts: []corev1.VolumeMount{
-									{Name: "vm1", MountPath: "/etc/default-config1"},
-									{Name: "vm2", MountPath: "/etc/default-config2"},
-								},
-							},
-							{
-								Name:    "c2",
-								Command: []string{""},
-								Resources: corev1.ResourceRequirements{
-									Requests: corev1.ResourceList{
-										corev1.ResourceCPU: resource.MustParse("2"),
-									},
-								},
-								Env: []corev1.EnvVar{
-									{Name: "e1", Value: "default-value1"},
-									{Name: "e2", Value: "default-value2"},
-								},
-								VolumeMounts: []corev1.VolumeMount{
-									{Name: "vm1", MountPath: "/etc/default-config1"},
-									{Name: "vm2", MountPath: "/etc/default-config2"},
-								},
-							},
-						},
-						Volumes: []corev1.Volume{
-							{
-								Name: "v1",
-								VolumeSource: corev1.VolumeSource{
-									ConfigMap: &corev1.ConfigMapVolumeSource{
-										LocalObjectReference: corev1.LocalObjectReference{
-											Name: "default-config1",
-										},
-									},
-								},
-							},
-							{
-								Name: "v2",
-								VolumeSource: corev1.VolumeSource{
-									ConfigMap: &corev1.ConfigMapVolumeSource{
-										LocalObjectReference: corev1.LocalObjectReference{
-											Name: "default-config2",
-										},
-									},
-								},
-							},
-						},
-					},
-				},
-			},
-		},
-	}
+	testStartTime := time.Now()
+	userID := os.Getenv(constants.SystemEnvVarNameUser)
+
+	testJobTemplateWrapper := wrappers.MakeJobTemplate("job-template", metav1.NamespaceDefault).
+		Parallelism(1).
+		Completions(1).
+		WithInitContainer(
+			*wrappers.MakeContainer("ic1", "").
+				WithEnvVar(corev1.EnvVar{Name: "e0", Value: "default-value0"}).
+				WithVolumeMount(corev1.VolumeMount{Name: "vm0", MountPath: "/etc/default-config0"}).
+				Obj(),
+		).
+		WithContainer(
+			*wrappers.MakeContainer("c1", "").
+				WithRequest(corev1.ResourceCPU, resource.MustParse("1")).
+				WithEnvVar(corev1.EnvVar{Name: "e1", Value: "default-value1"}).
+				WithEnvVar(corev1.EnvVar{Name: "e2", Value: "default-value2"}).
+				WithVolumeMount(corev1.VolumeMount{Name: "vm1", MountPath: "/etc/default-config1"}).
+				WithVolumeMount(corev1.VolumeMount{Name: "vm2", MountPath: "/etc/default-config2"}).
+				Obj(),
+		).
+		WithContainer(*wrappers.MakeContainer("c2", "").
+			WithRequest(corev1.ResourceCPU, resource.MustParse("2")).
+			WithEnvVar(corev1.EnvVar{Name: "e1", Value: "default-value1"}).
+			WithEnvVar(corev1.EnvVar{Name: "e2", Value: "default-value2"}).
+			WithVolumeMount(corev1.VolumeMount{Name: "vm1", MountPath: "/etc/default-config1"}).
+			WithVolumeMount(corev1.VolumeMount{Name: "vm2", MountPath: "/etc/default-config2"}).
+			Obj(),
+		).
+		WithVolume("v1", "default-config1").
+		WithVolume("v2", "default-config2")
 
 	testCases := map[string]struct {
 		namespace   string
@@ -147,18 +93,9 @@ func TestJobBuilder(t *testing.T) {
 			profile:   "profile",
 			mode:      v1alpha1.JobMode,
 			kjobctlObjs: []runtime.Object{
-				&v1alpha1.ApplicationProfile{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "profile",
-						Namespace: metav1.NamespaceDefault,
-					},
-					Spec: v1alpha1.ApplicationProfileSpec{
-						SupportedModes: []v1alpha1.SupportedMode{{
-							Name:     v1alpha1.JobMode,
-							Template: "job-template",
-						}},
-					},
-				},
+				wrappers.MakeApplicationProfile("profile", metav1.NamespaceDefault).
+					WithSupportedMode(v1alpha1.SupportedMode{Name: v1alpha1.JobMode, Template: "job-template"}).
+					Obj(),
 			},
 			wantErr: apierrors.NewNotFound(schema.GroupResource{Group: "kjobctl.x-k8s.io", Resource: "jobtemplates"}, "job-template"),
 		},
@@ -167,34 +104,26 @@ func TestJobBuilder(t *testing.T) {
 			profile:   "profile",
 			mode:      v1alpha1.JobMode,
 			kjobctlObjs: []runtime.Object{
-				testJobTemplate,
-				&v1alpha1.ApplicationProfile{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "profile",
-						Namespace: metav1.NamespaceDefault,
-					},
-					Spec: v1alpha1.ApplicationProfileSpec{
-						SupportedModes: []v1alpha1.SupportedMode{{
-							Name:     v1alpha1.JobMode,
-							Template: "job-template",
-						}},
-					},
-				},
-			},
-			wantObj: &batchv1.Job{
-				TypeMeta: metav1.TypeMeta{
-					Kind:       "Job",
-					APIVersion: "batch/v1",
-				},
-				ObjectMeta: metav1.ObjectMeta{
-					GenerateName: "profile-",
-					Namespace:    metav1.NamespaceDefault,
-					Labels: map[string]string{
-						constants.ProfileLabel: "profile",
-					},
-				},
-				Spec: testJobTemplate.Template.Spec,
+				testJobTemplateWrapper.Clone().Obj(),
+				wrappers.MakeApplicationProfile("profile", metav1.NamespaceDefault).
+					WithSupportedMode(v1alpha1.SupportedMode{Name: v1alpha1.JobMode, Template: "job-template"}).
+					Obj(),
 			},
+			wantObj: wrappers.MakeJob("", metav1.NamespaceDefault).GenerateName("profile-").
+				Label(constants.ProfileLabel, "profile").
+				Spec(
+					testJobTemplateWrapper.Clone().
+						WithEnvVar(corev1.EnvVar{Name: constants.EnvVarNameUserID, Value: userID}).
+						WithEnvVar(corev1.EnvVar{Name: constants.EnvVarTaskName, Value: "default_profile"}).
+						WithEnvVar(corev1.EnvVar{
+							Name:  constants.EnvVarTaskID,
+							Value: fmt.Sprintf("%s_%s_default_profile", userID, testStartTime.Format(time.RFC3339)),
+						}).
+						WithEnvVar(corev1.EnvVar{Name: "PROFILE", Value: "default_profile"}).
+						WithEnvVar(corev1.EnvVar{Name: "TIMESTAMP", Value: testStartTime.Format(time.RFC3339)}).
+						Obj().Template.Spec,
+				).
+				Obj(),
 		},
 		"should build job with replacements": {
 			namespace:   metav1.NamespaceDefault,
@@ -203,169 +132,44 @@ func TestJobBuilder(t *testing.T) {
 			command:     []string{"sleep"},
 			parallelism: ptr.To[int32](2),
 			completions: ptr.To[int32](3),
-			requests: corev1.ResourceList{
-				corev1.ResourceCPU: resource.MustParse("3"),
-			},
-			localQueue: "lq1",
+			requests:    corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("3")},
+			localQueue:  "lq1",
 			kjobctlObjs: []runtime.Object{
-				testJobTemplate,
-				&v1alpha1.ApplicationProfile{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "profile",
-						Namespace: metav1.NamespaceDefault,
-					},
-					Spec: v1alpha1.ApplicationProfileSpec{
-						SupportedModes: []v1alpha1.SupportedMode{{
-							Name:     v1alpha1.JobMode,
-							Template: "job-template",
-						}},
-						VolumeBundles: []v1alpha1.VolumeBundleReference{"vb1", "vb2"},
-					},
-				},
-				&v1alpha1.VolumeBundle{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "vb1",
-						Namespace: metav1.NamespaceDefault,
-					},
-					Spec: v1alpha1.VolumeBundleSpec{
-						Volumes: []corev1.Volume{
-							{
-								Name: "v3",
-								VolumeSource: corev1.VolumeSource{
-									ConfigMap: &corev1.ConfigMapVolumeSource{
-										LocalObjectReference: corev1.LocalObjectReference{
-											Name: "config3",
-										},
-									},
-								},
-							},
-						},
-						ContainerVolumeMounts: []corev1.VolumeMount{
-							{Name: "vm3", MountPath: "/etc/config3"},
-						},
-						EnvVars: []corev1.EnvVar{
-							{Name: "e3", Value: "value3"},
-						},
-					},
-				},
-				&v1alpha1.VolumeBundle{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "vb2",
-						Namespace: metav1.NamespaceDefault,
-					},
-					Spec: v1alpha1.VolumeBundleSpec{},
-				},
-			},
-			wantObj: &batchv1.Job{
-				TypeMeta: metav1.TypeMeta{
-					Kind:       "Job",
-					APIVersion: "batch/v1",
-				},
-				ObjectMeta: metav1.ObjectMeta{
-					GenerateName: "profile-",
-					Namespace:    metav1.NamespaceDefault,
-					Labels: map[string]string{
-						constants.ProfileLabel:    "profile",
-						kueueconstants.QueueLabel: "lq1",
-					},
-				},
-				Spec: batchv1.JobSpec{
-					Parallelism: ptr.To[int32](2),
-					Completions: ptr.To[int32](3),
-					Template: corev1.PodTemplateSpec{
-						Spec: corev1.PodSpec{
-							InitContainers: []corev1.Container{
-								{
-									Name:      "ic1",
-									Command:   []string{""},
-									Resources: corev1.ResourceRequirements{},
-									Env: []corev1.EnvVar{
-										{Name: "e0", Value: "default-value0"},
-										{Name: "e3", Value: "value3"},
-									},
-									VolumeMounts: []corev1.VolumeMount{
-										{Name: "vm0", MountPath: "/etc/default-config0"},
-										{Name: "vm3", MountPath: "/etc/config3"},
-									},
-								},
-							},
-							Containers: []corev1.Container{
-								{
-									Name:    "c1",
-									Command: []string{"sleep"},
-									Resources: corev1.ResourceRequirements{
-										Requests: corev1.ResourceList{
-											corev1.ResourceCPU: resource.MustParse("3"),
-										},
-									},
-									Env: []corev1.EnvVar{
-										{Name: "e1", Value: "default-value1"},
-										{Name: "e2", Value: "default-value2"},
-										{Name: "e3", Value: "value3"},
-									},
-									VolumeMounts: []corev1.VolumeMount{
-										{Name: "vm1", MountPath: "/etc/default-config1"},
-										{Name: "vm2", MountPath: "/etc/default-config2"},
-										{Name: "vm3", MountPath: "/etc/config3"},
-									},
-								},
-								{
-									Name:    "c2",
-									Command: []string{""},
-									Resources: corev1.ResourceRequirements{
-										Requests: corev1.ResourceList{
-											corev1.ResourceCPU: resource.MustParse("2"),
-										},
-									},
-									Env: []corev1.EnvVar{
-										{Name: "e1", Value: "default-value1"},
-										{Name: "e2", Value: "default-value2"},
-										{Name: "e3", Value: "value3"},
-									},
-									VolumeMounts: []corev1.VolumeMount{
-										{Name: "vm1", MountPath: "/etc/default-config1"},
-										{Name: "vm2", MountPath: "/etc/default-config2"},
-										{Name: "vm3", MountPath: "/etc/config3"},
-									},
-								},
-							},
-							Volumes: []corev1.Volume{
-								{
-									Name: "v1",
-									VolumeSource: corev1.VolumeSource{
-										ConfigMap: &corev1.ConfigMapVolumeSource{
-											LocalObjectReference: corev1.LocalObjectReference{
-												Name: "default-config1",
-											},
-										},
-									},
-								},
-								{
-									Name: "v2",
-									VolumeSource: corev1.VolumeSource{
-										ConfigMap: &corev1.ConfigMapVolumeSource{
-											LocalObjectReference: corev1.LocalObjectReference{
-												Name: "default-config2",
-											},
-										},
-									},
-								},
-								{
-									Name: "v3",
-									VolumeSource: corev1.VolumeSource{
-										ConfigMap: &corev1.ConfigMapVolumeSource{
-											LocalObjectReference: corev1.LocalObjectReference{
-												Name: "config3",
-											},
-										},
-									},
-								},
-							},
-						},
-					},
-				},
+				testJobTemplateWrapper.Clone().Obj(),
+				wrappers.MakeApplicationProfile("profile", metav1.NamespaceDefault).
+					WithSupportedMode(v1alpha1.SupportedMode{Name: v1alpha1.JobMode, Template: "job-template"}).
+					WithVolumeBundleReferences("vb1", "vb2").
+					Obj(),
+				wrappers.MakeVolumeBundle("vb1", metav1.NamespaceDefault).
+					WithVolume("v3", "config3").
+					WithVolumeMount(corev1.VolumeMount{Name: "vm3", MountPath: "/etc/config3"}).
+					WithEnvVar(corev1.EnvVar{Name: "e3", Value: "value3"}).
+					Obj(),
+				wrappers.MakeVolumeBundle("vb2", metav1.NamespaceDefault).Obj(),
 			},
-			wantErr: nil,
+			wantObj: wrappers.MakeJob("", metav1.NamespaceDefault).GenerateName("profile-").
+				Label(constants.ProfileLabel, "profile").
+				Label(kueueconstants.QueueLabel, "lq1").
+				Spec(
+					testJobTemplateWrapper.Clone().
+						Command([]string{"sleep"}).
+						Parallelism(2).
+						Completions(3).
+						WithRequest(corev1.ResourceCPU, resource.MustParse("3")).
+						WithVolume("v3", "config3").
+						WithVolumeMount(corev1.VolumeMount{Name: "vm3", MountPath: "/etc/config3"}).
+						WithEnvVar(corev1.EnvVar{Name: "e3", Value: "value3"}).
+						WithEnvVar(corev1.EnvVar{Name: constants.EnvVarNameUserID, Value: userID}).
+						WithEnvVar(corev1.EnvVar{Name: constants.EnvVarTaskName, Value: "default_profile"}).
+						WithEnvVar(corev1.EnvVar{
+							Name:  constants.EnvVarTaskID,
+							Value: fmt.Sprintf("%s_%s_default_profile", userID, testStartTime.Format(time.RFC3339)),
+						}).
+						WithEnvVar(corev1.EnvVar{Name: "PROFILE", Value: "default_profile"}).
+						WithEnvVar(corev1.EnvVar{Name: "TIMESTAMP", Value: testStartTime.Format(time.RFC3339)}).
+						Obj().Template.Spec,
+				).
+				Obj(),
 		},
 	}
 	for name, tc := range testCases {
@@ -376,7 +180,7 @@ func TestJobBuilder(t *testing.T) {
 			tcg := cmdtesting.NewTestClientGetter().
 				WithKjobctlClientset(kjobctlfake.NewSimpleClientset(tc.kjobctlObjs...))
 
-			gotObjs, gotErr := NewBuilder(tcg).
+			gotObjs, gotErr := NewBuilder(tcg, testStartTime).
 				WithNamespace(tc.namespace).
 				WithProfileName(tc.profile).
 				WithModeName(tc.mode).
diff --git a/cmd/experimental/kjobctl/pkg/cmd/create/create_test.go b/cmd/experimental/kjobctl/pkg/cmd/create/create_test.go
index 7ad6a2d0b..9f3939116 100644
--- a/cmd/experimental/kjobctl/pkg/cmd/create/create_test.go
+++ b/cmd/experimental/kjobctl/pkg/cmd/create/create_test.go
@@ -18,10 +18,16 @@ package create
 
 import (
 	"context"
+	"fmt"
+	"io"
+	"net/url"
+	"os"
 	"testing"
+	"time"
 
 	"github.com/google/go-cmp/cmp"
 	batchv1 "k8s.io/api/batch/v1"
+	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/meta"
 	"k8s.io/apimachinery/pkg/api/resource"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -30,26 +36,28 @@ import (
 	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 	"k8s.io/cli-runtime/pkg/genericiooptions"
 	"k8s.io/client-go/dynamic/fake"
+	k8sfake "k8s.io/client-go/kubernetes/fake"
 	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
+	restclient "k8s.io/client-go/rest"
+	"k8s.io/client-go/tools/remotecommand"
+	clocktesting "k8s.io/utils/clock/testing"
 
 	"sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1"
 	kjobctlfake "sigs.k8s.io/kueue/cmd/experimental/kjobctl/client-go/clientset/versioned/fake"
 	cmdtesting "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/cmd/testing"
+	"sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/constants"
 	"sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/testing/wrappers"
 )
 
 func TestCreateOptions_Complete(t *testing.T) {
+	testStartTime := time.Now()
+
 	testCases := map[string]struct {
 		args        []string
 		options     *CreateOptions
 		wantOptions *CreateOptions
 		wantErr     string
 	}{
-		"invalid mode": {
-			args:    []string{"invalid"},
-			options: &CreateOptions{},
-			wantErr: invalidApplicationProfileModeErr.Error(),
-		},
 		"invalid request": {
 			args: []string{"job"},
 			options: &CreateOptions{
@@ -67,12 +75,12 @@ func TestCreateOptions_Complete(t *testing.T) {
 
 			tcg := cmdtesting.NewTestClientGetter()
 
-			cmd := NewCreateCmd(tcg, streams)
+			cmd := NewCreateCmd(tcg, streams, clocktesting.NewFakeClock(testStartTime))
 			cmd.SetOut(out)
 			cmd.SetErr(outErr)
 			cmd.SetArgs(tc.args)
 
-			gotErr := tc.options.Complete(tcg, cmd, tc.args)
+			gotErr := tc.options.Complete(tcg, cmd.Commands()[0])
 
 			var gotErrStr string
 			if gotErr != nil {
@@ -91,6 +99,9 @@ func TestCreateOptions_Complete(t *testing.T) {
 }
 
 func TestCreateCmd(t *testing.T) {
+	testStartTime := time.Now()
+	userID := os.Getenv(constants.SystemEnvVarNameUser)
+
 	testCases := map[string]struct {
 		ns          string
 		args        []string
@@ -101,14 +112,6 @@ func TestCreateCmd(t *testing.T) {
 		wantOutErr  string
 		wantErr     string
 	}{
-		"shouldn't create job without mode": {
-			args:    []string{},
-			wantErr: `accepts 1 arg(s), received 0`,
-		},
-		"shouldn't create job with invalid mode": {
-			args:    []string{"invalid"},
-			wantErr: `invalid argument "invalid" for "create"`,
-		},
 		"should create job": {
 			args: []string{"job", "--profile", "profile"},
 			kjobctlObjs: []runtime.Object{
@@ -249,6 +252,14 @@ func TestCreateCmd(t *testing.T) {
 						Completions(1).
 						WithContainer(*wrappers.MakeContainer("c1", "sleep").Command("sleep", "15s").Obj()).
 						WithContainer(*wrappers.MakeContainer("c2", "sleep").Obj()).
+						WithEnvVar(corev1.EnvVar{Name: constants.EnvVarNameUserID, Value: userID}).
+						WithEnvVar(corev1.EnvVar{Name: constants.EnvVarTaskName, Value: "default_profile"}).
+						WithEnvVar(corev1.EnvVar{
+							Name:  constants.EnvVarTaskID,
+							Value: fmt.Sprintf("%s_%s_default_profile", userID, testStartTime.Format(time.RFC3339)),
+						}).
+						WithEnvVar(corev1.EnvVar{Name: "PROFILE", Value: "default_profile"}).
+						WithEnvVar(corev1.EnvVar{Name: "TIMESTAMP", Value: testStartTime.Format(time.RFC3339)}).
 						Obj(),
 				},
 			},
@@ -283,10 +294,15 @@ func TestCreateCmd(t *testing.T) {
 								WithRequest("ram", resource.MustParse("3Gi")).
 								Obj(),
 						).
-						WithContainer(
-							*wrappers.MakeContainer("c2", "sleep").
-								Obj(),
-						).
+						WithContainer(*wrappers.MakeContainer("c2", "sleep").Obj()).
+						WithEnvVar(corev1.EnvVar{Name: constants.EnvVarNameUserID, Value: userID}).
+						WithEnvVar(corev1.EnvVar{Name: constants.EnvVarTaskName, Value: "default_profile"}).
+						WithEnvVar(corev1.EnvVar{
+							Name:  constants.EnvVarTaskID,
+							Value: fmt.Sprintf("%s_%s_default_profile", userID, testStartTime.Format(time.RFC3339)),
+						}).
+						WithEnvVar(corev1.EnvVar{Name: "PROFILE", Value: "default_profile"}).
+						WithEnvVar(corev1.EnvVar{Name: "TIMESTAMP", Value: testStartTime.Format(time.RFC3339)}).
 						Obj(),
 				},
 			},
@@ -331,7 +347,7 @@ func TestCreateCmd(t *testing.T) {
 				tcg.WithNamespace(tc.ns)
 			}
 
-			cmd := NewCreateCmd(tcg, streams)
+			cmd := NewCreateCmd(tcg, streams, clocktesting.NewFakeClock(testStartTime))
 			cmd.SetOut(out)
 			cmd.SetErr(outErr)
 			cmd.SetArgs(tc.args)
@@ -388,3 +404,141 @@ func TestCreateCmd(t *testing.T) {
 		})
 	}
 }
+
+func TestInteractivePod(t *testing.T) {
+	testCases := map[string]struct {
+		podName string
+		options *CreateOptions
+		pods    []runtime.Object
+		wantErr string
+	}{
+		"success": {
+			podName: "foo",
+			options: &CreateOptions{
+				Namespace:  "test",
+				Attach:     &fakeRemoteAttach{},
+				AttachFunc: testAttachFunc,
+			},
+			pods: []runtime.Object{
+				&corev1.Pod{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "foo",
+						Namespace: "test",
+					},
+					Spec: corev1.PodSpec{
+						Containers: []corev1.Container{
+							{
+								Name:  "bar",
+								Stdin: true,
+								TTY:   true,
+							},
+						},
+					},
+					Status: corev1.PodStatus{
+						Phase: corev1.PodRunning,
+					},
+				},
+			},
+		},
+		"tty not allocated": {
+			podName: "foo",
+			options: &CreateOptions{
+				Namespace:  "test",
+				Attach:     &fakeRemoteAttach{},
+				AttachFunc: testAttachFunc,
+			},
+			pods: []runtime.Object{
+				&corev1.Pod{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "foo",
+						Namespace: "test",
+					},
+					Spec: corev1.PodSpec{
+						Containers: []corev1.Container{
+							{
+								Name: "bar",
+							},
+						},
+					},
+					Status: corev1.PodStatus{
+						Phase: corev1.PodRunning,
+					},
+				},
+			},
+			wantErr: "error: Unable to use a TTY - container bar did not allocate one",
+		},
+		"timeout waiting for pod": {
+			podName: "foo",
+			options: &CreateOptions{
+				Namespace:         "test",
+				Attach:            &fakeRemoteAttach{},
+				AttachFunc:        testAttachFunc,
+				PodRunningTimeout: 1 * time.Second,
+			},
+			pods: []runtime.Object{
+				&corev1.Pod{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "foo",
+						Namespace: "test",
+					},
+					Spec: corev1.PodSpec{
+						Containers: []corev1.Container{
+							{
+								Name:  "bar",
+								Stdin: true,
+								TTY:   true,
+							},
+						},
+					},
+					Status: corev1.PodStatus{
+						Phase: corev1.PodPending,
+					},
+				},
+			},
+			wantErr: "context deadline exceeded",
+		},
+	}
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			streams, _, out, outErr := genericiooptions.NewTestIOStreams()
+			tc.options.IOStreams = streams
+			tc.options.Out = out
+			tc.options.ErrOut = outErr
+
+			clientset := k8sfake.NewSimpleClientset(tc.pods...)
+			tcg := cmdtesting.NewTestClientGetter().WithK8sClientset(clientset)
+
+			gotErr := tc.options.RunInteractivePod(context.TODO(), tcg, tc.podName)
+
+			var gotErrStr string
+			if gotErr != nil {
+				gotErrStr = gotErr.Error()
+			}
+
+			if diff := cmp.Diff(tc.wantErr, gotErrStr); diff != "" {
+				t.Errorf("Unexpected error (-want/+got)\n%s", diff)
+			}
+		})
+	}
+}
+
+type fakeRemoteAttach struct {
+	url *url.URL
+	err error
+}
+
+func (f *fakeRemoteAttach) Attach(url *url.URL, config *restclient.Config, stdin io.Reader, stdout, stderr io.Writer, tty bool, terminalSizeQueue remotecommand.TerminalSizeQueue) error {
+	f.url = url
+	return f.err
+}
+
+func testAttachFunc(o *CreateOptions, containerToAttach *corev1.Container, sizeQueue remotecommand.TerminalSizeQueue, pod *corev1.Pod) func() error {
+	return func() error {
+		u, err := url.Parse("http://kjobctl.test")
+		if err != nil {
+			return err
+		}
+
+		return o.Attach.Attach(u, nil, nil, nil, nil, o.TTY, sizeQueue)
+	}
+}
diff --git a/cmd/experimental/kjobctl/pkg/cmd/testing/fake.go b/cmd/experimental/kjobctl/pkg/cmd/testing/fake.go
index 09d3f4b6d..b698e73ca 100644
--- a/cmd/experimental/kjobctl/pkg/cmd/testing/fake.go
+++ b/cmd/experimental/kjobctl/pkg/cmd/testing/fake.go
@@ -23,6 +23,7 @@ import (
 	"k8s.io/client-go/dynamic"
 	k8s "k8s.io/client-go/kubernetes"
 	k8sfake "k8s.io/client-go/kubernetes/fake"
+	"k8s.io/client-go/rest"
 	"k8s.io/client-go/tools/clientcmd"
 
 	kueueversioned "sigs.k8s.io/kueue/client-go/clientset/versioned"
@@ -39,11 +40,15 @@ type TestClientGetter struct {
 	kjobctlClientset kjobctlversioned.Interface
 	dynamicClient    dynamic.Interface
 
+	restConfig *rest.Config
+
 	configFlags *genericclioptions.TestConfigFlags
 }
 
 func NewTestClientGetter() *TestClientGetter {
 	clientConfig := &clientcmd.DeferredLoadingClientConfig{}
+	restConfig := &rest.Config{}
+
 	configFlags := genericclioptions.NewTestConfigFlags().
 		WithClientConfig(clientConfig).
 		WithNamespace(metav1.NamespaceDefault)
@@ -51,6 +56,7 @@ func NewTestClientGetter() *TestClientGetter {
 		ClientGetter:     util.NewClientGetter(configFlags),
 		kjobctlClientset: kjobctlfake.NewSimpleClientset(),
 		k8sClientset:     k8sfake.NewSimpleClientset(),
+		restConfig:       restConfig,
 		configFlags:      configFlags,
 	}
 }
@@ -65,6 +71,15 @@ func (cg *TestClientGetter) WithRESTMapper(mapper meta.RESTMapper) *TestClientGe
 	return cg
 }
 
+func (cg *TestClientGetter) WithRESTConfig(config *rest.Config) *TestClientGetter {
+	cg.restConfig = config
+	return cg
+}
+
+func (cg *TestClientGetter) ToRESTConfig() (*rest.Config, error) {
+	return cg.restConfig, nil
+}
+
 func (cg *TestClientGetter) WithK8sClientset(clientset k8s.Interface) *TestClientGetter {
 	cg.k8sClientset = clientset
 	return cg
diff --git a/cmd/experimental/kjobctl/pkg/testing/wrappers/application_profile_wrappers.go b/cmd/experimental/kjobctl/pkg/testing/wrappers/application_profile_wrappers.go
index 8cd54fbe1..de6cb8806 100644
--- a/cmd/experimental/kjobctl/pkg/testing/wrappers/application_profile_wrappers.go
+++ b/cmd/experimental/kjobctl/pkg/testing/wrappers/application_profile_wrappers.go
@@ -51,3 +51,9 @@ func (ap *ApplicationProfileWrapper) WithSupportedMode(supportedMode v1alpha1.Su
 	ap.Spec.SupportedModes = append(ap.Spec.SupportedModes, supportedMode)
 	return ap
 }
+
+// WithVolumeBundleReferences adds WithVolumeBundleReferences to VolumeBundles.
+func (ap *ApplicationProfileWrapper) WithVolumeBundleReferences(volumeBundleReferences ...v1alpha1.VolumeBundleReference) *ApplicationProfileWrapper {
+	ap.Spec.VolumeBundles = append(ap.Spec.VolumeBundles, volumeBundleReferences...)
+	return ap
+}
diff --git a/cmd/experimental/kjobctl/pkg/testing/wrappers/container_wrappers.go b/cmd/experimental/kjobctl/pkg/testing/wrappers/container_wrappers.go
index 771b659f0..b22d4e60f 100644
--- a/cmd/experimental/kjobctl/pkg/testing/wrappers/container_wrappers.go
+++ b/cmd/experimental/kjobctl/pkg/testing/wrappers/container_wrappers.go
@@ -50,3 +50,21 @@ func (c *ContainerWrapper) WithRequest(resourceName corev1.ResourceName, quantit
 	c.Resources.Requests[resourceName] = quantity
 	return c
 }
+
+// WithResources set Resources.
+func (c *ContainerWrapper) WithResources(resourceRequirements corev1.ResourceRequirements) *ContainerWrapper {
+	c.Container.Resources = resourceRequirements
+	return c
+}
+
+// WithEnvVar add EnvVar to Env.
+func (c *ContainerWrapper) WithEnvVar(envVar corev1.EnvVar) *ContainerWrapper {
+	c.Container.Env = append(c.Container.Env, envVar)
+	return c
+}
+
+// WithVolumeMount add VolumeMount to VolumeMounts.
+func (c *ContainerWrapper) WithVolumeMount(volumeMount corev1.VolumeMount) *ContainerWrapper {
+	c.Container.VolumeMounts = append(c.Container.VolumeMounts, volumeMount)
+	return c
+}
diff --git a/cmd/experimental/kjobctl/pkg/testing/wrappers/job_template_wrappers.go b/cmd/experimental/kjobctl/pkg/testing/wrappers/job_template_wrappers.go
index 55b6f7896..99aedd410 100644
--- a/cmd/experimental/kjobctl/pkg/testing/wrappers/job_template_wrappers.go
+++ b/cmd/experimental/kjobctl/pkg/testing/wrappers/job_template_wrappers.go
@@ -18,6 +18,7 @@ package wrappers
 
 import (
 	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/api/resource"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/utils/ptr"
 
@@ -62,8 +63,81 @@ func (j *JobTemplateWrapper) RestartPolicy(restartPolicy corev1.RestartPolicy) *
 	return j
 }
 
+// WithInitContainer add init container to the pod template.
+func (j *JobTemplateWrapper) WithInitContainer(container corev1.Container) *JobTemplateWrapper {
+	j.Template.Spec.Template.Spec.InitContainers = append(j.Template.Spec.Template.Spec.InitContainers, container)
+	return j
+}
+
 // WithContainer add container to the pod template.
 func (j *JobTemplateWrapper) WithContainer(container corev1.Container) *JobTemplateWrapper {
 	j.Template.Spec.Template.Spec.Containers = append(j.Template.Spec.Template.Spec.Containers, container)
 	return j
 }
+
+// Clone clone JobTemplateWrapper.
+func (j *JobTemplateWrapper) Clone() *JobTemplateWrapper {
+	return &JobTemplateWrapper{
+		JobTemplate: *j.JobTemplate.DeepCopy(),
+	}
+}
+
+// WithVolume add volume to the job template.
+func (j *JobTemplateWrapper) WithVolume(name, localObjectReferenceName string) *JobTemplateWrapper {
+	j.Template.Spec.Template.Spec.Volumes = append(j.Template.Spec.Template.Spec.Volumes, corev1.Volume{
+		Name: name,
+		VolumeSource: corev1.VolumeSource{
+			ConfigMap: &corev1.ConfigMapVolumeSource{
+				LocalObjectReference: corev1.LocalObjectReference{
+					Name: localObjectReferenceName,
+				},
+			},
+		},
+	})
+	return j
+}
+
+// WithEnvVar add volume to the job template.
+func (j *JobTemplateWrapper) WithEnvVar(envVar corev1.EnvVar) *JobTemplateWrapper {
+	for index := range j.Template.Spec.Template.Spec.InitContainers {
+		j.Template.Spec.Template.Spec.InitContainers[index].Env =
+			append(j.Template.Spec.Template.Spec.InitContainers[index].Env, envVar)
+	}
+	for index := range j.Template.Spec.Template.Spec.Containers {
+		j.Template.Spec.Template.Spec.Containers[index].Env =
+			append(j.Template.Spec.Template.Spec.Containers[index].Env, envVar)
+	}
+	return j
+}
+
+// WithVolumeMount add volume mount to pod templates.
+func (j *JobTemplateWrapper) WithVolumeMount(volumeMount corev1.VolumeMount) *JobTemplateWrapper {
+	for index := range j.Template.Spec.Template.Spec.InitContainers {
+		j.Template.Spec.Template.Spec.InitContainers[index].VolumeMounts =
+			append(j.Template.Spec.Template.Spec.InitContainers[index].VolumeMounts, volumeMount)
+	}
+	for index := range j.Template.Spec.Template.Spec.Containers {
+		j.Template.Spec.Template.Spec.Containers[index].VolumeMounts =
+			append(j.Template.Spec.Template.Spec.Containers[index].VolumeMounts, volumeMount)
+	}
+	return j
+}
+
+// Command set command to primary pod templates.
+func (j *JobTemplateWrapper) Command(command []string) *JobTemplateWrapper {
+	if len(j.Template.Spec.Template.Spec.Containers) > 0 {
+		j.Template.Spec.Template.Spec.Containers[0].Command = command
+	}
+	return j
+}
+
+// WithRequest set command to primary pod templates.
+func (j *JobTemplateWrapper) WithRequest(key corev1.ResourceName, value resource.Quantity) *JobTemplateWrapper {
+	if len(j.Template.Spec.Template.Spec.Containers) > 0 {
+		if j.Template.Spec.Template.Spec.Containers[0].Resources.Requests == nil {
+			j.Template.Spec.Template.Spec.Containers[0].Resources.Requests = make(corev1.ResourceList)
+		}
+		j.Template.Spec.Template.Spec.Containers[0].Resources.Requests[key] = value
+	}
+	return j
+}
diff --git a/cmd/experimental/kjobctl/pkg/testing/wrappers/job_wrappers.go b/cmd/experimental/kjobctl/pkg/testing/wrappers/job_wrappers.go
index b27ef0a77..5bf09b121 100644
--- a/cmd/experimental/kjobctl/pkg/testing/wrappers/job_wrappers.go
+++ b/cmd/experimental/kjobctl/pkg/testing/wrappers/job_wrappers.go
@@ -57,13 +57,13 @@ func (j *JobWrapper) GenerateName(v string) *JobWrapper {
 
 // Completions updates job completions.
 func (j *JobWrapper) Completions(v int32) *JobWrapper {
-	j.Spec.Completions = ptr.To(v)
+	j.Job.Spec.Completions = ptr.To(v)
 	return j
 }
 
 // Parallelism updates job parallelism.
 func (j *JobWrapper) Parallelism(v int32) *JobWrapper {
-	j.Spec.Parallelism = ptr.To(v)
+	j.Job.Spec.Parallelism = ptr.To(v)
 	return j
 }
 
@@ -88,13 +88,26 @@ func (j *JobWrapper) Label(key, value string) *JobWrapper {
 
 // WithContainer add container on the pod template.
 func (j *JobWrapper) WithContainer(container corev1.Container) *JobWrapper {
-	j.Spec.Template.Spec.Containers = append(j.Spec.Template.Spec.Containers, container)
+	j.Job.Spec.Template.Spec.Containers = append(j.Job.Spec.Template.Spec.Containers, container)
+	return j
+}
+
+// WithEnvVar add volume to the pod template.
+func (j *JobWrapper) WithEnvVar(envVar corev1.EnvVar) *JobWrapper {
+	for index := range j.Job.Spec.Template.Spec.InitContainers {
+		j.Job.Spec.Template.Spec.InitContainers[index].Env =
+			append(j.Job.Spec.Template.Spec.InitContainers[index].Env, envVar)
+	}
+	for index := range j.Job.Spec.Template.Spec.Containers {
+		j.Job.Spec.Template.Spec.Containers[index].Env =
+			append(j.Job.Spec.Template.Spec.Containers[index].Env, envVar)
+	}
 	return j
 }
 
 // RestartPolicy updates the restartPolicy on the pod template.
 func (j *JobWrapper) RestartPolicy(restartPolicy corev1.RestartPolicy) *JobWrapper {
-	j.Spec.Template.Spec.RestartPolicy = restartPolicy
+	j.Job.Spec.Template.Spec.RestartPolicy = restartPolicy
 	return j
 }
 
@@ -121,3 +134,9 @@ func (j *JobWrapper) Succeeded(value int32) *JobWrapper {
 	j.Status.Succeeded = value
 	return j
 }
+
+// Spec set job spec.
+func (j *JobWrapper) Spec(spec batchv1.JobSpec) *JobWrapper {
+	j.Job.Spec = spec
+	return j
+}
diff --git a/cmd/experimental/kjobctl/pkg/testing/wrappers/pod_template_wrappers.go b/cmd/experimental/kjobctl/pkg/testing/wrappers/pod_template_wrappers.go
new file mode 100644
index 000000000..b8752b615
--- /dev/null
+++ b/cmd/experimental/kjobctl/pkg/testing/wrappers/pod_template_wrappers.go
@@ -0,0 +1,135 @@
+/*
+Copyright 2024 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package wrappers
+
+import (
+	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/api/resource"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// PodTemplateWrapper wraps a PodTemplate.
+type PodTemplateWrapper struct{ corev1.PodTemplate }
+
+// MakePodTemplate creates a wrapper for a PodTemplate.
+func MakePodTemplate(name, ns string) *PodTemplateWrapper {
+	return &PodTemplateWrapper{
+		PodTemplate: corev1.PodTemplate{
+			ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: ns},
+		},
+	}
+}
+
+// Obj returns the inner PodTemplate.
+func (p *PodTemplateWrapper) Obj() *corev1.PodTemplate {
+	return &p.PodTemplate
+}
+
+// Clone clone PodTemplateWrapper.
+func (p *PodTemplateWrapper) Clone() *PodTemplateWrapper {
+	return &PodTemplateWrapper{
+		PodTemplate: *p.PodTemplate.DeepCopy(),
+	}
+}
+
+// WithInitContainer add container to the pod template.
+func (p *PodTemplateWrapper) WithInitContainer(container corev1.Container) *PodTemplateWrapper {
+	p.PodTemplate.Template.Spec.InitContainers = append(p.PodTemplate.Template.Spec.InitContainers, container)
+	return p
+}
+
+// WithContainer add container to the pod template.
+func (p *PodTemplateWrapper) WithContainer(container corev1.Container) *PodTemplateWrapper {
+	p.PodTemplate.Template.Spec.Containers = append(p.PodTemplate.Template.Spec.Containers, container)
+	return p
+}
+
+// WithVolume add volume to the pod template.
+func (p *PodTemplateWrapper) WithVolume(name, localObjectReferenceName string) *PodTemplateWrapper {
+	p.Template.Spec.Volumes = append(p.Template.Spec.Volumes, corev1.Volume{
+		Name: name,
+		VolumeSource: corev1.VolumeSource{
+			ConfigMap: &corev1.ConfigMapVolumeSource{
+				LocalObjectReference: corev1.LocalObjectReference{
+					Name: localObjectReferenceName,
+				},
+			},
+		},
+	})
+	return p
+}
+
+// WithEnvVar add volume to the pod template.
+func (p *PodTemplateWrapper) WithEnvVar(envVar corev1.EnvVar) *PodTemplateWrapper {
+	for index := range p.Template.Spec.InitContainers {
+		p.Template.Spec.InitContainers[index].Env =
+			append(p.Template.Spec.InitContainers[index].Env, envVar)
+	}
+	for index := range p.Template.Spec.Containers {
+		p.Template.Spec.Containers[index].Env =
+			append(p.Template.Spec.Containers[index].Env, envVar)
+	}
+	return p
+}
+
+// WithVolumeMount add volume mount to pod templates.
+func (p *PodTemplateWrapper) WithVolumeMount(volumeMount corev1.VolumeMount) *PodTemplateWrapper {
+	for index := range p.Template.Spec.InitContainers {
+		p.Template.Spec.InitContainers[index].VolumeMounts =
+			append(p.Template.Spec.InitContainers[index].VolumeMounts, volumeMount)
+	}
+	for index := range p.Template.Spec.Containers {
+		p.Template.Spec.Containers[index].VolumeMounts =
+			append(p.Template.Spec.Containers[index].VolumeMounts, volumeMount)
+	}
+	return p
+}
+
+// Command set command to primary pod templates.
+func (p *PodTemplateWrapper) Command(command []string) *PodTemplateWrapper {
+	if len(p.Template.Spec.Containers) > 0 {
+		p.Template.Spec.Containers[0].Command = command
+	}
+	return p
+}
+
+// WithRequest set command to primary pod templates.
+func (p *PodTemplateWrapper) WithRequest(key corev1.ResourceName, value resource.Quantity) *PodTemplateWrapper {
+	if len(p.Template.Spec.Containers) > 0 {
+		if p.Template.Spec.Containers[0].Resources.Requests == nil {
+			p.Template.Spec.Containers[0].Resources.Requests = make(corev1.ResourceList)
+		}
+		p.Template.Spec.Containers[0].Resources.Requests[key] = value
+	}
+	return p
+}
+
+// TTY set tty=true on primary pod templates.
+func (p *PodTemplateWrapper) TTY() *PodTemplateWrapper {
+	if len(p.Template.Spec.Containers) > 0 {
+		p.Template.Spec.Containers[0].TTY = true
+	}
+	return p
+}
+
+// Stdin set stdin=true on primary pod templates.
+func (p *PodTemplateWrapper) Stdin() *PodTemplateWrapper {
+	if len(p.Template.Spec.Containers) > 0 {
+		p.Template.Spec.Containers[0].Stdin = true
+	}
+	return p
+}
diff --git a/cmd/experimental/kjobctl/pkg/testing/wrappers/pod_wrappers.go b/cmd/experimental/kjobctl/pkg/testing/wrappers/pod_wrappers.go
new file mode 100644
index 000000000..1bfd69e02
--- /dev/null
+++ b/cmd/experimental/kjobctl/pkg/testing/wrappers/pod_wrappers.go
@@ -0,0 +1,100 @@
+/*
+Copyright 2024 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package wrappers
+
+import (
+	"time"
+
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	"sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/constants"
+	kueueconstants "sigs.k8s.io/kueue/pkg/controller/constants"
+)
+
+// PodWrapper wraps a Pod.
+type PodWrapper struct{ corev1.Pod }
+
+// MakePod creates a wrapper for a Pod
+func MakePod(name, ns string) *PodWrapper {
+	return &PodWrapper{
+		corev1.Pod{
+			TypeMeta:   metav1.TypeMeta{Kind: "Pod", APIVersion: "v1"},
+			ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: ns},
+		},
+	}
+}
+
+// Obj returns the inner Pod.
+func (j *PodWrapper) Obj() *corev1.Pod {
+	return &j.Pod
+}
+
+// GenerateName updates generateName.
+func (j *PodWrapper) GenerateName(v string) *PodWrapper {
+	j.ObjectMeta.GenerateName = v
+	return j
+}
+
+// Profile sets the profile label.
+func (j *PodWrapper) Profile(v string) *PodWrapper {
+	return j.Label(constants.ProfileLabel, v)
+}
+
+// LocalQueue sets the localqueue label.
+func (j *PodWrapper) LocalQueue(v string) *PodWrapper {
+	return j.Label(kueueconstants.QueueLabel, v)
+}
+
+// Label sets the label key and value.
+func (j *PodWrapper) Label(key, value string) *PodWrapper {
+	if j.Labels == nil {
+		j.Labels = make(map[string]string)
+	}
+	j.ObjectMeta.Labels[key] = value
+	return j
+}
+
+// WithContainer add container on the pod template.
+func (j *PodWrapper) WithContainer(container corev1.Container) *PodWrapper {
+	j.Pod.Spec.Containers = append(j.Pod.Spec.Containers, container)
+	return j
+}
+
+// RestartPolicy updates the restartPolicy on the pod template.
+func (j *PodWrapper) RestartPolicy(restartPolicy corev1.RestartPolicy) *PodWrapper {
+	j.Pod.Spec.RestartPolicy = restartPolicy
+	return j
+}
+
+// CreationTimestamp sets the .metadata.creationTimestamp.
+func (j *PodWrapper) CreationTimestamp(t time.Time) *PodWrapper {
+	j.ObjectMeta.CreationTimestamp = metav1.NewTime(t)
+	return j
+}
+
+// StartTime sets the .status.startTime.
+func (j *PodWrapper) StartTime(t time.Time) *PodWrapper {
+	j.Status.StartTime = &metav1.Time{Time: t}
+	return j
+}
+
+// Spec set pod spec.
+func (j *PodWrapper) Spec(spec corev1.PodSpec) *PodWrapper {
+	j.Pod.Spec = spec
+	return j
+}
diff --git a/cmd/experimental/kjobctl/pkg/testing/wrappers/volume_bundle_wrappers.go b/cmd/experimental/kjobctl/pkg/testing/wrappers/volume_bundle_wrappers.go
new file mode 100644
index 000000000..d220c93ec
--- /dev/null
+++ b/cmd/experimental/kjobctl/pkg/testing/wrappers/volume_bundle_wrappers.go
@@ -0,0 +1,71 @@
+/*
+Copyright 2024 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package wrappers
+
+import (
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	"sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1"
+)
+
+// VolumeBundleWrapper wraps a VolumeBundle.
+type VolumeBundleWrapper struct{ v1alpha1.VolumeBundle }
+
+// MakeVolumeBundle creates a wrapper for a VolumeBundle
+func MakeVolumeBundle(name, namespace string) *VolumeBundleWrapper {
+	return &VolumeBundleWrapper{
+		VolumeBundle: v1alpha1.VolumeBundle{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      name,
+				Namespace: namespace,
+			},
+		},
+	}
+}
+
+// Obj returns the inner VolumeBundle.
+func (vb *VolumeBundleWrapper) Obj() *v1alpha1.VolumeBundle {
+	return &vb.VolumeBundle
+}
+
+// WithVolume add volume on the volumes.
+func (vb *VolumeBundleWrapper) WithVolume(name, localObjectReferenceName string) *VolumeBundleWrapper {
+	vb.VolumeBundle.Spec.Volumes = append(vb.VolumeBundle.Spec.Volumes, corev1.Volume{
+		Name: name,
+		VolumeSource: corev1.VolumeSource{
+			ConfigMap: &corev1.ConfigMapVolumeSource{
+				LocalObjectReference: corev1.LocalObjectReference{
+					Name: localObjectReferenceName,
+				},
+			},
+		},
+	})
+	return vb
+}
+
+// WithVolumeMount add volume mount on the volumes.
+func (vb *VolumeBundleWrapper) WithVolumeMount(volumeMount corev1.VolumeMount) *VolumeBundleWrapper {
+	vb.VolumeBundle.Spec.ContainerVolumeMounts = append(vb.VolumeBundle.Spec.ContainerVolumeMounts, volumeMount)
+	return vb
+}
+
+// WithEnvVar add EnvVar to EnvVars.
+func (vb *VolumeBundleWrapper) WithEnvVar(envVar corev1.EnvVar) *VolumeBundleWrapper {
+	vb.Spec.EnvVars = append(vb.Spec.EnvVars, envVar)
+	return vb
+}
diff --git a/cmd/experimental/kjobctl/test/integration/kjobctl/create_test.go b/cmd/experimental/kjobctl/test/integration/kjobctl/create_test.go
index 8e9a8dd58..d8cded161 100644
--- a/cmd/experimental/kjobctl/test/integration/kjobctl/create_test.go
+++ b/cmd/experimental/kjobctl/test/integration/kjobctl/create_test.go
@@ -18,6 +18,7 @@ package kjobctl
 
 import (
 	"fmt"
+	"time"
 
 	"github.com/onsi/ginkgo/v2"
 	"github.com/onsi/gomega"
@@ -26,6 +27,7 @@ import (
 	"k8s.io/apimachinery/pkg/api/resource"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/cli-runtime/pkg/genericiooptions"
+	testingclock "k8s.io/utils/clock/testing"
 	"k8s.io/utils/ptr"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
@@ -70,11 +72,17 @@ var _ = ginkgo.Describe("Kjobctl Create", ginkgo.Ordered, ginkgo.ContinueOnFailu
 		})
 
 		ginkgo.It("Should create job", func() {
+			testStartTime := time.Now()
+
 			ginkgo.By("Create a Job", func() {
 				streams, _, out, outErr := genericiooptions.NewTestIOStreams()
 				configFlags := CreateConfigFlagsWithRestConfig(cfg, streams)
 
-				kjobctlCmd := cmd.NewKjobctlCmd(cmd.KjobctlOptions{ConfigFlags: configFlags, IOStreams: streams})
+				kjobctlCmd := cmd.NewKjobctlCmd(cmd.KjobctlOptions{
+					ConfigFlags: configFlags,
+					IOStreams:   streams,
+					Clock:       testingclock.NewFakeClock(testStartTime),
+				})
 				kjobctlCmd.SetOut(out)
 				kjobctlCmd.SetErr(outErr)
 				kjobctlCmd.SetArgs([]string{
@@ -96,6 +104,11 @@ var _ = ginkgo.Describe("Kjobctl Create", ginkgo.Ordered, ginkgo.ContinueOnFailu
 			})
 
 			ginkgo.By("Check that Job created", func() {
+				timestamp := testStartTime.Format(time.RFC3339)
+				expectedTaskName := fmt.Sprintf("%s_%s", ns.Name, profile.Name)
+				expectedProfileName := fmt.Sprintf("%s_%s", ns.Name, profile.Name)
+				expectedTaskID := fmt.Sprintf("%s_%s_%s_%s", userID, timestamp, ns.Name, profile.Name)
+
 				jobList := &batchv1.JobList{}
 				gomega.Expect(k8sClient.List(ctx, jobList, client.InNamespace(ns.Name))).To(gomega.Succeed())
 				gomega.Expect(jobList.Items).To(gomega.HaveLen(1))
@@ -111,8 +124,22 @@ var _ = ginkgo.Describe("Kjobctl Create", ginkgo.Ordered, ginkgo.ContinueOnFailu
 					corev1.ResourceCPU:    resource.MustParse("100m"),
 					corev1.ResourceMemory: resource.MustParse("4Gi"),
 				}))
+				gomega.Expect(jobList.Items[0].Spec.Template.Spec.Containers[0].Env).To(gomega.Equal([]corev1.EnvVar{
+					{Name: constants.EnvVarNameUserID, Value: userID},
+					{Name: constants.EnvVarTaskName, Value: expectedTaskName},
+					{Name: constants.EnvVarTaskID, Value: expectedTaskID},
+					{Name: constants.EnvVarNameProfile, Value: expectedProfileName},
+					{Name: constants.EnvVarNameTimestamp, Value: timestamp},
+				}))
 				gomega.Expect(jobList.Items[0].Spec.Template.Spec.Containers[1].Command).To(gomega.BeNil())
 				gomega.Expect(jobList.Items[0].Spec.Template.Spec.Containers[1].Resources.Requests).To(gomega.BeNil())
+				gomega.Expect(jobList.Items[0].Spec.Template.Spec.Containers[1].Env).To(gomega.Equal([]corev1.EnvVar{
+					{Name: constants.EnvVarNameUserID, Value: userID},
+					{Name: constants.EnvVarTaskName, Value: expectedTaskName},
+					{Name: constants.EnvVarTaskID, Value: expectedTaskID},
+					{Name: constants.EnvVarNameProfile, Value: expectedProfileName},
+					{Name: constants.EnvVarNameTimestamp, Value: timestamp},
+				}))
 			})
 		})
 
diff --git a/cmd/experimental/kjobctl/test/integration/kjobctl/suite_test.go b/cmd/experimental/kjobctl/test/integration/kjobctl/suite_test.go
index 540a46b0b..b4a68a7b5 100644
--- a/cmd/experimental/kjobctl/test/integration/kjobctl/suite_test.go
+++ b/cmd/experimental/kjobctl/test/integration/kjobctl/suite_test.go
@@ -18,6 +18,7 @@ package kjobctl
 
 import (
 	"context"
+	"os"
 	"path/filepath"
 	"testing"
 
@@ -26,10 +27,12 @@ import (
 	"k8s.io/client-go/rest"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
+	"sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/constants"
 	"sigs.k8s.io/kueue/cmd/experimental/kjobctl/test/framework"
 )
 
 var (
+	userID    string
 	cfg       *rest.Config
 	k8sClient client.Client
 	ctx       context.Context
@@ -38,6 +41,7 @@ var (
 )
 
 func TestKjobctl(t *testing.T) {
+	userID = os.Getenv(constants.SystemEnvVarNameUser)
 	gomega.RegisterFailHandler(ginkgo.Fail)
 	ginkgo.RunSpecs(t, "Kjobctl Suite")
 }
diff --git a/cmd/kueuectl/app/create/create_clusterqueue_test.go b/cmd/kueuectl/app/create/create_clusterqueue_test.go
index 4e599e7b3..a0a78dc21 100644
--- a/cmd/kueuectl/app/create/create_clusterqueue_test.go
+++ b/cmd/kueuectl/app/create/create_clusterqueue_test.go
@@ -102,14 +102,15 @@ func TestParseResourceQuotas(t *testing.T) {
 		wantResourceGroups []v1beta1.ResourceGroup
 	}{
 		"should create one resource group with one flavor and nominalQuota set": {
-			quotaArgs: []string{"alpha:cpu=1;memory=1"},
+			quotaArgs: []string{"alpha-2.0:cpu=1;memory=1;example-1.org/memory=5Gi"},
 			wantResourceGroups: []v1beta1.ResourceGroup{
 				{
-					CoveredResources: []corev1.ResourceName{"cpu", "memory"},
+					CoveredResources: []corev1.ResourceName{"cpu", "memory", "example-1.org/memory"},
 					Flavors: []v1beta1.FlavorQuotas{
-						*utiltesting.MakeFlavorQuotas("alpha").
+						*utiltesting.MakeFlavorQuotas("alpha-2.0").
 							Resource("cpu", "1").
 							Resource("memory", "1").
+							Resource("example-1.org/memory", "5Gi").
 							Obj(),
 					},
 				},
diff --git a/pkg/cache/clusterqueue_test.go b/pkg/cache/clusterqueue_test.go
index 43fc91f58..f86168b15 100644
--- a/pkg/cache/clusterqueue_test.go
+++ b/pkg/cache/clusterqueue_test.go
@@ -98,206 +98,238 @@ func TestFitInCohort(t *testing.T) {
 	cases := map[string]struct {
 		request            resources.FlavorResourceQuantitiesFlat
 		wantFit            bool
-		cq                 *ClusterQueueSnapshot
+		usage              resources.FlavorResourceQuantitiesFlat
+		clusterQueue       []*kueue.ClusterQueue
 		enableLendingLimit bool
 	}{
 		"full cohort, empty request": {
 			request: resources.FlavorResourceQuantitiesFlat{},
 			wantFit: true,
-			cq: &ClusterQueueSnapshot{
-				Name: "CQ",
-				Cohort: &CohortSnapshot{
-					Name: "C",
-					RequestableResources: resources.FlavorResourceQuantitiesFlat{
-						{Flavor: "f1", Resource: corev1.ResourceCPU}:    5,
-						{Flavor: "f1", Resource: corev1.ResourceMemory}: 5,
-						{Flavor: "f2", Resource: corev1.ResourceCPU}:    5,
-						{Flavor: "f2", Resource: corev1.ResourceMemory}: 5,
-					}.Unflatten(),
-					Usage: resources.FlavorResourceQuantitiesFlat{
-						{Flavor: "f1", Resource: corev1.ResourceCPU}:    5,
-						{Flavor: "f1", Resource: corev1.ResourceMemory}: 5,
-						{Flavor: "f2", Resource: corev1.ResourceCPU}:    5,
-						{Flavor: "f2", Resource: corev1.ResourceMemory}: 5,
-					}.Unflatten(),
-				},
-				ResourceGroups: nil,
+			usage: resources.FlavorResourceQuantitiesFlat{
+				{Flavor: "f1", Resource: corev1.ResourceCPU}:    5_000,
+				{Flavor: "f1", Resource: corev1.ResourceMemory}: 5,
+				{Flavor: "f2", Resource: corev1.ResourceCPU}:    5_000,
+				{Flavor: "f2", Resource: corev1.ResourceMemory}: 5,
+			},
+			clusterQueue: []*kueue.ClusterQueue{
+				utiltesting.
+					MakeClusterQueue("CQ").
+					ResourceGroup(
+						*utiltesting.MakeFlavorQuotas("f1").
+							Resource(corev1.ResourceCPU, "5").
+							Resource(corev1.ResourceMemory, "5").
+							Obj(),
+						*utiltesting.MakeFlavorQuotas("f2").
+							Resource(corev1.ResourceCPU, "5").
+							Resource(corev1.ResourceMemory, "5").
+							Obj(),
+					).
+					Cohort("C").
+					Obj(),
 			},
 		},
 		"can fit": {
 			request: resources.FlavorResourceQuantitiesFlat{
-				{Flavor: "f2", Resource: corev1.ResourceCPU}:    1,
+				{Flavor: "f2", Resource: corev1.ResourceCPU}:    1_000,
 				{Flavor: "f2", Resource: corev1.ResourceMemory}: 1,
 			},
 			wantFit: true,
-			cq: &ClusterQueueSnapshot{
-				Name: "CQ",
-				Cohort: &CohortSnapshot{
-					Name: "C",
-					RequestableResources: resources.FlavorResourceQuantitiesFlat{
-						{Flavor: "f1", Resource: corev1.ResourceCPU}:    5,
-						{Flavor: "f1", Resource: corev1.ResourceMemory}: 5,
-						{Flavor: "f2", Resource: corev1.ResourceCPU}:    5,
-						{Flavor: "f2", Resource: corev1.ResourceMemory}: 5,
-					}.Unflatten(),
-					Usage: resources.FlavorResourceQuantitiesFlat{
-						{Flavor: "f1", Resource: corev1.ResourceCPU}:    5,
-						{Flavor: "f1", Resource: corev1.ResourceMemory}: 5,
-						{Flavor: "f2", Resource: corev1.ResourceCPU}:    4,
-						{Flavor: "f2", Resource: corev1.ResourceMemory}: 4,
-					}.Unflatten(),
-				},
-				ResourceGroups: nil,
+			usage: resources.FlavorResourceQuantitiesFlat{
+				{Flavor: "f1", Resource: corev1.ResourceCPU}:    5_000,
+				{Flavor: "f1", Resource: corev1.ResourceMemory}: 5,
+				{Flavor: "f2", Resource: corev1.ResourceCPU}:    4_000,
+				{Flavor: "f2", Resource: corev1.ResourceMemory}: 4,
+			},
+			clusterQueue: []*kueue.ClusterQueue{
+				utiltesting.
+					MakeClusterQueue("CQ").
+					ResourceGroup(
+						*utiltesting.MakeFlavorQuotas("f1").
+							Resource(corev1.ResourceCPU, "5").
+							Resource(corev1.ResourceMemory, "5").
+							Obj(),
+						*utiltesting.MakeFlavorQuotas("f2").
+							Resource(corev1.ResourceCPU, "5").
+							Resource(corev1.ResourceMemory, "5").
+							Obj(),
+					).
+					Cohort("C").
+					Obj(),
 			},
 		},
 		"full cohort, none fit": {
 			request: resources.FlavorResourceQuantitiesFlat{
-				{Flavor: "f1", Resource: corev1.ResourceCPU}:    1,
+				{Flavor: "f1", Resource: corev1.ResourceCPU}:    1_000,
 				{Flavor: "f1", Resource: corev1.ResourceMemory}: 1,
-				{Flavor: "f2", Resource: corev1.ResourceCPU}:    1,
+				{Flavor: "f2", Resource: corev1.ResourceCPU}:    1_000,
 				{Flavor: "f2", Resource: corev1.ResourceMemory}: 1,
 			},
 			wantFit: false,
-			cq: &ClusterQueueSnapshot{
-				Name: "CQ",
-				Cohort: &CohortSnapshot{
-					Name: "C",
-					RequestableResources: resources.FlavorResourceQuantitiesFlat{
-						{Flavor: "f1", Resource: corev1.ResourceCPU}:    5,
-						{Flavor: "f1", Resource: corev1.ResourceMemory}: 5,
-						{Flavor: "f2", Resource: corev1.ResourceCPU}:    5,
-						{Flavor: "f2", Resource: corev1.ResourceMemory}: 5,
-					}.Unflatten(),
-					Usage: resources.FlavorResourceQuantitiesFlat{
-						{Flavor: "f1", Resource: corev1.ResourceCPU}:    5,
-						{Flavor: "f1", Resource: corev1.ResourceMemory}: 5,
-						{Flavor: "f2", Resource: corev1.ResourceCPU}:    5,
-						{Flavor: "f2", Resource: corev1.ResourceMemory}: 5,
-					}.Unflatten(),
-				},
-				ResourceGroups: nil,
+			usage: resources.FlavorResourceQuantitiesFlat{
+				{Flavor: "f1", Resource: corev1.ResourceCPU}:    5_000,
+				{Flavor: "f1", Resource: corev1.ResourceMemory}: 5,
+				{Flavor: "f2", Resource: corev1.ResourceCPU}:    5_000,
+				{Flavor: "f2", Resource: corev1.ResourceMemory}: 5,
+			},
+			clusterQueue: []*kueue.ClusterQueue{
+				utiltesting.
+					MakeClusterQueue("CQ").
+					ResourceGroup(
+						*utiltesting.MakeFlavorQuotas("f1").
+							Resource(corev1.ResourceCPU, "5").
+							Resource(corev1.ResourceMemory, "5").
+							Obj(),
+						*utiltesting.MakeFlavorQuotas("f2").
+							Resource(corev1.ResourceCPU, "5").
+							Resource(corev1.ResourceMemory, "5").
+							Obj(),
+					).
+					Cohort("C").
+					Obj(),
 			},
 		},
 		"one cannot fit": {
 			request: resources.FlavorResourceQuantitiesFlat{
-				{Flavor: "f1", Resource: corev1.ResourceCPU}:    1,
+				{Flavor: "f1", Resource: corev1.ResourceCPU}:    1_000,
 				{Flavor: "f1", Resource: corev1.ResourceMemory}: 1,
-				{Flavor: "f2", Resource: corev1.ResourceCPU}:    2,
+				{Flavor: "f2", Resource: corev1.ResourceCPU}:    2_000,
 				{Flavor: "f2", Resource: corev1.ResourceMemory}: 1,
 			},
 			wantFit: false,
-			cq: &ClusterQueueSnapshot{
-				Name: "CQ",
-				Cohort: &CohortSnapshot{
-					Name: "C",
-					RequestableResources: resources.FlavorResourceQuantitiesFlat{
-						{Flavor: "f1", Resource: corev1.ResourceCPU}:    5,
-						{Flavor: "f1", Resource: corev1.ResourceMemory}: 5,
-						{Flavor: "f2", Resource: corev1.ResourceCPU}:    5,
-						{Flavor: "f2", Resource: corev1.ResourceMemory}: 5,
-					}.Unflatten(),
-					Usage: resources.FlavorResourceQuantitiesFlat{
-						{Flavor: "f1", Resource: corev1.ResourceCPU}:    4,
-						{Flavor: "f1", Resource: corev1.ResourceMemory}: 4,
-						{Flavor: "f2", Resource: corev1.ResourceCPU}:    4,
-						{Flavor: "f2", Resource: corev1.ResourceMemory}: 4,
-					}.Unflatten(),
-				},
-				ResourceGroups: nil,
+			usage: resources.FlavorResourceQuantitiesFlat{
+				{Flavor: "f1", Resource: corev1.ResourceCPU}:    4_000,
+				{Flavor: "f1", Resource: corev1.ResourceMemory}: 4,
+				{Flavor: "f2", Resource: corev1.ResourceCPU}:    4_000,
+				{Flavor: "f2", Resource: corev1.ResourceMemory}: 4,
+			},
+			clusterQueue: []*kueue.ClusterQueue{
+				utiltesting.
+					MakeClusterQueue("CQ").
+					ResourceGroup(
+						*utiltesting.MakeFlavorQuotas("f1").
+							Resource(corev1.ResourceCPU, "5").
+							Resource(corev1.ResourceMemory, "5").
+							Obj(),
+						*utiltesting.MakeFlavorQuotas("f2").
+							Resource(corev1.ResourceCPU, "5").
+							Resource(corev1.ResourceMemory, "5").
+							Obj(),
+					).
+					Cohort("C").
+					Obj(),
 			},
 		},
 		"missing flavor": {
 			request: resources.FlavorResourceQuantitiesFlat{
-				{Flavor: "f2", Resource: corev1.ResourceCPU}:    1,
-				{Flavor: "f2", Resource: corev1.ResourceMemory}: 1,
+				{Flavor: "non-existent-flavor", Resource: corev1.ResourceCPU}:    1_000,
+				{Flavor: "non-existent-flavor", Resource: corev1.ResourceMemory}: 1,
 			},
 			wantFit: false,
-			cq: &ClusterQueueSnapshot{
-				Name: "CQ",
-				Cohort: &CohortSnapshot{
-					Name: "C",
-					RequestableResources: resources.FlavorResourceQuantitiesFlat{
-						{Flavor: "f1", Resource: corev1.ResourceCPU}:    5,
-						{Flavor: "f1", Resource: corev1.ResourceMemory}: 5,
-					}.Unflatten(),
-					Usage: resources.FlavorResourceQuantitiesFlat{
-						{Flavor: "f1", Resource: corev1.ResourceCPU}:    5,
-						{Flavor: "f1", Resource: corev1.ResourceMemory}: 5,
-					}.Unflatten(),
-				},
-				ResourceGroups: nil,
+			usage: resources.FlavorResourceQuantitiesFlat{
+				{Flavor: "f1", Resource: corev1.ResourceCPU}:    5_000,
+				{Flavor: "f1", Resource: corev1.ResourceMemory}: 5,
+			},
+			clusterQueue: []*kueue.ClusterQueue{
+				utiltesting.
+					MakeClusterQueue("CQ").
+					ResourceGroup(
+						*utiltesting.MakeFlavorQuotas("f1").
+							Resource(corev1.ResourceCPU, "5").
+							Resource(corev1.ResourceMemory, "5").
+							Obj(),
+					).
+					Cohort("C").
+					Obj(),
 			},
 		},
 		"missing resource": {
 			request: resources.FlavorResourceQuantitiesFlat{
-				{Flavor: "f1", Resource: corev1.ResourceCPU}:    1,
+				{Flavor: "f1", Resource: corev1.ResourceCPU}:    1_000,
 				{Flavor: "f1", Resource: corev1.ResourceMemory}: 1,
 			},
 			wantFit: false,
-			cq: &ClusterQueueSnapshot{
-				Name: "CQ",
-				Cohort: &CohortSnapshot{
-					Name: "C",
-					RequestableResources: resources.FlavorResourceQuantitiesFlat{
-						{Flavor: "f1", Resource: corev1.ResourceCPU}: 5,
-					}.Unflatten(),
-					Usage: resources.FlavorResourceQuantitiesFlat{
-						{Flavor: "f1", Resource: corev1.ResourceCPU}: 3,
-					}.Unflatten(),
-				},
-				ResourceGroups: nil,
+			usage: resources.FlavorResourceQuantitiesFlat{
+				{Flavor: "f1", Resource: corev1.ResourceCPU}: 3_000,
+			},
+			clusterQueue: []*kueue.ClusterQueue{
+				utiltesting.
+					MakeClusterQueue("CQ").
+					ResourceGroup(
+						*utiltesting.MakeFlavorQuotas("f1").
+							Resource(corev1.ResourceCPU, "5").
+							Obj(),
+					).
+					Cohort("C").
+					Obj(),
 			},
 		},
 		"lendingLimit enabled can't fit": {
 			request: resources.FlavorResourceQuantitiesFlat{
-				{Flavor: "f1", Resource: corev1.ResourceCPU}: 3,
+				{Flavor: "f1", Resource: corev1.ResourceCPU}: 3_000,
 			},
 			wantFit: false,
-			cq: &ClusterQueueSnapshot{
-				Name: "CQ-A",
-				Cohort: &CohortSnapshot{
-					Name: "C",
-					RequestableResources: resources.FlavorResourceQuantitiesFlat{
-						{Flavor: "f1", Resource:
-						// CQ-A has 2 nominal cpu, CQ-B has 3 nominal cpu and 2 lendingLimit,
-						// so when lendingLimit enabled, the cohort's RequestableResources is 4 cpu.
-						corev1.ResourceCPU}: 4,
-					}.Unflatten(),
-					Usage: resources.FlavorResourceQuantitiesFlat{
-						{Flavor: "f1", Resource: corev1.ResourceCPU}: 2,
-					}.Unflatten(),
-				},
-				GuaranteedQuota: resources.FlavorResourceQuantitiesFlat{
-					{Flavor: "f1", Resource: corev1.ResourceCPU}: 0,
-				}.Unflatten(),
+			usage: resources.FlavorResourceQuantitiesFlat{
+				{Flavor: "f1", Resource: corev1.ResourceCPU}: 2_000,
+			},
+			clusterQueue: []*kueue.ClusterQueue{
+				utiltesting.
+					MakeClusterQueue("CQ").
+					ResourceGroup(
+						utiltesting.MakeFlavorQuotas("f1").
+							ResourceQuotaWrapper(corev1.ResourceCPU).
+							NominalQuota("2").
+							Append().
+							FlavorQuotas,
+					).
+					Cohort("C").
+					Obj(),
+				utiltesting.
+					MakeClusterQueue("CQ-B").
+					ResourceGroup(
+						utiltesting.MakeFlavorQuotas("f1").
+							ResourceQuotaWrapper(corev1.ResourceCPU).
+							NominalQuota("3").
+							LendingLimit("2").
+							Append().
+							FlavorQuotas,
+					).
+					Cohort("C").
+					Obj(),
 			},
 			enableLendingLimit: true,
 		},
 		"lendingLimit enabled can fit": {
 			request: resources.FlavorResourceQuantitiesFlat{
-				{Flavor: "f1", Resource: corev1.ResourceCPU}: 3,
+				{Flavor: "f1", Resource: corev1.ResourceCPU}: 3_000,
 			},
 			wantFit: true,
-			cq: &ClusterQueueSnapshot{
-				Name: "CQ-A",
-				Cohort: &CohortSnapshot{
-					Name: "C",
-					RequestableResources: resources.FlavorResourceQuantitiesFlat{
-						{Flavor: "f1", Resource:
-						// CQ-A has 2 nominal cpu, CQ-B has 3 nominal cpu and 2 lendingLimit,
-						// so when lendingLimit enabled, the cohort's RequestableResources is 4 cpu.
-						corev1.ResourceCPU}: 4,
-					}.Unflatten(),
-					Usage: resources.FlavorResourceQuantitiesFlat{
-						{Flavor: "f1", Resource:
-						// CQ-B has admitted a workload with 2 cpus, but with 1 GuaranteedQuota,
-						// so when lendingLimit enabled, Cohort.Usage should be 2 - 1 = 1.
-						corev1.ResourceCPU}: 1,
-					}.Unflatten(),
-				},
-				GuaranteedQuota: resources.FlavorResourceQuantitiesFlat{
-					{Flavor: "f1", Resource: corev1.ResourceCPU}: 2,
-				}.Unflatten(),
+			usage: resources.FlavorResourceQuantitiesFlat{
+				{Flavor: "f1", Resource: corev1.ResourceCPU}: 1_000,
+			},
+			clusterQueue: []*kueue.ClusterQueue{
+				utiltesting.
+					MakeClusterQueue("CQ").
+					ResourceGroup(
+						utiltesting.MakeFlavorQuotas("f1").
+							ResourceQuotaWrapper(corev1.ResourceCPU).
+							NominalQuota("2").
+							Append().
+							FlavorQuotas,
+					).
+					Cohort("C").
+					Obj(),
+				utiltesting.
+					MakeClusterQueue("CQ-B").
+					ResourceGroup(
+						utiltesting.MakeFlavorQuotas("f1").
+							ResourceQuotaWrapper(corev1.ResourceCPU).
+							NominalQuota("3").
+							LendingLimit("2").
+							Append().
+							FlavorQuotas,
+					).
+					Cohort("C").
+					Obj(),
 			},
 			enableLendingLimit: true,
 		},
@@ -306,7 +338,20 @@ func TestFitInCohort(t *testing.T) {
 	for name, tc := range cases {
 		t.Run(name, func(t *testing.T) {
 			defer features.SetFeatureGateDuringTest(t, features.LendingLimit, tc.enableLendingLimit)()
-			got := tc.cq.FitInCohort(tc.request)
+			cache := New(utiltesting.NewFakeClient())
+
+			cache.AddOrUpdateResourceFlavor(utiltesting.MakeResourceFlavor("f1").Obj())
+			cache.AddOrUpdateResourceFlavor(utiltesting.MakeResourceFlavor("f2").Obj())
+
+			for _, cq := range tc.clusterQueue {
+				_ = cache.AddClusterQueue(context.Background(), cq)
+			}
+
+			snapshot := cache.Snapshot()
+			cq := snapshot.ClusterQueues["CQ"]
+			cq.AddUsage(tc.usage)
+
+			got := cq.FitInCohort(tc.request)
 			if got != tc.wantFit {
 				t.Errorf("Unexpected result, %v", got)
 			}
diff --git a/pkg/controller/jobframework/setup_test.go b/pkg/controller/jobframework/setup_test.go
index 03f59b0db..082bf7be6 100644
--- a/pkg/controller/jobframework/setup_test.go
+++ b/pkg/controller/jobframework/setup_test.go
@@ -119,10 +119,9 @@ func TestSetupControllers(t *testing.T) {
 					return k8sClient, nil
 				},
 				MapperProvider: func(*rest.Config, *http.Client) (apimeta.RESTMapper, error) {
-					gvs := make([]schema.GroupVersion, len(tc.mapperGVKs))
-					for _, gvk := range tc.mapperGVKs {
-						gvs = append(gvs, gvk.GroupVersion())
-					}
+					gvs := slices.Map(tc.mapperGVKs, func(gvk *schema.GroupVersionKind) schema.GroupVersion {
+						return gvk.GroupVersion()
+					})
 					mapper := apimeta.NewDefaultRESTMapper(gvs)
 					for _, gvk := range tc.mapperGVKs {
 						mapper.Add(gvk, apimeta.RESTScopeNamespace)
diff --git a/test/integration/controller/jobs/jobset/jobset_controller_test.go b/test/integration/controller/jobs/jobset/jobset_controller_test.go
index 574e3a03b..2207edb33 100644
--- a/test/integration/controller/jobs/jobset/jobset_controller_test.go
+++ b/test/integration/controller/jobs/jobset/jobset_controller_test.go
@@ -276,6 +276,87 @@ var _ = ginkgo.Describe("JobSet controller", ginkgo.Ordered, ginkgo.ContinueOnFa
 			util.ExpectWorkloadToFinish(ctx, k8sClient, wlLookupKey)
 		})
 
+		ginkgo.It("Should finish the preemption when the jobset becomes inactive", func() {
+			jobSet := testingjobset.MakeJobSet(jobSetName, ns.Name).ReplicatedJobs(
+				testingjobset.ReplicatedJobRequirements{
+					Name:        "replicated-job-1",
+					Replicas:    1,
+					Parallelism: 1,
+					Completions: 1,
+				},
+			).Queue(localQueue.Name).
+				Suspend(false).
+				Obj()
+			createdWorkload := &kueue.Workload{}
+			var wlLookupKey types.NamespacedName
+
+			ginkgo.By("create the jobset and admit the workload", func() {
+				gomega.Expect(k8sClient.Create(ctx, jobSet)).To(gomega.Succeed())
+				wlLookupKey = types.NamespacedName{Name: workloadjobset.GetWorkloadNameForJobSet(jobSet.Name, jobSet.UID), Namespace: ns.Name}
+				gomega.Eventually(func(g gomega.Gomega) { g.Expect(k8sClient.Get(ctx, wlLookupKey, createdWorkload)).To(gomega.Succeed()) }, util.Timeout, util.Interval).Should(gomega.Succeed())
+				admission := testing.MakeAdmission(localQueue.Name).PodSets(
+					kueue.PodSetAssignment{
+						Name: createdWorkload.Spec.PodSets[0].Name,
+						Flavors: map[corev1.ResourceName]kueue.ResourceFlavorReference{
+							corev1.ResourceCPU: kueue.ResourceFlavorReference(onDemandFlavor.Name),
+						},
+					},
+				).Obj()
+				gomega.Expect(util.SetQuotaReservation(ctx, k8sClient, createdWorkload, admission)).To(gomega.Succeed())
+				util.SyncAdmittedConditionForWorkloads(ctx, k8sClient, createdWorkload)
+			})
+
+			ginkgo.By("wait for the jobset to be unsuspended", func() {
+				gomega.Eventually(func(g gomega.Gomega) {
+					g.Expect(k8sClient.Get(ctx, types.NamespacedName{Name: jobSetName, Namespace: ns.Name}, jobSet)).Should(gomega.Succeed())
+					g.Expect(ptr.Deref(jobSet.Spec.Suspend, false)).Should(gomega.BeTrue())
+				}, util.Timeout, util.Interval).Should(gomega.Succeed())
+			})
+
+			ginkgo.By("mark the jobset as active", func() {
+				gomega.Eventually(func(g gomega.Gomega) {
+					g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(jobSet), jobSet)).To(gomega.Succeed())
+					jobSet.Status.ReplicatedJobsStatus = make([]jobsetapi.ReplicatedJobStatus, 1)
+					jobSet.Status.ReplicatedJobsStatus[0].Active = 1
+					jobSet.Status.ReplicatedJobsStatus[0].Name = jobSet.Spec.ReplicatedJobs[0].Name
+					g.Expect(k8sClient.Status().Update(ctx, jobSet)).To(gomega.Succeed())
+				}, util.Timeout, util.Interval).Should(gomega.Succeed())
+			})
+
+			ginkgo.By("preempt the workload", func() {
+				gomega.Eventually(func(g gomega.Gomega) {
+					g.Expect(k8sClient.Get(ctx, wlLookupKey, createdWorkload)).To(gomega.Succeed())
+					g.Expect(workload.UpdateStatus(ctx, k8sClient, createdWorkload, kueue.WorkloadEvicted, metav1.ConditionTrue, kueue.WorkloadEvictedByPreemption, "By test", "evict")).To(gomega.Succeed())
+				}, util.Timeout, util.Interval).Should(gomega.Succeed())
+			})
+
+			ginkgo.By("wait for the jobset to be suspended", func() {
+				gomega.Eventually(func(g gomega.Gomega) {
+					g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(jobSet), jobSet)).To(gomega.Succeed())
+					g.Expect(*jobSet.Spec.Suspend).To(gomega.BeTrue())
+				}, util.Timeout, util.Interval).Should(gomega.Succeed())
+			})
+
+			ginkgo.By("the workload should stay admitted", func() {
+				gomega.Consistently(func(g gomega.Gomega) {
+					g.Expect(k8sClient.Get(ctx, wlLookupKey, createdWorkload)).To(gomega.Succeed())
+					g.Expect(apimeta.IsStatusConditionTrue(createdWorkload.Status.Conditions, kueue.WorkloadQuotaReserved)).To(gomega.BeTrue())
+				}, util.ConsistentDuration, util.Interval).Should(gomega.Succeed())
+			})
+
+			ginkgo.By("mark the jobset as inactive", func() {
+				gomega.Eventually(func(g gomega.Gomega) {
+					g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(jobSet), jobSet)).To(gomega.Succeed())
+					jobSet.Status.ReplicatedJobsStatus[0].Active = 0
+					g.Expect(k8sClient.Status().Update(ctx, jobSet)).To(gomega.Succeed())
+				}, util.Timeout, util.Interval).Should(gomega.Succeed())
+			})
+
+			ginkgo.By("the workload should get unadmitted", func() {
+				util.ExpectWorkloadsToBePending(ctx, k8sClient, createdWorkload)
+			})
+		})
+
 		ginkgo.It("Should allow to create jobset with one replicated job replica count 0", func() {
 			mixJobSet := testingjobset.MakeJobSet("mix-jobset", ns.Name).ReplicatedJobs(
 				testingjobset.ReplicatedJobRequirements{
diff --git a/test/performance/scheduler/default_rangespec.yaml b/test/performance/scheduler/default_rangespec.yaml
index 35ee32327..af3dfb2c9 100644
--- a/test/performance/scheduler/default_rangespec.yaml
+++ b/test/performance/scheduler/default_rangespec.yaml
@@ -19,8 +19,8 @@ clusterQueueClassesMinUsage:
   cq: 55 #%
 
 wlClassesMaxAvgTimeToAdmissionMs:
-  # Average value 6666 (+/- 14%), setting at +35% + 1s accounting for observed failures
-  large: 10_000
+  # Average value 6666 (+/- 14%), setting at +35% + 2s accounting for observed failures
+  large: 11_000
 
   # Average value 76768 (+/- 2%), setting at +20%
   medium: 90_000