From a10c96be5d4617d3008b102410027d341805fc7e Mon Sep 17 00:00:00 2001 From: Mykhailo Bobrovskyi Date: Wed, 4 Sep 2024 12:46:34 +0300 Subject: [PATCH 001/155] Resolve InvalidDefaultArgInFrom build check warnings. (#2974) --- Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8c0b67b390..0da26efccb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,6 @@ -ARG BUILDER_IMAGE -ARG BASE_IMAGE +ARG BUILDER_IMAGE=golang:1.22.6 +ARG BASE_IMAGE=gcr.io/distroless/static:nonroot + # Build the manager binary FROM --platform=${BUILDPLATFORM} ${BUILDER_IMAGE} AS builder From b070ab6ce8b4fa52c000a8b81bf8e8aea1b69ea8 Mon Sep 17 00:00:00 2001 From: Mykhailo Bobrovskyi Date: Wed, 4 Sep 2024 15:53:23 +0300 Subject: [PATCH 002/155] [kjobctl] Fix create job examples. (#2979) --- .../docs/commands/kjobctl_create/_index.md | 30 +++++++++---------- .../kjobctl_create_interactive.md | 2 +- .../kjobctl_create/kjobctl_create_job.md | 10 +++---- .../kjobctl_create_raycluster.md | 8 ++--- .../kjobctl_create/kjobctl_create_rayjob.md | 10 +++---- .../hack/tools/kjobctl-docs/templates/main.md | 2 +- .../kjobctl/pkg/cmd/create/create.go | 26 ++++++++-------- 7 files changed, 44 insertions(+), 44 deletions(-) diff --git a/cmd/experimental/kjobctl/docs/commands/kjobctl_create/_index.md b/cmd/experimental/kjobctl/docs/commands/kjobctl_create/_index.md index 2db74858a3..dc77a07e3b 100644 --- a/cmd/experimental/kjobctl/docs/commands/kjobctl_create/_index.md +++ b/cmd/experimental/kjobctl/docs/commands/kjobctl_create/_index.md @@ -16,35 +16,35 @@ Create a task ``` # Create job - kjobctl create job \ - --profile my-application-profile \ - --cmd "sleep 5" \ + kjobctl create job \ + --profile my-application-profile \ + --cmd "sleep 5" \ --parallelism 4 \ - --completions 4 \ - --request cpu=500m,ram=4Gi \ + --completions 4 \ + --request cpu=500m,memory=4Gi \ --localqueue my-local-queue-name # Create interactive - kjobctl create interactive \ + kjobctl create interactive \ --profile my-application-profile \ --pod-running-timeout 30s \ --rm # Create rayjob - kjobctl create rayjob \ - --profile my-application-profile \ - --cmd "python /home/ray/samples/sample_code.py" \ + kjobctl create rayjob \ + --profile my-application-profile \ + --cmd "python /home/ray/samples/sample_code.py" \ --replicas small-group=1 \ - --min-replicas small-group=1 \ - --max-replicas small-group=5 \ + --min-replicas small-group=1 \ + --max-replicas small-group=5 \ --localqueue my-local-queue-name # Create raycluster - kjobctl create raycluster \ - --profile my-application-profile \ + kjobctl create raycluster \ + --profile my-application-profile \ --replicas small-group=1 \ - --min-replicas small-group=1 \ - --max-replicas small-group=5 \ + --min-replicas small-group=1 \ + --max-replicas small-group=5 \ --localqueue my-local-queue-name # Create slurm 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 index 96105add01..2dd1a9e871 100644 --- a/cmd/experimental/kjobctl/docs/commands/kjobctl_create/kjobctl_create_interactive.md +++ b/cmd/experimental/kjobctl/docs/commands/kjobctl_create/kjobctl_create_interactive.md @@ -20,7 +20,7 @@ kjobctl create interactive --profile APPLICATION_PROFILE_NAME [--localqueue LOCA ``` # Create interactive - kjobctl create interactive \ + kjobctl create interactive \ --profile my-application-profile \ --pod-running-timeout 30s \ --rm 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 index 70692f911f..954f981237 100644 --- a/cmd/experimental/kjobctl/docs/commands/kjobctl_create/kjobctl_create_job.md +++ b/cmd/experimental/kjobctl/docs/commands/kjobctl_create/kjobctl_create_job.md @@ -20,12 +20,12 @@ kjobctl create job --profile APPLICATION_PROFILE_NAME [--localqueue LOCAL_QUEUE_ ``` # Create job - kjobctl create job \ - --profile my-application-profile \ - --cmd "sleep 5" \ + kjobctl create job \ + --profile my-application-profile \ + --cmd "sleep 5" \ --parallelism 4 \ - --completions 4 \ - --request cpu=500m,ram=4Gi \ + --completions 4 \ + --request cpu=500m,memory=4Gi \ --localqueue my-local-queue-name ``` diff --git a/cmd/experimental/kjobctl/docs/commands/kjobctl_create/kjobctl_create_raycluster.md b/cmd/experimental/kjobctl/docs/commands/kjobctl_create/kjobctl_create_raycluster.md index ce85ec9839..f6dc7b186e 100644 --- a/cmd/experimental/kjobctl/docs/commands/kjobctl_create/kjobctl_create_raycluster.md +++ b/cmd/experimental/kjobctl/docs/commands/kjobctl_create/kjobctl_create_raycluster.md @@ -23,11 +23,11 @@ kjobctl create raycluster --profile APPLICATION_PROFILE_NAME [--localqueue LOCAL ``` # Create raycluster - kjobctl create raycluster \ - --profile my-application-profile \ + kjobctl create raycluster \ + --profile my-application-profile \ --replicas small-group=1 \ - --min-replicas small-group=1 \ - --max-replicas small-group=5 \ + --min-replicas small-group=1 \ + --max-replicas small-group=5 \ --localqueue my-local-queue-name ``` diff --git a/cmd/experimental/kjobctl/docs/commands/kjobctl_create/kjobctl_create_rayjob.md b/cmd/experimental/kjobctl/docs/commands/kjobctl_create/kjobctl_create_rayjob.md index 784e863799..0e9586d904 100644 --- a/cmd/experimental/kjobctl/docs/commands/kjobctl_create/kjobctl_create_rayjob.md +++ b/cmd/experimental/kjobctl/docs/commands/kjobctl_create/kjobctl_create_rayjob.md @@ -23,12 +23,12 @@ kjobctl create rayjob --profile APPLICATION_PROFILE_NAME [--localqueue LOCAL_QUE ``` # Create rayjob - kjobctl create rayjob \ - --profile my-application-profile \ - --cmd "python /home/ray/samples/sample_code.py" \ + kjobctl create rayjob \ + --profile my-application-profile \ + --cmd "python /home/ray/samples/sample_code.py" \ --replicas small-group=1 \ - --min-replicas small-group=1 \ - --max-replicas small-group=5 \ + --min-replicas small-group=1 \ + --max-replicas small-group=5 \ --localqueue my-local-queue-name ``` diff --git a/cmd/experimental/kjobctl/hack/tools/kjobctl-docs/templates/main.md b/cmd/experimental/kjobctl/hack/tools/kjobctl-docs/templates/main.md index c32425d91c..9b1e954d8a 100644 --- a/cmd/experimental/kjobctl/hack/tools/kjobctl-docs/templates/main.md +++ b/cmd/experimental/kjobctl/hack/tools/kjobctl-docs/templates/main.md @@ -22,7 +22,7 @@ The file is auto-generated from the Go source code of the component using the ## Examples ``` -{{.Example}} +{{html .Example}} ``` {{- end}} {{- if .Options}} diff --git a/cmd/experimental/kjobctl/pkg/cmd/create/create.go b/cmd/experimental/kjobctl/pkg/cmd/create/create.go index a9565902d1..88208a341d 100644 --- a/cmd/experimental/kjobctl/pkg/cmd/create/create.go +++ b/cmd/experimental/kjobctl/pkg/cmd/create/create.go @@ -52,15 +52,15 @@ import ( const ( createJobExample = ` # Create job - kjobctl create job \ - --profile my-application-profile \ + kjobctl create job \ + --profile my-application-profile \ --cmd "sleep 5" \ --parallelism 4 \ - --completions 4 \ - --request cpu=500m,ram=4Gi \ + --completions 4 \ + --request cpu=500m,memory=4Gi \ --localqueue my-local-queue-name` createInteractiveExample = ` # Create interactive - kjobctl create interactive \ + kjobctl create interactive \ --profile my-application-profile \ --pod-running-timeout 30s \ --rm` @@ -69,23 +69,23 @@ const ( KubeRay operator is required for RayJob. How to install KubeRay operator you can find here https://ray-project.github.io/kuberay/deploy/installation/.` createRayJobExample = ` # Create rayjob - kjobctl create rayjob \ - --profile my-application-profile \ + kjobctl create rayjob \ + --profile my-application-profile \ --cmd "python /home/ray/samples/sample_code.py" \ --replicas small-group=1 \ - --min-replicas small-group=1 \ - --max-replicas small-group=5 \ + --min-replicas small-group=1 \ + --max-replicas small-group=5 \ --localqueue my-local-queue-name` createRayClusterLong = `Create a raycluster. KubeRay operator is required for RayCluster. How to install KubeRay operator you can find here https://ray-project.github.io/kuberay/deploy/installation/.` createRayClusterExample = ` # Create raycluster - kjobctl create raycluster \ - --profile my-application-profile \ + kjobctl create raycluster \ + --profile my-application-profile \ --replicas small-group=1 \ - --min-replicas small-group=1 \ - --max-replicas small-group=5 \ + --min-replicas small-group=1 \ + --max-replicas small-group=5 \ --localqueue my-local-queue-name` createSlurmExample = ` # Create slurm kjobctl create slurm --profile my-application-profile -- \ From 6701133475d218a178f0dd6a971ee00d2c6f3311 Mon Sep 17 00:00:00 2001 From: Mykhailo Bobrovskyi Date: Wed, 4 Sep 2024 18:54:53 +0300 Subject: [PATCH 003/155] [kueuectl] Add EXEC TIME column on list workload command. (#2977) * [kueuectl] Add DURATION column on list workload command. * Add test cases with Admitted=false and Finished=false. * Rename DURATION column to EXEC TIME. --- cmd/kueuectl/app/list/list_test.go | 12 +- .../app/list/list_workload_printer.go | 16 ++ cmd/kueuectl/app/list/list_workload_test.go | 185 ++++++++++++------ test/integration/kueuectl/list_test.go | 12 +- 4 files changed, 152 insertions(+), 73 deletions(-) diff --git a/cmd/kueuectl/app/list/list_test.go b/cmd/kueuectl/app/list/list_test.go index d3be6a017a..b4b6dcdefd 100644 --- a/cmd/kueuectl/app/list/list_test.go +++ b/cmd/kueuectl/app/list/list_test.go @@ -125,9 +125,9 @@ cq2 cohort2 0 0 false 120m Creation(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). Obj(), }, - wantOut: `NAMESPACE NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE AGE -ns1 wl1 j1 lq1 cq1 PENDING 60m -ns2 wl2 j2 lq2 cq2 PENDING 120m + wantOut: `NAMESPACE NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE EXEC TIME AGE +ns1 wl1 j1 lq1 cq1 PENDING 60m +ns2 wl2 j2 lq2 cq2 PENDING 120m `, }, "should print workload list with all namespaces (short command and flag)": { @@ -148,9 +148,9 @@ ns2 wl2 j2 lq2 cq2 PENDING Creation(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). Obj(), }, - wantOut: `NAMESPACE NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE AGE -ns1 wl1 j1 lq1 cq1 PENDING 60m -ns2 wl2 j2 lq2 cq2 PENDING 120m + wantOut: `NAMESPACE NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE EXEC TIME AGE +ns1 wl1 j1 lq1 cq1 PENDING 60m +ns2 wl2 j2 lq2 cq2 PENDING 120m `, }, } diff --git a/cmd/kueuectl/app/list/list_workload_printer.go b/cmd/kueuectl/app/list/list_workload_printer.go index fa3956790c..f550b82f31 100644 --- a/cmd/kueuectl/app/list/list_workload_printer.go +++ b/cmd/kueuectl/app/list/list_workload_printer.go @@ -22,6 +22,7 @@ import ( "io" "strings" + apimeta "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/duration" @@ -75,6 +76,7 @@ func (p *listWorkloadPrinter) PrintObj(obj runtime.Object, out io.Writer) error {Name: "ClusterQueue", Type: "string"}, {Name: "Status", Type: "string"}, {Name: "Position in Queue", Type: "string"}, + {Name: "Exec Time", Type: "string"}, {Name: "Age", Type: "string"}, }, Rows: p.printWorkloadList(list), @@ -138,6 +140,19 @@ func (p *listWorkloadPrinter) printWorkload(wl *v1beta1.Workload) metav1.TableRo positionInQueue = fmt.Sprintf("%d", pendingWorkload.PositionInLocalQueue) } + var execTime string + if admittedCond := apimeta.FindStatusCondition(wl.Status.Conditions, v1beta1.WorkloadAdmitted); admittedCond != nil && + admittedCond.Status == metav1.ConditionTrue { + finishedTime := p.clock.Now() + + if finishedCond := apimeta.FindStatusCondition(wl.Status.Conditions, v1beta1.WorkloadFinished); finishedCond != nil && + finishedCond.Status == metav1.ConditionTrue { + finishedTime = finishedCond.LastTransitionTime.Time + } + + execTime = duration.HumanDuration(finishedTime.Sub(admittedCond.LastTransitionTime.Time)) + } + row.Cells = []any{ wl.Name, strings.Join(p.crdTypes(wl), ", "), @@ -146,6 +161,7 @@ func (p *listWorkloadPrinter) printWorkload(wl *v1beta1.Workload) metav1.TableRo clusterQueueName, strings.ToUpper(workload.Status(wl)), positionInQueue, + execTime, duration.HumanDuration(p.clock.Since(wl.CreationTimestamp.Time)), } diff --git a/cmd/kueuectl/app/list/list_workload_test.go b/cmd/kueuectl/app/list/list_workload_test.go index eb70833f9c..07922f747e 100644 --- a/cmd/kueuectl/app/list/list_workload_test.go +++ b/cmd/kueuectl/app/list/list_workload_test.go @@ -84,8 +84,8 @@ func TestWorkloadCmd(t *testing.T) { Creation(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). Obj(), }, - wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE AGE -wl1 j1 lq1 cq1 PENDING 60m + wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE EXEC TIME AGE +wl1 j1 lq1 cq1 PENDING 60m `, }, "should print workload list with localqueue filter": { @@ -106,8 +106,8 @@ wl1 j1 lq1 cq1 PENDING Creation(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). Obj(), }, - wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE AGE -wl1 j1 lq1 cq1 PENDING 60m + wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE EXEC TIME AGE +wl1 j1 lq1 cq1 PENDING 60m `, }, "should print workload list with localqueue filter (short flag)": { @@ -128,8 +128,8 @@ wl1 j1 lq1 cq1 PENDING Creation(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). Obj(), }, - wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE AGE -wl1 j1 lq1 cq1 PENDING 60m + wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE EXEC TIME AGE +wl1 j1 lq1 cq1 PENDING 60m `, }, "should print workload list with clusterqueue filter": { @@ -150,8 +150,8 @@ wl1 j1 lq1 cq1 PENDING Creation(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). Obj(), }, - wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE AGE -wl1 j1 lq1 cq1 PENDING 60m + wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE EXEC TIME AGE +wl1 j1 lq1 cq1 PENDING 60m `, }, "should print workload list with clusterqueue filter (short flag)": { @@ -172,8 +172,8 @@ wl1 j1 lq1 cq1 PENDING Creation(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). Obj(), }, - wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE AGE -wl1 j1 lq1 cq1 PENDING 60m + wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE EXEC TIME AGE +wl1 j1 lq1 cq1 PENDING 60m `, }, "should print workload list with all status flag": { @@ -194,29 +194,71 @@ wl1 j1 lq1 cq1 PENDING Creation(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). Conditions([]metav1.Condition{ { - Type: kueue.WorkloadAdmitted, - Status: metav1.ConditionTrue, + Type: kueue.WorkloadAdmitted, + Status: metav1.ConditionTrue, + LastTransitionTime: metav1.NewTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)), }, }...). Obj(), utiltesting.MakeWorkload("wl3", metav1.NamespaceDefault). - OwnerReference(batchv1.SchemeGroupVersion.WithKind("Job"), "j3", "test-uid"). + OwnerReference(rayv1.GroupVersion.WithKind("RayJob"), "j3", "test-uid"). Queue("lq3"). Active(true). Admission(utiltesting.MakeAdmission("cq3").Obj()). + Creation(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + Conditions([]metav1.Condition{ + { + Type: kueue.WorkloadAdmitted, + Status: metav1.ConditionFalse, + LastTransitionTime: metav1.NewTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)), + }, + }...). + Obj(), + utiltesting.MakeWorkload("wl4", metav1.NamespaceDefault). + OwnerReference(batchv1.SchemeGroupVersion.WithKind("Job"), "j4", "test-uid"). + Queue("lq4"). + Active(true). + Admission(utiltesting.MakeAdmission("cq4").Obj()). Creation(testStartTime.Add(-3 * time.Hour).Truncate(time.Second)). Conditions([]metav1.Condition{ { - Type: kueue.WorkloadFinished, - Status: metav1.ConditionTrue, + Type: kueue.WorkloadAdmitted, + Status: metav1.ConditionTrue, + LastTransitionTime: metav1.NewTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)), + }, + { + Type: kueue.WorkloadFinished, + Status: metav1.ConditionTrue, + LastTransitionTime: metav1.NewTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)), + }, + }...). + Obj(), + utiltesting.MakeWorkload("wl5", metav1.NamespaceDefault). + OwnerReference(batchv1.SchemeGroupVersion.WithKind("Job"), "j5", "test-uid"). + Queue("lq5"). + Active(true). + Admission(utiltesting.MakeAdmission("cq5").Obj()). + Creation(testStartTime.Add(-3 * time.Hour).Truncate(time.Second)). + Conditions([]metav1.Condition{ + { + Type: kueue.WorkloadAdmitted, + Status: metav1.ConditionTrue, + LastTransitionTime: metav1.NewTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)), + }, + { + Type: kueue.WorkloadFinished, + Status: metav1.ConditionFalse, + LastTransitionTime: metav1.NewTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)), }, }...). Obj(), }, - wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE AGE -wl1 j1 lq1 cq1 PENDING 60m -wl2 j2 lq2 cq2 ADMITTED 120m -wl3 j3 lq3 cq3 FINISHED 3h + wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE EXEC TIME AGE +wl1 j1 lq1 cq1 PENDING 60m +wl2 j2 lq2 cq2 ADMITTED 60m 120m +wl3 j3 lq3 cq3 PENDING 120m +wl4 j4 lq4 cq4 FINISHED 60m 3h +wl5 j5 lq5 cq5 ADMITTED 120m 3h `, }, "should print workload list with only admitted and finished status flags": { @@ -237,8 +279,9 @@ wl3 j3 lq3 cq3 FINISHED Creation(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). Conditions([]metav1.Condition{ { - Type: kueue.WorkloadAdmitted, - Status: metav1.ConditionTrue, + Type: kueue.WorkloadAdmitted, + Status: metav1.ConditionTrue, + LastTransitionTime: metav1.NewTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)), }, }...). Obj(), @@ -250,15 +293,21 @@ wl3 j3 lq3 cq3 FINISHED Creation(testStartTime.Add(-3 * time.Hour).Truncate(time.Second)). Conditions([]metav1.Condition{ { - Type: kueue.WorkloadFinished, - Status: metav1.ConditionTrue, + Type: kueue.WorkloadAdmitted, + Status: metav1.ConditionTrue, + LastTransitionTime: metav1.NewTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)), + }, + { + Type: kueue.WorkloadFinished, + Status: metav1.ConditionTrue, + LastTransitionTime: metav1.NewTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)), }, }...). Obj(), }, - wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE AGE -wl2 j2 lq2 cq2 ADMITTED 120m -wl3 j3 lq3 cq3 FINISHED 3h + wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE EXEC TIME AGE +wl2 j2 lq2 cq2 ADMITTED 60m 120m +wl3 j3 lq3 cq3 FINISHED 60m 3h `, }, "should print workload list with only pending filter": { @@ -285,8 +334,8 @@ wl3 j3 lq3 cq3 FINISHED }...). Obj(), }, - wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE AGE -wl1 j1 lq1 cq1 PENDING 60m + wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE EXEC TIME AGE +wl1 j1 lq1 cq1 PENDING 60m `, }, "should print workload list with only quotareserved filter": { @@ -319,8 +368,8 @@ wl1 j1 lq1 cq1 PENDING }...). Obj(), }, - wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE AGE -wl1 j1 lq1 cq1 QUOTARESERVED 60m + wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE EXEC TIME AGE +wl1 j1 lq1 cq1 QUOTARESERVED 60m `, }, "should print workload list with only admitted filter": { @@ -334,8 +383,9 @@ wl1 j1 lq1 cq1 QUOTARESERVED Creation(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). Conditions([]metav1.Condition{ { - Type: kueue.WorkloadAdmitted, - Status: metav1.ConditionTrue, + Type: kueue.WorkloadAdmitted, + Status: metav1.ConditionTrue, + LastTransitionTime: metav1.NewTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)), }, }...). Obj(), @@ -347,14 +397,15 @@ wl1 j1 lq1 cq1 QUOTARESERVED Creation(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). Conditions([]metav1.Condition{ { - Type: kueue.WorkloadAdmitted, - Status: metav1.ConditionFalse, + Type: kueue.WorkloadAdmitted, + Status: metav1.ConditionFalse, + LastTransitionTime: metav1.NewTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)), }, }...). Obj(), }, - wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE AGE -wl1 j1 lq1 cq1 ADMITTED 60m + wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE EXEC TIME AGE +wl1 j1 lq1 cq1 ADMITTED 60m 60m `, }, "should print workload list with only finished status filter": { @@ -368,8 +419,14 @@ wl1 j1 lq1 cq1 ADMITTED Creation(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). Conditions([]metav1.Condition{ { - Type: kueue.WorkloadFinished, - Status: metav1.ConditionTrue, + Type: kueue.WorkloadAdmitted, + Status: metav1.ConditionTrue, + LastTransitionTime: metav1.NewTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)), + }, + { + Type: kueue.WorkloadFinished, + Status: metav1.ConditionTrue, + LastTransitionTime: metav1.NewTime(testStartTime.Truncate(time.Second)), }, }...). Obj(), @@ -381,14 +438,20 @@ wl1 j1 lq1 cq1 ADMITTED Creation(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). Conditions([]metav1.Condition{ { - Type: kueue.WorkloadFinished, - Status: metav1.ConditionFalse, + Type: kueue.WorkloadAdmitted, + Status: metav1.ConditionTrue, + LastTransitionTime: metav1.NewTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)), + }, + { + Type: kueue.WorkloadFinished, + Status: metav1.ConditionFalse, + LastTransitionTime: metav1.NewTime(testStartTime.Truncate(time.Second)), }, }...). Obj(), }, - wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE AGE -wl1 j1 lq1 cq1 FINISHED 60m + wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE EXEC TIME AGE +wl1 j1 lq1 cq1 FINISHED 60m 60m `, }, "should print workload list with label selector filter": { @@ -411,8 +474,8 @@ wl1 j1 lq1 cq1 FINISHED Label("key", "value2"). Obj(), }, - wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE AGE -wl1 j1 lq1 cq1 PENDING 60m + wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE EXEC TIME AGE +wl1 j1 lq1 cq1 PENDING 60m `, }, "should print workload list with label selector filter (short flag)": { @@ -435,8 +498,8 @@ wl1 j1 lq1 cq1 PENDING Label("key", "value2"). Obj(), }, - wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE AGE -wl1 j1 lq1 cq1 PENDING 60m + wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE EXEC TIME AGE +wl1 j1 lq1 cq1 PENDING 60m `, }, "should print workload list with Job types": { @@ -494,10 +557,10 @@ wl1 j1 lq1 cq1 PENDING Creation(testStartTime.Add(-3 * time.Hour).Truncate(time.Second)). Obj(), }, - wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE AGE -wl1 job j1 lq1 cq1 PENDING 60m -wl2 rayjob.ray.io j2 lq2 cq2 PENDING 120m -wl3 pytorchjob.kubeflow.... j3 lq3 cq3 PENDING 3h + wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE EXEC TIME AGE +wl1 job j1 lq1 cq1 PENDING 60m +wl2 rayjob.ray.io j2 lq2 cq2 PENDING 120m +wl3 pytorchjob.kubeflow.... j3 lq3 cq3 PENDING 3h `, }, "should print workload list with resource filter": { @@ -553,8 +616,8 @@ wl3 pytorchjob.kubeflow.... j3 lq3 cq3 PENDING }, }, }, - wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE AGE -wl1 job.batch job-test lq1 cq1 PENDING 120m + wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE EXEC TIME AGE +wl1 job.batch job-test lq1 cq1 PENDING 120m `, }, "should print workload list with resource filter and composable jobs": { @@ -619,8 +682,8 @@ wl1 job.batch job-test lq1 cq1 PENDING }, }, }, - wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE AGE -wl2 pod pod-test-1 lq2 cq2 PENDING 3h + wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE EXEC TIME AGE +wl2 pod pod-test-1 lq2 cq2 PENDING 3h `, }, "should print workload list with custom resource filter": { @@ -687,8 +750,8 @@ wl2 pod pod-test-1 lq2 cq2 PENDING }, }, }, - wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE AGE -wl1 rayjob.ray.io job-test lq1 cq1 PENDING 120m + wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE EXEC TIME AGE +wl1 rayjob.ray.io job-test lq1 cq1 PENDING 120m `, }, "should print workload list with full resource filter": { @@ -755,8 +818,8 @@ wl1 rayjob.ray.io job-test lq1 cq1 PENDING }, }, }, - wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE AGE -wl1 rayjob.ray.io job-test lq1 cq1 PENDING 120m + wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE EXEC TIME AGE +wl1 rayjob.ray.io job-test lq1 cq1 PENDING 120m `, }, "should print workload list with position in queue": { @@ -798,9 +861,9 @@ wl1 rayjob.ray.io job-test lq1 cq1 PENDING Creation(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). Obj(), }, - wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE AGE -wl1 j1 lq1 cq1 PENDING 12 60m -wl2 j2 lq2 cq2 PENDING 22 120m + wantOut: `NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE EXEC TIME AGE +wl1 j1 lq1 cq1 PENDING 12 60m +wl2 j2 lq2 cq2 PENDING 22 120m `, }, "should print not found error": { diff --git a/test/integration/kueuectl/list_test.go b/test/integration/kueuectl/list_test.go index 0263050e0d..1b30471630 100644 --- a/test/integration/kueuectl/list_test.go +++ b/test/integration/kueuectl/list_test.go @@ -216,8 +216,8 @@ very-long-cluster-queue-name 0 0 gomega.Expect(err).NotTo(gomega.HaveOccurred(), "%s: %s", err, output) gomega.Expect(errOutput.String()).Should(gomega.BeEmpty()) - gomega.Expect(output.String()).Should(gomega.Equal(fmt.Sprintf(`NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE AGE -wl1 lq1 PENDING %s + gomega.Expect(output.String()).Should(gomega.Equal(fmt.Sprintf(`NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE EXEC TIME AGE +wl1 lq1 PENDING %s `, duration.HumanDuration(executeTime.Sub(wl1.CreationTimestamp.Time))))) }) @@ -235,10 +235,10 @@ wl1 lq1 PENDING gomega.Expect(err).NotTo(gomega.HaveOccurred(), "%s: %s", err, output) gomega.Expect(errOutput.String()).Should(gomega.BeEmpty()) - gomega.Expect(output.String()).Should(gomega.Equal(fmt.Sprintf(`NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE AGE -very-long-workload-name lq1 PENDING %s -wl1 lq1 PENDING %s -wl2 very-long-local-queue-name PENDING %s + gomega.Expect(output.String()).Should(gomega.Equal(fmt.Sprintf(`NAME JOB TYPE JOB NAME LOCALQUEUE CLUSTERQUEUE STATUS POSITION IN QUEUE EXEC TIME AGE +very-long-workload-name lq1 PENDING %s +wl1 lq1 PENDING %s +wl2 very-long-local-queue-name PENDING %s `, duration.HumanDuration(executeTime.Sub(wl3.CreationTimestamp.Time)), duration.HumanDuration(executeTime.Sub(wl1.CreationTimestamp.Time)), From afb49468223ca81419b13e45923f752f803dd80e Mon Sep 17 00:00:00 2001 From: Mykhailo Bobrovskyi Date: Wed, 4 Sep 2024 20:16:54 +0300 Subject: [PATCH 004/155] [kjobctl] Added list slurm command. (#2862) --- .../docs/commands/kjobctl_list/_index.md | 1 + .../kjobctl_list/kjobctl_list_slurm.md | 311 ++++++++++++++ .../kjobctl/pkg/builder/builder.go | 4 + .../kjobctl/pkg/builder/builder_test.go | 4 +- .../pkg/builder/interactive_builder_test.go | 6 +- .../kjobctl/pkg/builder/job_builder_test.go | 6 +- .../pkg/builder/ray_cluster_builder_test.go | 6 +- .../pkg/builder/ray_job_builder_test.go | 9 +- .../kjobctl/pkg/builder/slurm_builder_test.go | 2 + .../kjobctl/pkg/cmd/completion/completion.go | 9 +- .../pkg/cmd/completion/completion_test.go | 14 +- .../kjobctl/pkg/cmd/create/create_test.go | 19 + .../kjobctl/pkg/cmd/delete/delete_job.go | 3 +- cmd/experimental/kjobctl/pkg/cmd/list/list.go | 1 + .../kjobctl/pkg/cmd/list/list_job.go | 4 + .../kjobctl/pkg/cmd/list/list_job_test.go | 45 ++ .../kjobctl/pkg/cmd/list/list_slurm.go | 220 ++++++++++ .../kjobctl/pkg/cmd/list/list_slurm_test.go | 389 ++++++++++++++++++ .../kjobctl/pkg/cmd/list/list_test.go | 32 ++ .../kjobctl/pkg/constants/constants.go | 1 + .../testing/wrappers/configmap_wrappers.go | 6 + .../pkg/testing/wrappers/job_wrappers.go | 6 + .../pkg/testing/wrappers/pod_wrappers.go | 6 + .../testing/wrappers/ray_cluster_wrappers.go | 6 + .../pkg/testing/wrappers/ray_job_wrappers.go | 6 + .../test/integration/kjobctl/list_test.go | 66 +++ 26 files changed, 1163 insertions(+), 19 deletions(-) create mode 100644 cmd/experimental/kjobctl/docs/commands/kjobctl_list/kjobctl_list_slurm.md create mode 100644 cmd/experimental/kjobctl/pkg/cmd/list/list_slurm.go create mode 100644 cmd/experimental/kjobctl/pkg/cmd/list/list_slurm_test.go diff --git a/cmd/experimental/kjobctl/docs/commands/kjobctl_list/_index.md b/cmd/experimental/kjobctl/docs/commands/kjobctl_list/_index.md index 2a738ac68f..56049fb8f4 100644 --- a/cmd/experimental/kjobctl/docs/commands/kjobctl_list/_index.md +++ b/cmd/experimental/kjobctl/docs/commands/kjobctl_list/_index.md @@ -224,4 +224,5 @@ Display resources * [kjobctl list job](kjobctl_list_job.md) - List Job * [kjobctl list raycluster](kjobctl_list_raycluster.md) - List RayCluster * [kjobctl list rayjob](kjobctl_list_rayjob.md) - List RayJob +* [kjobctl list slurm](kjobctl_list_slurm.md) - List Slurm diff --git a/cmd/experimental/kjobctl/docs/commands/kjobctl_list/kjobctl_list_slurm.md b/cmd/experimental/kjobctl/docs/commands/kjobctl_list/kjobctl_list_slurm.md new file mode 100644 index 0000000000..b5efc17eaa --- /dev/null +++ b/cmd/experimental/kjobctl/docs/commands/kjobctl_list/kjobctl_list_slurm.md @@ -0,0 +1,311 @@ + + +# kjobctl list slurm + + +## Synopsis + + +List Slurm + +``` +kjobctl list slurm [--profile PROFILE_NAME] [--localqueue LOCALQUEUE_NAME] [--selector key1=value1] [--field-selector key1=value1] [--all-namespaces] +``` + + +## Examples + +``` + # List Slurm + kjobctl list slurm + + # List Slurm with profile filter + kjobctl list slurm --profile my-profile +``` + + +## Options + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
-A, --all-namespaces
+

If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.

+
--allow-missing-template-keys     Default: true
+

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.

+
--field-selector string
+

Selector (field query) to filter on, supports '=', '==', and '!='.(e.g. --field-selector key1=value1,key2=value2). The server only supports a limited number of field queries per type.

+
-h, --help
+

help for slurm

+
-q, --localqueue string
+

Filter by localqueue which is associated with the resource.

+
-o, --output string
+

Output format. One of: (json, yaml, name, go-template, go-template-file, template, templatefile, jsonpath, jsonpath-as-json, jsonpath-file).

+
-p, --profile string
+

Filter by profile name which is associated with the resource.

+
-l, --selector string
+

Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2). Matching objects must satisfy all of the specified label constraints.

+
--show-managed-fields
+

If true, keep the managedFields when printing objects in JSON or YAML format.

+
--template string
+

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].

+
+ + + +## Options inherited from parent commands + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
--as string
+

Username to impersonate for the operation. User could be a regular user or a service account in a namespace.

+
--as-group strings
+

Group to impersonate for the operation, this flag can be repeated to specify multiple groups.

+
--as-uid string
+

UID to impersonate for the operation.

+
--cache-dir string     Default: "$HOME/.kube/cache"
+

Default cache directory

+
--certificate-authority string
+

Path to a cert file for the certificate authority

+
--client-certificate string
+

Path to a client certificate file for TLS

+
--client-key string
+

Path to a client key file for TLS

+
--cluster string
+

The name of the kubeconfig cluster to use

+
--context string
+

The name of the kubeconfig context to use

+
--disable-compression
+

If true, opt-out of response compression for all requests to the server

+
--insecure-skip-tls-verify
+

If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure

+
--kubeconfig string
+

Path to the kubeconfig file to use for CLI requests.

+
-n, --namespace string
+

If present, the namespace scope for this CLI request

+
--request-timeout string     Default: "0"
+

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't timeout requests.

+
-s, --server string
+

The address and port of the Kubernetes API server

+
--tls-server-name string
+

Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used

+
--token string
+

Bearer token for authentication to the API server

+
--user string
+

The name of the kubeconfig user to use

+
+ + + +## See Also + +* [kjobctl_list](_index.md) - Display resources + diff --git a/cmd/experimental/kjobctl/pkg/builder/builder.go b/cmd/experimental/kjobctl/pkg/builder/builder.go index e97c4cec2a..e2dcdf2cdc 100644 --- a/cmd/experimental/kjobctl/pkg/builder/builder.go +++ b/cmd/experimental/kjobctl/pkg/builder/builder.go @@ -451,6 +451,10 @@ func (b *Builder) buildObjectMeta(templateObjectMeta metav1.ObjectMeta) metav1.O objectMeta.Labels[constants.ProfileLabel] = b.profile.Name } + if b.mode != nil { + objectMeta.Labels[constants.ModeLabel] = string(b.mode.Name) + } + if len(b.localQueue) > 0 { objectMeta.Labels[kueueconstants.QueueLabel] = b.localQueue } diff --git a/cmd/experimental/kjobctl/pkg/builder/builder_test.go b/cmd/experimental/kjobctl/pkg/builder/builder_test.go index 41e441a142..942c0eb387 100644 --- a/cmd/experimental/kjobctl/pkg/builder/builder_test.go +++ b/cmd/experimental/kjobctl/pkg/builder/builder_test.go @@ -32,7 +32,6 @@ import ( "sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1" "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" ) @@ -420,7 +419,8 @@ func TestBuilder(t *testing.T) { wrappers.MakeJob("", metav1.NamespaceDefault).GenerateName("profile-job-"). Annotation("foo", "baz"). Label("foo", "bar"). - Label(constants.ProfileLabel, "profile"). + Profile("profile"). + Mode(v1alpha1.JobMode). Obj(), }, }, diff --git a/cmd/experimental/kjobctl/pkg/builder/interactive_builder_test.go b/cmd/experimental/kjobctl/pkg/builder/interactive_builder_test.go index ff5af01db8..ceb51b149d 100644 --- a/cmd/experimental/kjobctl/pkg/builder/interactive_builder_test.go +++ b/cmd/experimental/kjobctl/pkg/builder/interactive_builder_test.go @@ -111,7 +111,8 @@ func TestInteractiveBuilder(t *testing.T) { wantObj: []runtime.Object{wrappers.MakePod("", metav1.NamespaceDefault).GenerateName("profile-interactive-"). Annotation("foo", "baz"). Label("foo", "bar"). - Label(constants.ProfileLabel, "profile"). + Profile("profile"). + Mode(v1alpha1.InteractiveMode). Spec( testPodTemplateWrapper.Clone(). WithEnvVar(corev1.EnvVar{Name: constants.EnvVarNameUserID, Value: userID}). @@ -153,7 +154,8 @@ func TestInteractiveBuilder(t *testing.T) { wrappers.MakePod("", metav1.NamespaceDefault).GenerateName("profile-interactive-"). Annotation("foo", "baz"). Label("foo", "bar"). - Label(constants.ProfileLabel, "profile"). + Profile("profile"). + Mode(v1alpha1.InteractiveMode). Label(kueueconstants.QueueLabel, "lq1"). Spec( testPodTemplateWrapper.Clone(). diff --git a/cmd/experimental/kjobctl/pkg/builder/job_builder_test.go b/cmd/experimental/kjobctl/pkg/builder/job_builder_test.go index d4f54bf630..3d6bd62e51 100644 --- a/cmd/experimental/kjobctl/pkg/builder/job_builder_test.go +++ b/cmd/experimental/kjobctl/pkg/builder/job_builder_test.go @@ -115,7 +115,8 @@ func TestJobBuilder(t *testing.T) { wrappers.MakeJob("", metav1.NamespaceDefault).GenerateName("profile-job-"). Annotation("foo", "baz"). Label("foo", "bar"). - Label(constants.ProfileLabel, "profile"). + Profile("profile"). + Mode(v1alpha1.JobMode). Spec( testJobTemplateWrapper.Clone(). WithEnvVar(corev1.EnvVar{Name: constants.EnvVarNameUserID, Value: userID}). @@ -157,7 +158,8 @@ func TestJobBuilder(t *testing.T) { wrappers.MakeJob("", metav1.NamespaceDefault).GenerateName("profile-job-"). Annotation("foo", "baz"). Label("foo", "bar"). - Label(constants.ProfileLabel, "profile"). + Profile("profile"). + Mode(v1alpha1.JobMode). Label(kueueconstants.QueueLabel, "lq1"). Spec( testJobTemplateWrapper.Clone(). diff --git a/cmd/experimental/kjobctl/pkg/builder/ray_cluster_builder_test.go b/cmd/experimental/kjobctl/pkg/builder/ray_cluster_builder_test.go index ef247bffac..10c4f856e5 100644 --- a/cmd/experimental/kjobctl/pkg/builder/ray_cluster_builder_test.go +++ b/cmd/experimental/kjobctl/pkg/builder/ray_cluster_builder_test.go @@ -149,7 +149,8 @@ func TestRayClusterBuilder(t *testing.T) { wrappers.MakeRayCluster("", metav1.NamespaceDefault).GenerateName("profile-raycluster-"). Annotation("foo", "baz"). Label("foo", "bar"). - Label(constants.ProfileLabel, "profile"). + Profile("profile"). + Mode(v1alpha1.RayClusterMode). Spec( testRayClusterTemplateWrapper.Clone(). Spec( @@ -196,7 +197,8 @@ func TestRayClusterBuilder(t *testing.T) { wrappers.MakeRayCluster("", metav1.NamespaceDefault).GenerateName("profile-raycluster-"). Annotation("foo", "baz"). Label("foo", "bar"). - Label(constants.ProfileLabel, "profile"). + Profile("profile"). + Mode(v1alpha1.RayClusterMode). Label(kueueconstants.QueueLabel, "lq1"). Spec( testRayClusterTemplateWrapper.Clone(). diff --git a/cmd/experimental/kjobctl/pkg/builder/ray_job_builder_test.go b/cmd/experimental/kjobctl/pkg/builder/ray_job_builder_test.go index 345d45e5c2..f1427c2fce 100644 --- a/cmd/experimental/kjobctl/pkg/builder/ray_job_builder_test.go +++ b/cmd/experimental/kjobctl/pkg/builder/ray_job_builder_test.go @@ -150,7 +150,8 @@ func TestRayJobBuilder(t *testing.T) { wrappers.MakeRayJob("", metav1.NamespaceDefault).GenerateName("profile-rayjob-"). Annotation("foo", "baz"). Label("foo", "bar"). - Label(constants.ProfileLabel, "profile"). + Profile("profile"). + Mode(v1alpha1.RayJobMode). Spec( testRayJobTemplateWrapper.Clone(). WithRayClusterSpec( @@ -197,7 +198,8 @@ func TestRayJobBuilder(t *testing.T) { wrappers.MakeRayJob("", metav1.NamespaceDefault).GenerateName("profile-rayjob-"). Annotation("foo", "baz"). Label("foo", "bar"). - Label(constants.ProfileLabel, "profile"). + Profile("profile"). + Mode(v1alpha1.RayJobMode). Label(kueueconstants.QueueLabel, "lq1"). Spec( testRayJobTemplateWrapper.Clone(). @@ -253,7 +255,8 @@ func TestRayJobBuilder(t *testing.T) { wrappers.MakeRayJob("", metav1.NamespaceDefault).GenerateName("profile-rayjob-"). Annotation("foo", "baz"). Label("foo", "bar"). - Label(constants.ProfileLabel, "profile"). + Profile("profile"). + Mode(v1alpha1.RayJobMode). WithRayClusterLabelSelector("rc1"). Entrypoint("python /home/ray/samples/sample_code.py"). Obj(), diff --git a/cmd/experimental/kjobctl/pkg/builder/slurm_builder_test.go b/cmd/experimental/kjobctl/pkg/builder/slurm_builder_test.go index f5b274fb27..4121bfbe8e 100644 --- a/cmd/experimental/kjobctl/pkg/builder/slurm_builder_test.go +++ b/cmd/experimental/kjobctl/pkg/builder/slurm_builder_test.go @@ -232,6 +232,7 @@ func TestSlurmBuilderDo(t *testing.T) { Completions(5). CompletionMode(batchv1.IndexedCompletion). Profile("profile"). + Mode(v1alpha1.SlurmMode). WithContainer(*wrappers.MakeContainer("c1", "bash:4.4"). Command("bash", "/slurm/entrypoint.sh"). WithVolumeMount(corev1.VolumeMount{MountPath: "/slurm"}). @@ -258,6 +259,7 @@ func TestSlurmBuilderDo(t *testing.T) { Obj(), wrappers.MakeConfigMap("", metav1.NamespaceDefault). Profile("profile"). + Mode(v1alpha1.SlurmMode). Data(map[string]string{ "script": "#!/bin/bash\nsleep 300'", "entrypoint.sh": `#!/usr/bin/bash diff --git a/cmd/experimental/kjobctl/pkg/cmd/completion/completion.go b/cmd/experimental/kjobctl/pkg/cmd/completion/completion.go index 296d9d4624..91feaa32df 100644 --- a/cmd/experimental/kjobctl/pkg/cmd/completion/completion.go +++ b/cmd/experimental/kjobctl/pkg/cmd/completion/completion.go @@ -17,12 +17,14 @@ limitations under the License. package completion import ( + "fmt" "slices" "strings" "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1" "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/cmd/util" "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/constants" ) @@ -154,7 +156,7 @@ func LocalQueueNameFunc(clientGetter util.ClientGetter) func(*cobra.Command, []s } } -func JobNameFunc(clientGetter util.ClientGetter) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) { +func JobNameFunc(clientGetter util.ClientGetter, mode v1alpha1.ApplicationProfileMode) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) { return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { clientset, err := clientGetter.K8sClientset() if err != nil { @@ -166,7 +168,10 @@ func JobNameFunc(clientGetter util.ClientGetter) func(*cobra.Command, []string, return []string{}, cobra.ShellCompDirectiveError } - opts := metav1.ListOptions{LabelSelector: constants.ProfileLabel, Limit: completionLimit} + opts := metav1.ListOptions{ + LabelSelector: fmt.Sprintf("%s,%s=%s", constants.ProfileLabel, constants.ModeLabel, mode), + Limit: completionLimit, + } list, err := clientset.BatchV1().Jobs(namespace).List(cmd.Context(), opts) if err != nil { return []string{}, cobra.ShellCompDirectiveError diff --git a/cmd/experimental/kjobctl/pkg/cmd/completion/completion_test.go b/cmd/experimental/kjobctl/pkg/cmd/completion/completion_test.go index 3bb84d0ec6..8cd3d8e25e 100644 --- a/cmd/experimental/kjobctl/pkg/cmd/completion/completion_test.go +++ b/cmd/experimental/kjobctl/pkg/cmd/completion/completion_test.go @@ -29,6 +29,7 @@ import ( "sigs.k8s.io/kueue/apis/kueue/v1beta1" kueuefake "sigs.k8s.io/kueue/client-go/clientset/versioned/fake" + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1" "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/testing/wrappers" @@ -110,11 +111,14 @@ func TestLocalQueueNameFunc(t *testing.T) { func TestJobNameCompletionFunc(t *testing.T) { args := []string{"job1"} objs := []runtime.Object{ - wrappers.MakeJob("job1", metav1.NamespaceDefault).Profile("p1").Obj(), - wrappers.MakeJob("job2", metav1.NamespaceDefault).Profile("p1").Obj(), - wrappers.MakeJob("job3", "test").Profile("p1").Obj(), - wrappers.MakeJob("job4", metav1.NamespaceDefault).Obj(), + wrappers.MakeJob("job1", metav1.NamespaceDefault).Profile("p1").Mode("jJb").Obj(), + wrappers.MakeJob("job2", metav1.NamespaceDefault).Profile("p1").Mode("Job").Obj(), + wrappers.MakeJob("job3", metav1.NamespaceDefault).Profile("p1").Mode("Slurm").Obj(), + wrappers.MakeJob("job4", "test").Profile("p1").Mode("Job").Obj(), + wrappers.MakeJob("job5", metav1.NamespaceDefault).Profile("p1").Obj(), + wrappers.MakeJob("job6", metav1.NamespaceDefault).Mode("Job").Obj(), } + mode := v1alpha1.JobMode wantNames := []string{"job2"} wantDirective := cobra.ShellCompDirectiveNoFileComp @@ -122,7 +126,7 @@ func TestJobNameCompletionFunc(t *testing.T) { tcg := cmdtesting.NewTestClientGetter() tcg.WithK8sClientset(k8sfake.NewSimpleClientset(objs...)) - complFn := JobNameFunc(tcg) + complFn := JobNameFunc(tcg, mode) names, directive := complFn(&cobra.Command{}, args, "") if diff := cmp.Diff(wantNames, names); diff != "" { t.Errorf("Unexpected names (-want/+got)\n%s", diff) diff --git a/cmd/experimental/kjobctl/pkg/cmd/create/create_test.go b/cmd/experimental/kjobctl/pkg/cmd/create/create_test.go index 383bcf48a4..aca79e78e4 100644 --- a/cmd/experimental/kjobctl/pkg/cmd/create/create_test.go +++ b/cmd/experimental/kjobctl/pkg/cmd/create/create_test.go @@ -160,6 +160,7 @@ func TestCreateCmd(t *testing.T) { *wrappers.MakeJob("", metav1.NamespaceDefault). GenerateName("profile-job-"). Profile("profile"). + Mode(v1alpha1.JobMode). Obj(), }, }, @@ -183,6 +184,7 @@ func TestCreateCmd(t *testing.T) { *wrappers.MakeRayJob("", metav1.NamespaceDefault). GenerateName("profile-rayjob-"). Profile("profile"). + Mode(v1alpha1.RayJobMode). Obj(), }, }, @@ -206,6 +208,7 @@ func TestCreateCmd(t *testing.T) { *wrappers.MakeRayCluster("", metav1.NamespaceDefault). GenerateName("profile-raycluster-"). Profile("profile"). + Mode(v1alpha1.RayClusterMode). Obj(), }, }, @@ -229,6 +232,7 @@ func TestCreateCmd(t *testing.T) { *wrappers.MakeJob("", metav1.NamespaceDefault). GenerateName("profile-job-"). Profile("profile"). + Mode(v1alpha1.JobMode). Obj(), }, }, @@ -254,6 +258,7 @@ func TestCreateCmd(t *testing.T) { *wrappers.MakeJob("", metav1.NamespaceDefault). GenerateName("profile-job-"). Profile("profile"). + Mode(v1alpha1.JobMode). LocalQueue("lq1"). Obj(), }, @@ -283,6 +288,7 @@ func TestCreateCmd(t *testing.T) { *wrappers.MakeJob("", metav1.NamespaceDefault). GenerateName("profile-job-"). Profile("profile"). + Mode(v1alpha1.JobMode). Parallelism(5). Completions(1). Obj(), @@ -313,6 +319,7 @@ func TestCreateCmd(t *testing.T) { *wrappers.MakeJob("", metav1.NamespaceDefault). GenerateName("profile-job-"). Profile("profile"). + Mode(v1alpha1.JobMode). Parallelism(1). Completions(5). Obj(), @@ -345,6 +352,7 @@ func TestCreateCmd(t *testing.T) { *wrappers.MakeJob("", metav1.NamespaceDefault). GenerateName("profile-job-"). Profile("profile"). + Mode(v1alpha1.JobMode). Parallelism(1). Completions(1). WithContainer(*wrappers.MakeContainer("c1", "sleep").Command("sleep", "15s").Obj()). @@ -387,6 +395,7 @@ func TestCreateCmd(t *testing.T) { *wrappers.MakeJob("", metav1.NamespaceDefault). GenerateName("profile-job-"). Profile("profile"). + Mode(v1alpha1.JobMode). Parallelism(1). Completions(1). WithContainer( @@ -435,6 +444,7 @@ func TestCreateCmd(t *testing.T) { *wrappers.MakeRayJob("", metav1.NamespaceDefault). GenerateName("profile-rayjob-"). Profile("profile"). + Mode(v1alpha1.RayJobMode). WithWorkerGroupSpec(*wrappers.MakeWorkerGroupSpec("g1").Replicas(5).Obj()). Obj(), }, @@ -462,6 +472,7 @@ func TestCreateCmd(t *testing.T) { *wrappers.MakeRayJob("", metav1.NamespaceDefault). GenerateName("profile-rayjob-"). Profile("profile"). + Mode(v1alpha1.RayJobMode). Entrypoint("sleep 3s"). Obj(), }, @@ -494,6 +505,7 @@ func TestCreateCmd(t *testing.T) { *wrappers.MakeRayJob("", metav1.NamespaceDefault). GenerateName("profile-rayjob-"). Profile("profile"). + Mode(v1alpha1.RayJobMode). WithWorkerGroupSpec(*wrappers.MakeWorkerGroupSpec("g1").MinReplicas(5).Obj()). Obj(), }, @@ -526,6 +538,7 @@ func TestCreateCmd(t *testing.T) { *wrappers.MakeRayJob("", metav1.NamespaceDefault). GenerateName("profile-rayjob-"). Profile("profile"). + Mode(v1alpha1.RayJobMode). WithWorkerGroupSpec(*wrappers.MakeWorkerGroupSpec("g1").MaxReplicas(5).Obj()). Obj(), }, @@ -558,6 +571,7 @@ func TestCreateCmd(t *testing.T) { *wrappers.MakeRayJob("", metav1.NamespaceDefault). GenerateName("profile-rayjob-"). Profile("profile"). + Mode(v1alpha1.RayJobMode). WithRayClusterLabelSelector("rc1"). Obj(), }, @@ -606,6 +620,7 @@ func TestCreateCmd(t *testing.T) { *wrappers.MakeRayCluster("", metav1.NamespaceDefault). GenerateName("profile-raycluster-"). Profile("profile"). + Mode(v1alpha1.RayClusterMode). Obj(), }, }, @@ -663,6 +678,7 @@ func TestCreateCmd(t *testing.T) { Completions(1). CompletionMode(batchv1.IndexedCompletion). Profile("profile"). + Mode(v1alpha1.SlurmMode). WithContainer(*wrappers.MakeContainer("c1", "bash:4.4"). Command("bash", "/slurm/entrypoint.sh"). WithVolumeMount(corev1.VolumeMount{MountPath: "/slurm"}). @@ -694,6 +710,7 @@ func TestCreateCmd(t *testing.T) { Items: []corev1.ConfigMap{ *wrappers.MakeConfigMap("", metav1.NamespaceDefault). Profile("profile"). + Mode(v1alpha1.SlurmMode). Data(map[string]string{ "script": "#!/bin/bash\nsleep 300'", "entrypoint.sh": `#!/usr/bin/bash @@ -833,6 +850,7 @@ error_path=$(unmask_filename "$SBATCH_ERROR") Completions(9). CompletionMode(batchv1.IndexedCompletion). Profile("profile"). + Mode(v1alpha1.SlurmMode). LocalQueue("lq1"). WithContainer(*wrappers.MakeContainer("c1-0", "bash:4.4"). Command("bash", "/slurm/entrypoint.sh"). @@ -873,6 +891,7 @@ error_path=$(unmask_filename "$SBATCH_ERROR") Items: []corev1.ConfigMap{ *wrappers.MakeConfigMap("", metav1.NamespaceDefault). Profile("profile"). + Mode(v1alpha1.SlurmMode). LocalQueue("lq1"). Data(map[string]string{ "script": "#!/bin/bash\nsleep 300'", diff --git a/cmd/experimental/kjobctl/pkg/cmd/delete/delete_job.go b/cmd/experimental/kjobctl/pkg/cmd/delete/delete_job.go index e276ef9271..9bed6b2ea4 100644 --- a/cmd/experimental/kjobctl/pkg/cmd/delete/delete_job.go +++ b/cmd/experimental/kjobctl/pkg/cmd/delete/delete_job.go @@ -30,6 +30,7 @@ import ( "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1" "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/cmd/completion" "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/cmd/util" "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/constants" @@ -72,7 +73,7 @@ func NewJobCmd(clientGetter util.ClientGetter, streams genericiooptions.IOStream Short: "Delete Job", Example: jobExample, Args: cobra.MinimumNArgs(1), - ValidArgsFunction: completion.JobNameFunc(clientGetter), + ValidArgsFunction: completion.JobNameFunc(clientGetter, v1alpha1.JobMode), RunE: func(cmd *cobra.Command, args []string) error { cmd.SilenceUsage = true diff --git a/cmd/experimental/kjobctl/pkg/cmd/list/list.go b/cmd/experimental/kjobctl/pkg/cmd/list/list.go index c8c5b1821d..22a0484b2c 100644 --- a/cmd/experimental/kjobctl/pkg/cmd/list/list.go +++ b/cmd/experimental/kjobctl/pkg/cmd/list/list.go @@ -41,6 +41,7 @@ func NewListCmd(clientGetter util.ClientGetter, streams genericiooptions.IOStrea cmd.AddCommand(NewInteractiveCmd(clientGetter, streams, clock)) cmd.AddCommand(NewRayJobCmd(clientGetter, streams, clock)) cmd.AddCommand(NewRayClusterCmd(clientGetter, streams, clock)) + cmd.AddCommand(NewSlurmCmd(clientGetter, streams, clock)) return cmd } diff --git a/cmd/experimental/kjobctl/pkg/cmd/list/list_job.go b/cmd/experimental/kjobctl/pkg/cmd/list/list_job.go index 57578b1554..0687445881 100644 --- a/cmd/experimental/kjobctl/pkg/cmd/list/list_job.go +++ b/cmd/experimental/kjobctl/pkg/cmd/list/list_job.go @@ -29,6 +29,7 @@ import ( batchv1 "k8s.io/client-go/kubernetes/typed/batch/v1" "k8s.io/utils/clock" + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1" "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/cmd/completion" "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/cmd/util" "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/constants" @@ -165,6 +166,9 @@ func (o *JobOptions) Run(ctx context.Context) error { } else { opts.LabelSelector = constants.ProfileLabel } + + opts.LabelSelector = fmt.Sprintf("%s,%s=%s", opts.LabelSelector, constants.ModeLabel, v1alpha1.JobMode) + if len(o.LocalQueueFilter) > 0 { opts.LabelSelector = fmt.Sprintf("%s,%s=%s", opts.LabelSelector, kueueconstants.QueueLabel, o.LocalQueueFilter) } diff --git a/cmd/experimental/kjobctl/pkg/cmd/list/list_job_test.go b/cmd/experimental/kjobctl/pkg/cmd/list/list_job_test.go index 5b972ea8bd..e4bc324c83 100644 --- a/cmd/experimental/kjobctl/pkg/cmd/list/list_job_test.go +++ b/cmd/experimental/kjobctl/pkg/cmd/list/list_job_test.go @@ -32,6 +32,7 @@ import ( kubetesting "k8s.io/client-go/testing" testingclock "k8s.io/utils/clock/testing" + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1" cmdtesting "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/cmd/testing" "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/testing/wrappers" ) @@ -52,6 +53,7 @@ func TestJobCmd(t *testing.T) { objs: []runtime.Object{ wrappers.MakeJob("j1", "ns1"). Profile("profile1"). + Mode(v1alpha1.JobMode). LocalQueue("lq1"). Completions(3). CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). @@ -70,6 +72,33 @@ func TestJobCmd(t *testing.T) { }, wantOut: `NAME PROFILE LOCAL QUEUE COMPLETIONS DURATION AGE j1 profile1 lq1 3/3 60m 60m +`, + }, + "should print only Job mode jobs": { + ns: "ns1", + objs: []runtime.Object{ + wrappers.MakeJob("j1", "ns1"). + Profile("profile1"). + Mode(v1alpha1.JobMode). + LocalQueue("lq1"). + Completions(3). + CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + StartTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + CompletionTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + Succeeded(3). + Obj(), + wrappers.MakeJob("j2", "ns2"). + LocalQueue("lq2"). + Mode(v1alpha1.SlurmMode). + Completions(3). + CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + StartTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + CompletionTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + Succeeded(3). + Obj(), + }, + wantOut: `NAME PROFILE LOCAL QUEUE COMPLETIONS DURATION AGE +j1 profile1 lq1 3/3 60m 60m `, }, "should print job list with namespace filter": { @@ -77,6 +106,7 @@ j1 profile1 lq1 3/3 60m 60m objs: []runtime.Object{ wrappers.MakeJob("j1", "ns1"). Profile("profile1"). + Mode(v1alpha1.JobMode). LocalQueue("lq1"). Completions(3). CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). @@ -86,6 +116,7 @@ j1 profile1 lq1 3/3 60m 60m Obj(), wrappers.MakeJob("j2", "ns2"). Profile("profile2"). + Mode(v1alpha1.JobMode). LocalQueue("lq2"). Completions(3). CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). @@ -103,6 +134,7 @@ j1 profile1 lq1 3/3 60m 60m objs: []runtime.Object{ wrappers.MakeJob("j1", metav1.NamespaceDefault). Profile("profile1"). + Mode(v1alpha1.JobMode). LocalQueue("lq1"). Completions(3). CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). @@ -112,6 +144,7 @@ j1 profile1 lq1 3/3 60m 60m Obj(), wrappers.MakeJob("j2", metav1.NamespaceDefault). Profile("profile2"). + Mode(v1alpha1.JobMode). LocalQueue("lq2"). Completions(3). CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). @@ -129,6 +162,7 @@ j1 profile1 lq1 3/3 60m 60m objs: []runtime.Object{ wrappers.MakeJob("j1", metav1.NamespaceDefault). Profile("profile1"). + Mode(v1alpha1.JobMode). LocalQueue("lq1"). Completions(3). CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). @@ -138,6 +172,7 @@ j1 profile1 lq1 3/3 60m 60m Obj(), wrappers.MakeJob("j2", metav1.NamespaceDefault). Profile("profile2"). + Mode(v1alpha1.JobMode). LocalQueue("lq2"). Completions(3). CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). @@ -155,6 +190,7 @@ j1 profile1 lq1 3/3 60m 60m objs: []runtime.Object{ wrappers.MakeJob("j1", metav1.NamespaceDefault). Profile("profile1"). + Mode(v1alpha1.JobMode). LocalQueue("lq1"). LocalQueue("lq1"). Completions(3). @@ -165,6 +201,7 @@ j1 profile1 lq1 3/3 60m 60m Obj(), wrappers.MakeJob("j2", metav1.NamespaceDefault). Profile("profile2"). + Mode(v1alpha1.JobMode). LocalQueue("lq2"). LocalQueue("lq2"). Completions(3). @@ -183,6 +220,7 @@ j1 profile1 lq1 3/3 60m 60m objs: []runtime.Object{ wrappers.MakeJob("j1", metav1.NamespaceDefault). Profile("profile1"). + Mode(v1alpha1.JobMode). LocalQueue("lq1"). Completions(3). CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). @@ -192,6 +230,7 @@ j1 profile1 lq1 3/3 60m 60m Obj(), wrappers.MakeJob("j2", metav1.NamespaceDefault). Profile("profile2"). + Mode(v1alpha1.JobMode). LocalQueue("lq2"). LocalQueue("lq2"). Completions(3). @@ -210,6 +249,7 @@ j1 profile1 lq1 3/3 60m 60m objs: []runtime.Object{ wrappers.MakeJob("j1", metav1.NamespaceDefault). Profile("profile1"). + Mode(v1alpha1.JobMode). LocalQueue("lq1"). Label("foo", "bar"). Completions(3). @@ -220,6 +260,7 @@ j1 profile1 lq1 3/3 60m 60m Obj(), wrappers.MakeJob("j2", metav1.NamespaceDefault). Profile("profile2"). + Mode(v1alpha1.JobMode). LocalQueue("lq2"). Completions(3). CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). @@ -237,6 +278,7 @@ j1 profile1 lq1 3/3 60m 60m objs: []runtime.Object{ wrappers.MakeJob("j1", metav1.NamespaceDefault). Profile("profile1"). + Mode(v1alpha1.JobMode). LocalQueue("lq1"). Label("foo", "bar"). Completions(3). @@ -247,6 +289,7 @@ j1 profile1 lq1 3/3 60m 60m Obj(), wrappers.MakeJob("j2", metav1.NamespaceDefault). Profile("profile2"). + Mode(v1alpha1.JobMode). LocalQueue("lq2"). Completions(3). CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). @@ -264,6 +307,7 @@ j1 profile1 lq1 3/3 60m 60m objs: []runtime.Object{ wrappers.MakeJob("j1", metav1.NamespaceDefault). Profile("profile1"). + Mode(v1alpha1.JobMode). LocalQueue("lq1"). Completions(3). CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). @@ -273,6 +317,7 @@ j1 profile1 lq1 3/3 60m 60m Obj(), wrappers.MakeJob("j2", metav1.NamespaceDefault). Profile("profile2"). + Mode(v1alpha1.JobMode). LocalQueue("lq2"). Completions(3). CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). diff --git a/cmd/experimental/kjobctl/pkg/cmd/list/list_slurm.go b/cmd/experimental/kjobctl/pkg/cmd/list/list_slurm.go new file mode 100644 index 0000000000..76a81799ff --- /dev/null +++ b/cmd/experimental/kjobctl/pkg/cmd/list/list_slurm.go @@ -0,0 +1,220 @@ +/* +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 list + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + "k8s.io/cli-runtime/pkg/printers" + "k8s.io/client-go/kubernetes/scheme" + batchv1 "k8s.io/client-go/kubernetes/typed/batch/v1" + "k8s.io/utils/clock" + + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1" + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/cmd/completion" + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/cmd/util" + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/constants" + kueueconstants "sigs.k8s.io/kueue/pkg/controller/constants" +) + +const ( + slurmExample = ` # List Slurm + kjobctl list slurm + + # List Slurm with profile filter + kjobctl list slurm --profile my-profile` +) + +type SlurmOptions struct { + Clock clock.Clock + PrintFlags *genericclioptions.PrintFlags + + Limit int64 + AllNamespaces bool + Namespace string + ProfileFilter string + LocalQueueFilter string + FieldSelector string + LabelSelector string + + Client batchv1.BatchV1Interface + + genericiooptions.IOStreams +} + +func NewSlurmOptions(streams genericiooptions.IOStreams, clock clock.Clock) *SlurmOptions { + return &SlurmOptions{ + PrintFlags: genericclioptions.NewPrintFlags("").WithTypeSetter(scheme.Scheme), + IOStreams: streams, + Clock: clock, + } +} + +func NewSlurmCmd(clientGetter util.ClientGetter, streams genericiooptions.IOStreams, clock clock.Clock) *cobra.Command { + o := NewSlurmOptions(streams, clock) + + cmd := &cobra.Command{ + Use: "slurm" + + " [--profile PROFILE_NAME]" + + " [--localqueue LOCALQUEUE_NAME]" + + " [--selector key1=value1]" + + " [--field-selector key1=value1]" + + " [--all-namespaces]", + DisableFlagsInUseLine: true, + Short: "List Slurm", + Example: slurmExample, + RunE: func(cmd *cobra.Command, _ []string) error { + cmd.SilenceUsage = true + err := o.Complete(clientGetter) + if err != nil { + return err + } + return o.Run(cmd.Context()) + }, + } + + o.PrintFlags.AddFlags(cmd) + + util.AddAllNamespacesFlagVar(cmd, &o.AllNamespaces) + util.AddFieldSelectorFlagVar(cmd, &o.FieldSelector) + util.AddLabelSelectorFlagVar(cmd, &o.LabelSelector) + util.AddProfileFlagVar(cmd, &o.ProfileFilter) + util.AddLocalQueueFlagVar(cmd, &o.LocalQueueFilter) + + cobra.CheckErr(cmd.RegisterFlagCompletionFunc("profile", completion.ApplicationProfileNameFunc(clientGetter))) + cobra.CheckErr(cmd.RegisterFlagCompletionFunc("localqueue", completion.LocalQueueNameFunc(clientGetter))) + + return cmd +} + +// Complete completes all the required options +func (o *SlurmOptions) Complete(clientGetter util.ClientGetter) error { + var err error + + o.Limit, err = listRequestLimit() + if err != nil { + return err + } + + o.Namespace, _, err = clientGetter.ToRawKubeConfigLoader().Namespace() + if err != nil { + return err + } + + clientset, err := clientGetter.K8sClientset() + if err != nil { + return err + } + + o.Client = clientset.BatchV1() + + return nil +} + +func (o *SlurmOptions) ToPrinter(headers bool) (printers.ResourcePrinterFunc, error) { + if !o.PrintFlags.OutputFlagSpecified() { + printer := newJobTablePrinter(). + WithNamespace(o.AllNamespaces). + WithHeaders(headers). + WithClock(o.Clock) + return printer.PrintObj, nil + } + + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return nil, err + } + + return printer.PrintObj, nil +} + +// Run performs the list operation. +func (o *SlurmOptions) Run(ctx context.Context) error { + var totalCount int + + namespace := o.Namespace + if o.AllNamespaces { + namespace = "" + } + + opts := metav1.ListOptions{ + FieldSelector: o.FieldSelector, + Limit: o.Limit, + } + + if len(o.ProfileFilter) > 0 { + opts.LabelSelector = fmt.Sprintf("%s=%s", constants.ProfileLabel, o.ProfileFilter) + } else { + opts.LabelSelector = constants.ProfileLabel + } + + opts.LabelSelector = fmt.Sprintf("%s,%s=%s", opts.LabelSelector, constants.ModeLabel, v1alpha1.SlurmMode) + + if len(o.LocalQueueFilter) > 0 { + opts.LabelSelector = fmt.Sprintf("%s,%s=%s", opts.LabelSelector, kueueconstants.QueueLabel, o.LocalQueueFilter) + } + if len(o.LabelSelector) > 0 { + opts.LabelSelector = fmt.Sprintf("%s,%s", opts.LabelSelector, o.LabelSelector) + } + + tabWriter := printers.GetNewTabWriter(o.Out) + + for { + headers := totalCount == 0 + + list, err := o.Client.Jobs(namespace).List(ctx, opts) + if err != nil { + return err + } + + totalCount += len(list.Items) + + printer, err := o.ToPrinter(headers) + if err != nil { + return err + } + + if err := printer.PrintObj(list, tabWriter); err != nil { + return err + } + + if list.Continue != "" { + opts.Continue = list.Continue + continue + } + + if totalCount == 0 { + if !o.AllNamespaces { + fmt.Fprintf(o.ErrOut, "No resources found in %s namespace.\n", o.Namespace) + } else { + fmt.Fprintln(o.ErrOut, "No resources found") + } + return nil + } + + if err := tabWriter.Flush(); err != nil { + return err + } + + return nil + } +} diff --git a/cmd/experimental/kjobctl/pkg/cmd/list/list_slurm_test.go b/cmd/experimental/kjobctl/pkg/cmd/list/list_slurm_test.go new file mode 100644 index 0000000000..0bfc8144b4 --- /dev/null +++ b/cmd/experimental/kjobctl/pkg/cmd/list/list_slurm_test.go @@ -0,0 +1,389 @@ +/* +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 list + +import ( + "fmt" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + batchv1 "k8s.io/api/batch/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/cli-runtime/pkg/genericiooptions" + "k8s.io/client-go/kubernetes/fake" + kubetesting "k8s.io/client-go/testing" + testingclock "k8s.io/utils/clock/testing" + + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1" + cmdtesting "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/cmd/testing" + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/testing/wrappers" +) + +func TestSlurmCmd(t *testing.T) { + testStartTime := time.Now() + + testCases := map[string]struct { + ns string + objs []runtime.Object + args []string + wantOut string + wantOutErr string + wantErr error + }{ + "should print only kjobctl jobs": { + ns: "ns1", + objs: []runtime.Object{ + wrappers.MakeJob("j1", "ns1"). + Profile("profile1"). + Mode(v1alpha1.SlurmMode). + LocalQueue("lq1"). + Completions(3). + CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + StartTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + CompletionTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + Succeeded(3). + Obj(), + wrappers.MakeJob("j2", "ns2"). + LocalQueue("lq2"). + Completions(3). + CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + StartTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + CompletionTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + Succeeded(3). + Obj(), + }, + wantOut: `NAME PROFILE LOCAL QUEUE COMPLETIONS DURATION AGE +j1 profile1 lq1 3/3 60m 60m +`, + }, + "should print only Slurm mode jobs": { + ns: "ns1", + objs: []runtime.Object{ + wrappers.MakeJob("j1", "ns1"). + Profile("profile1"). + Mode(v1alpha1.SlurmMode). + LocalQueue("lq1"). + Completions(3). + CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + StartTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + CompletionTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + Succeeded(3). + Obj(), + wrappers.MakeJob("j2", "ns2"). + LocalQueue("lq2"). + Completions(3). + CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + StartTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + CompletionTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + Succeeded(3). + Obj(), + }, + wantOut: `NAME PROFILE LOCAL QUEUE COMPLETIONS DURATION AGE +j1 profile1 lq1 3/3 60m 60m +`, + }, + "should print slurm job list with namespace filter": { + ns: "ns1", + objs: []runtime.Object{ + wrappers.MakeJob("j1", "ns1"). + Profile("profile1"). + Mode(v1alpha1.SlurmMode). + LocalQueue("lq1"). + Completions(3). + CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + StartTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + CompletionTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + Succeeded(3). + Obj(), + wrappers.MakeJob("j2", "ns2"). + Profile("profile2"). + Mode(v1alpha1.SlurmMode). + LocalQueue("lq2"). + Completions(3). + CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + StartTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + CompletionTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + Succeeded(3). + Obj(), + }, + wantOut: `NAME PROFILE LOCAL QUEUE COMPLETIONS DURATION AGE +j1 profile1 lq1 3/3 60m 60m +`, + }, + "should print slurm job list with profile filter": { + args: []string{"--profile", "profile1"}, + objs: []runtime.Object{ + wrappers.MakeJob("j1", metav1.NamespaceDefault). + Profile("profile1"). + Mode(v1alpha1.SlurmMode). + LocalQueue("lq1"). + Completions(3). + CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + StartTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + CompletionTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + Succeeded(3). + Obj(), + wrappers.MakeJob("j2", metav1.NamespaceDefault). + Profile("profile2"). + Mode(v1alpha1.SlurmMode). + LocalQueue("lq2"). + Completions(3). + CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + StartTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + CompletionTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + Succeeded(3). + Obj(), + }, + wantOut: `NAME PROFILE LOCAL QUEUE COMPLETIONS DURATION AGE +j1 profile1 lq1 3/3 60m 60m +`, + }, + "should print slurm job list with profile filter (short flag)": { + args: []string{"-p", "profile1"}, + objs: []runtime.Object{ + wrappers.MakeJob("j1", metav1.NamespaceDefault). + Profile("profile1"). + Mode(v1alpha1.SlurmMode). + LocalQueue("lq1"). + Completions(3). + CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + StartTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + CompletionTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + Succeeded(3). + Obj(), + wrappers.MakeJob("j2", metav1.NamespaceDefault). + Profile("profile2"). + Mode(v1alpha1.SlurmMode). + LocalQueue("lq2"). + Completions(3). + CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + StartTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + CompletionTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + Succeeded(3). + Obj(), + }, + wantOut: `NAME PROFILE LOCAL QUEUE COMPLETIONS DURATION AGE +j1 profile1 lq1 3/3 60m 60m +`, + }, + "should print slurm job list with localqueue filter": { + args: []string{"--localqueue", "lq1"}, + objs: []runtime.Object{ + wrappers.MakeJob("j1", metav1.NamespaceDefault). + Profile("profile1"). + Mode(v1alpha1.SlurmMode). + LocalQueue("lq1"). + LocalQueue("lq1"). + Completions(3). + CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + StartTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + CompletionTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + Succeeded(3). + Obj(), + wrappers.MakeJob("j2", metav1.NamespaceDefault). + Profile("profile2"). + Mode(v1alpha1.SlurmMode). + LocalQueue("lq2"). + LocalQueue("lq2"). + Completions(3). + CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + StartTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + CompletionTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + Succeeded(3). + Obj(), + }, + wantOut: `NAME PROFILE LOCAL QUEUE COMPLETIONS DURATION AGE +j1 profile1 lq1 3/3 60m 60m +`, + }, + "should print slurm job list with localqueue filter (short flag)": { + args: []string{"-q", "lq1"}, + objs: []runtime.Object{ + wrappers.MakeJob("j1", metav1.NamespaceDefault). + Profile("profile1"). + Mode(v1alpha1.SlurmMode). + LocalQueue("lq1"). + Completions(3). + CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + StartTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + CompletionTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + Succeeded(3). + Obj(), + wrappers.MakeJob("j2", metav1.NamespaceDefault). + Profile("profile2"). + Mode(v1alpha1.SlurmMode). + LocalQueue("lq2"). + LocalQueue("lq2"). + Completions(3). + CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + StartTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + CompletionTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + Succeeded(3). + Obj(), + }, + wantOut: `NAME PROFILE LOCAL QUEUE COMPLETIONS DURATION AGE +j1 profile1 lq1 3/3 60m 60m +`, + }, + "should print slurm job list with label selector filter": { + args: []string{"--selector", "foo=bar"}, + objs: []runtime.Object{ + wrappers.MakeJob("j1", metav1.NamespaceDefault). + Profile("profile1"). + Mode(v1alpha1.SlurmMode). + LocalQueue("lq1"). + Label("foo", "bar"). + Completions(3). + CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + StartTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + CompletionTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + Succeeded(3). + Obj(), + wrappers.MakeJob("j2", metav1.NamespaceDefault). + Profile("profile2"). + Mode(v1alpha1.SlurmMode). + LocalQueue("lq2"). + Completions(3). + CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + StartTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + CompletionTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + Succeeded(3). + Obj(), + }, + wantOut: `NAME PROFILE LOCAL QUEUE COMPLETIONS DURATION AGE +j1 profile1 lq1 3/3 60m 60m +`, + }, + "should print slurm job list with label selector filter (short flag)": { + args: []string{"-l", "foo=bar"}, + objs: []runtime.Object{ + wrappers.MakeJob("j1", metav1.NamespaceDefault). + Profile("profile1"). + Mode(v1alpha1.SlurmMode). + LocalQueue("lq1"). + Label("foo", "bar"). + Completions(3). + CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + StartTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + CompletionTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + Succeeded(3). + Obj(), + wrappers.MakeJob("j2", metav1.NamespaceDefault). + Profile("profile2"). + Mode(v1alpha1.SlurmMode). + LocalQueue("lq2"). + Completions(3). + CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + StartTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + CompletionTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + Succeeded(3). + Obj(), + }, + wantOut: `NAME PROFILE LOCAL QUEUE COMPLETIONS DURATION AGE +j1 profile1 lq1 3/3 60m 60m +`, + }, + "should print slurm job list with field selector filter": { + args: []string{"--field-selector", "metadata.name=j1"}, + objs: []runtime.Object{ + wrappers.MakeJob("j1", metav1.NamespaceDefault). + Profile("profile1"). + Mode(v1alpha1.SlurmMode). + LocalQueue("lq1"). + Completions(3). + CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + StartTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + CompletionTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + Succeeded(3). + Obj(), + wrappers.MakeJob("j2", metav1.NamespaceDefault). + Profile("profile2"). + Mode(v1alpha1.SlurmMode). + LocalQueue("lq2"). + Completions(3). + CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + StartTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + CompletionTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + Succeeded(3). + Obj(), + }, + wantOut: `NAME PROFILE LOCAL QUEUE COMPLETIONS DURATION AGE +j1 profile1 lq1 3/3 60m 60m +`, + }, + "should print not found error": { + wantOutErr: fmt.Sprintf("No resources found in %s namespace.\n", metav1.NamespaceDefault), + }, + "should print not found error with all-namespaces filter": { + args: []string{"-A"}, + wantOutErr: "No resources found\n", + }, + } + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + streams, _, out, outErr := genericiooptions.NewTestIOStreams() + + clientset := fake.NewSimpleClientset(tc.objs...) + clientset.PrependReactor("list", "jobs", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { + listAction := action.(kubetesting.ListActionImpl) + fieldsSelector := listAction.GetListRestrictions().Fields + + obj, err := clientset.Tracker().List(listAction.GetResource(), listAction.GetKind(), listAction.Namespace) + jobList := obj.(*batchv1.JobList) + + filtered := make([]batchv1.Job, 0, len(jobList.Items)) + for _, item := range jobList.Items { + fieldsSet := fields.Set{ + "metadata.name": item.Name, + } + if fieldsSelector.Matches(fieldsSet) { + filtered = append(filtered, item) + } + } + jobList.Items = filtered + return true, jobList, err + }) + + tcg := cmdtesting.NewTestClientGetter().WithK8sClientset(clientset) + if len(tc.ns) > 0 { + tcg.WithNamespace(tc.ns) + } + + cmd := NewSlurmCmd(tcg, streams, testingclock.NewFakeClock(testStartTime)) + cmd.SetArgs(tc.args) + + gotErr := cmd.Execute() + if diff := cmp.Diff(tc.wantErr, gotErr, cmpopts.EquateErrors()); diff != "" { + t.Errorf("Unexpected error (-want/+got)\n%s", diff) + } + + gotOut := out.String() + if diff := cmp.Diff(tc.wantOut, gotOut); diff != "" { + t.Errorf("Unexpected output (-want/+got)\n%s", diff) + } + + gotOutErr := outErr.String() + if diff := cmp.Diff(tc.wantOutErr, gotOutErr); diff != "" { + t.Errorf("Unexpected output (-want/+got)\n%s", diff) + } + }) + } +} diff --git a/cmd/experimental/kjobctl/pkg/cmd/list/list_test.go b/cmd/experimental/kjobctl/pkg/cmd/list/list_test.go index f77037e821..f700218873 100644 --- a/cmd/experimental/kjobctl/pkg/cmd/list/list_test.go +++ b/cmd/experimental/kjobctl/pkg/cmd/list/list_test.go @@ -32,6 +32,7 @@ import ( k8sfake "k8s.io/client-go/kubernetes/fake" testingclock "k8s.io/utils/clock/testing" + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1" cmdtesting "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/cmd/testing" "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/testing/wrappers" ) @@ -53,6 +54,7 @@ func TestListCmd(t *testing.T) { k8sObjs: []runtime.Object{ wrappers.MakeJob("j1", "ns1"). Profile("profile1"). + Mode(v1alpha1.JobMode). LocalQueue("lq1"). Completions(3). CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). @@ -62,6 +64,36 @@ func TestListCmd(t *testing.T) { Obj(), wrappers.MakeJob("j2", "ns2"). Profile("profile2"). + Mode(v1alpha1.JobMode). + LocalQueue("lq1"). + Completions(3). + CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + StartTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + CompletionTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + Succeeded(3). + Obj(), + }, + wantOut: `NAMESPACE NAME PROFILE LOCAL QUEUE COMPLETIONS DURATION AGE +ns1 j1 profile1 lq1 3/3 60m 60m +ns2 j2 profile2 lq1 3/3 60m 60m +`, + }, + "should print slurm job list with all namespaces": { + args: []string{"slurm", "--all-namespaces"}, + k8sObjs: []runtime.Object{ + wrappers.MakeJob("j1", "ns1"). + Profile("profile1"). + Mode(v1alpha1.SlurmMode). + LocalQueue("lq1"). + Completions(3). + CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + StartTime(testStartTime.Add(-2 * time.Hour).Truncate(time.Second)). + CompletionTime(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). + Succeeded(3). + Obj(), + wrappers.MakeJob("j2", "ns2"). + Profile("profile2"). + Mode(v1alpha1.SlurmMode). LocalQueue("lq1"). Completions(3). CreationTimestamp(testStartTime.Add(-1 * time.Hour).Truncate(time.Second)). diff --git a/cmd/experimental/kjobctl/pkg/constants/constants.go b/cmd/experimental/kjobctl/pkg/constants/constants.go index 68c22f3f9d..a243442e47 100644 --- a/cmd/experimental/kjobctl/pkg/constants/constants.go +++ b/cmd/experimental/kjobctl/pkg/constants/constants.go @@ -18,6 +18,7 @@ package constants const ( ProfileLabel = "kjobctl.x-k8s.io/profile" + ModeLabel = "kjobctl.x-k8s.io/mode" ) const ( diff --git a/cmd/experimental/kjobctl/pkg/testing/wrappers/configmap_wrappers.go b/cmd/experimental/kjobctl/pkg/testing/wrappers/configmap_wrappers.go index 2c9ffe597e..cf90d060b3 100644 --- a/cmd/experimental/kjobctl/pkg/testing/wrappers/configmap_wrappers.go +++ b/cmd/experimental/kjobctl/pkg/testing/wrappers/configmap_wrappers.go @@ -20,6 +20,7 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1" "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/constants" kueueconstants "sigs.k8s.io/kueue/pkg/controller/constants" ) @@ -50,6 +51,11 @@ func (w *ConfigMapWrapper) Profile(v string) *ConfigMapWrapper { return w.Label(constants.ProfileLabel, v) } +// Mode sets the profile label. +func (w *ConfigMapWrapper) Mode(v v1alpha1.ApplicationProfileMode) *ConfigMapWrapper { + return w.Label(constants.ModeLabel, string(v)) +} + // LocalQueue sets the localqueue label. func (w *ConfigMapWrapper) LocalQueue(v string) *ConfigMapWrapper { return w.Label(kueueconstants.QueueLabel, v) diff --git a/cmd/experimental/kjobctl/pkg/testing/wrappers/job_wrappers.go b/cmd/experimental/kjobctl/pkg/testing/wrappers/job_wrappers.go index b202e7623c..6949c7cead 100644 --- a/cmd/experimental/kjobctl/pkg/testing/wrappers/job_wrappers.go +++ b/cmd/experimental/kjobctl/pkg/testing/wrappers/job_wrappers.go @@ -25,6 +25,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1" "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/constants" kueueconstants "sigs.k8s.io/kueue/pkg/controller/constants" ) @@ -79,6 +80,11 @@ func (j *JobWrapper) Profile(v string) *JobWrapper { return j.Label(constants.ProfileLabel, v) } +// Mode sets the profile label. +func (j *JobWrapper) Mode(v v1alpha1.ApplicationProfileMode) *JobWrapper { + return j.Label(constants.ModeLabel, string(v)) +} + // LocalQueue sets the localqueue label. func (j *JobWrapper) LocalQueue(v string) *JobWrapper { return j.Label(kueueconstants.QueueLabel, v) diff --git a/cmd/experimental/kjobctl/pkg/testing/wrappers/pod_wrappers.go b/cmd/experimental/kjobctl/pkg/testing/wrappers/pod_wrappers.go index b910e7622d..dad106b777 100644 --- a/cmd/experimental/kjobctl/pkg/testing/wrappers/pod_wrappers.go +++ b/cmd/experimental/kjobctl/pkg/testing/wrappers/pod_wrappers.go @@ -22,6 +22,7 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1" "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/constants" kueueconstants "sigs.k8s.io/kueue/pkg/controller/constants" ) @@ -55,6 +56,11 @@ func (j *PodWrapper) Profile(v string) *PodWrapper { return j.Label(constants.ProfileLabel, v) } +// Mode sets the profile label. +func (j *PodWrapper) Mode(v v1alpha1.ApplicationProfileMode) *PodWrapper { + return j.Label(constants.ModeLabel, string(v)) +} + // LocalQueue sets the localqueue label. func (j *PodWrapper) LocalQueue(v string) *PodWrapper { return j.Label(kueueconstants.QueueLabel, v) diff --git a/cmd/experimental/kjobctl/pkg/testing/wrappers/ray_cluster_wrappers.go b/cmd/experimental/kjobctl/pkg/testing/wrappers/ray_cluster_wrappers.go index 1c76f1d656..48cbcc2e1e 100644 --- a/cmd/experimental/kjobctl/pkg/testing/wrappers/ray_cluster_wrappers.go +++ b/cmd/experimental/kjobctl/pkg/testing/wrappers/ray_cluster_wrappers.go @@ -23,6 +23,7 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1" "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/constants" kueueconstants "sigs.k8s.io/kueue/pkg/controller/constants" ) @@ -65,6 +66,11 @@ func (j *RayClusterWrapper) Profile(v string) *RayClusterWrapper { return j.Label(constants.ProfileLabel, v) } +// Mode sets the profile label. +func (j *RayClusterWrapper) Mode(v v1alpha1.ApplicationProfileMode) *RayClusterWrapper { + return j.Label(constants.ModeLabel, string(v)) +} + // LocalQueue sets the localqueue label. func (j *RayClusterWrapper) LocalQueue(v string) *RayClusterWrapper { return j.Label(kueueconstants.QueueLabel, v) diff --git a/cmd/experimental/kjobctl/pkg/testing/wrappers/ray_job_wrappers.go b/cmd/experimental/kjobctl/pkg/testing/wrappers/ray_job_wrappers.go index 055d06c6fa..52c0448a90 100644 --- a/cmd/experimental/kjobctl/pkg/testing/wrappers/ray_job_wrappers.go +++ b/cmd/experimental/kjobctl/pkg/testing/wrappers/ray_job_wrappers.go @@ -24,6 +24,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1" "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/constants" kueueconstants "sigs.k8s.io/kueue/pkg/controller/constants" ) @@ -66,6 +67,11 @@ func (j *RayJobWrapper) Profile(v string) *RayJobWrapper { return j.Label(constants.ProfileLabel, v) } +// Mode sets the profile label. +func (j *RayJobWrapper) Mode(v v1alpha1.ApplicationProfileMode) *RayJobWrapper { + return j.Label(constants.ModeLabel, string(v)) +} + // LocalQueue sets the localqueue label. func (j *RayJobWrapper) LocalQueue(v string) *RayJobWrapper { return j.Label(kueueconstants.QueueLabel, v) diff --git a/cmd/experimental/kjobctl/test/integration/kjobctl/list_test.go b/cmd/experimental/kjobctl/test/integration/kjobctl/list_test.go index 6925878f0e..cae7e9c880 100644 --- a/cmd/experimental/kjobctl/test/integration/kjobctl/list_test.go +++ b/cmd/experimental/kjobctl/test/integration/kjobctl/list_test.go @@ -31,6 +31,7 @@ import ( "k8s.io/cli-runtime/pkg/genericiooptions" testingclock "k8s.io/utils/clock/testing" + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1" "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/cmd" "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/cmd/list" "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/testing/wrappers" @@ -60,6 +61,7 @@ var _ = ginkgo.Describe("Kjobctl List", ginkgo.Ordered, ginkgo.ContinueOnFailure ginkgo.JustBeforeEach(func() { j1 = wrappers.MakeJob("j1", ns.Name). Profile("profile1"). + Mode(v1alpha1.JobMode). Completions(3). WithContainer(*wrappers.MakeContainer("c1", "sleep").Obj()). RestartPolicy(corev1.RestartPolicyOnFailure). @@ -68,6 +70,7 @@ var _ = ginkgo.Describe("Kjobctl List", ginkgo.Ordered, ginkgo.ContinueOnFailure j2 = wrappers.MakeJob("j2", ns.Name). Profile("profile1"). + Mode(v1alpha1.JobMode). Completions(3). WithContainer(*wrappers.MakeContainer("c1", "sleep").Obj()). RestartPolicy(corev1.RestartPolicyOnFailure). @@ -76,6 +79,7 @@ var _ = ginkgo.Describe("Kjobctl List", ginkgo.Ordered, ginkgo.ContinueOnFailure j3 = wrappers.MakeJob("very-long-job-name", ns.Name). Profile("profile1"). + Mode(v1alpha1.JobMode). Completions(3). WithContainer(*wrappers.MakeContainer("c1", "sleep").Obj()). RestartPolicy(corev1.RestartPolicyOnFailure). @@ -277,4 +281,66 @@ very-long-ray-cluster-name profile1 0 0 ))) }) }) + + ginkgo.When("List Slurm Jobs", func() { + var ( + j1 *batchv1.Job + j2 *batchv1.Job + j3 *batchv1.Job + ) + + ginkgo.JustBeforeEach(func() { + j1 = wrappers.MakeJob("j1", ns.Name). + Profile("profile1"). + Mode(v1alpha1.SlurmMode). + Completions(3). + WithContainer(*wrappers.MakeContainer("c1", "sleep").Obj()). + RestartPolicy(corev1.RestartPolicyOnFailure). + Obj() + gomega.Expect(k8sClient.Create(ctx, j1)).To(gomega.Succeed()) + + j2 = wrappers.MakeJob("j2", ns.Name). + Profile("profile1"). + Mode(v1alpha1.SlurmMode). + Completions(3). + WithContainer(*wrappers.MakeContainer("c1", "sleep").Obj()). + RestartPolicy(corev1.RestartPolicyOnFailure). + Obj() + gomega.Expect(k8sClient.Create(ctx, j2)).To(gomega.Succeed()) + + j3 = wrappers.MakeJob("very-long-job-name", ns.Name). + Profile("profile1"). + Mode(v1alpha1.SlurmMode). + Completions(3). + WithContainer(*wrappers.MakeContainer("c1", "sleep").Obj()). + RestartPolicy(corev1.RestartPolicyOnFailure). + Obj() + gomega.Expect(k8sClient.Create(ctx, j3)).To(gomega.Succeed()) + }) + + // Simple client set that are using on unit tests not allow paging. + ginkgo.It("Should print slurm jobs list with paging", func() { + streams, _, output, errOutput := genericiooptions.NewTestIOStreams() + configFlags := CreateConfigFlagsWithRestConfig(cfg, streams) + executeTime := time.Now() + kjobctl := cmd.NewKjobctlCmd(cmd.KjobctlOptions{ConfigFlags: configFlags, IOStreams: streams, + Clock: testingclock.NewFakeClock(executeTime)}) + + os.Setenv(list.KjobctlListRequestLimitEnvName, "1") + kjobctl.SetArgs([]string{"list", "slurm", "--namespace", ns.Name}) + err := kjobctl.Execute() + + gomega.Expect(err).NotTo(gomega.HaveOccurred(), "%s: %s", err, output) + gomega.Expect(errOutput.String()).Should(gomega.BeEmpty()) + gomega.Expect(output.String()).Should(gomega.Equal(fmt.Sprintf(`NAME PROFILE LOCAL QUEUE COMPLETIONS DURATION AGE +j1 profile1 0/3 %s +j2 profile1 0/3 %s +very-long-job-name profile1 0/3 %s +`, + duration.HumanDuration(executeTime.Sub(j1.CreationTimestamp.Time)), + duration.HumanDuration(executeTime.Sub(j2.CreationTimestamp.Time)), + duration.HumanDuration(executeTime.Sub(j3.CreationTimestamp.Time)), + ))) + }) + }) }) From 4c50cbcda3738e8df3d9d7ca60579d56498a8d54 Mon Sep 17 00:00:00 2001 From: gabesaba <15304068+gabesaba@users.noreply.github.com> Date: Thu, 5 Sep 2024 11:15:49 +0200 Subject: [PATCH 005/155] Update AllocatableResourceGeneration (#2984) --- pkg/cache/cache_test.go | 40 ++-- pkg/cache/clusterqueue.go | 1 - pkg/cache/cohort_snapshot.go | 4 - pkg/cache/resource_node.go | 1 + pkg/cache/snapshot.go | 2 - pkg/cache/snapshot_test.go | 205 ++++++++---------- .../flavorassigner/flavorassigner.go | 13 +- .../flavorassigner/flavorassigner_test.go | 22 -- pkg/scheduler/preemption/preemption_test.go | 1 - pkg/workload/workload.go | 2 - 10 files changed, 111 insertions(+), 180 deletions(-) diff --git a/pkg/cache/cache_test.go b/pkg/cache/cache_test.go index c8f205b7a1..4a6556e903 100644 --- a/pkg/cache/cache_test.go +++ b/pkg/cache/cache_test.go @@ -108,7 +108,7 @@ func TestCacheClusterQueueOperations(t *testing.T) { wantClusterQueues: map[string]*clusterQueue{ "a": { Name: "a", - AllocatableResourceGeneration: 1, + AllocatableResourceGeneration: 2, NamespaceSelector: labels.Nothing(), FlavorFungibility: defaultFlavorFungibility, Status: active, @@ -126,7 +126,7 @@ func TestCacheClusterQueueOperations(t *testing.T) { }, "c": { Name: "c", - AllocatableResourceGeneration: 1, + AllocatableResourceGeneration: 3, NamespaceSelector: labels.Nothing(), FlavorFungibility: defaultFlavorFungibility, Status: active, @@ -144,7 +144,7 @@ func TestCacheClusterQueueOperations(t *testing.T) { }, "e": { Name: "e", - AllocatableResourceGeneration: 1, + AllocatableResourceGeneration: 2, NamespaceSelector: labels.Nothing(), FlavorFungibility: defaultFlavorFungibility, Status: pending, @@ -234,7 +234,7 @@ func TestCacheClusterQueueOperations(t *testing.T) { wantClusterQueues: map[string]*clusterQueue{ "a": { Name: "a", - AllocatableResourceGeneration: 1, + AllocatableResourceGeneration: 2, FlavorFungibility: defaultFlavorFungibility, NamespaceSelector: labels.Nothing(), Status: active, @@ -252,7 +252,7 @@ func TestCacheClusterQueueOperations(t *testing.T) { }, "c": { Name: "c", - AllocatableResourceGeneration: 1, + AllocatableResourceGeneration: 3, NamespaceSelector: labels.Nothing(), FlavorFungibility: defaultFlavorFungibility, Status: active, @@ -270,7 +270,7 @@ func TestCacheClusterQueueOperations(t *testing.T) { }, "e": { Name: "e", - AllocatableResourceGeneration: 1, + AllocatableResourceGeneration: 2, NamespaceSelector: labels.Nothing(), FlavorFungibility: defaultFlavorFungibility, Status: pending, @@ -335,7 +335,7 @@ func TestCacheClusterQueueOperations(t *testing.T) { wantClusterQueues: map[string]*clusterQueue{ "a": { Name: "a", - AllocatableResourceGeneration: 2, + AllocatableResourceGeneration: 4, NamespaceSelector: labels.Nothing(), FlavorFungibility: defaultFlavorFungibility, Status: active, @@ -344,7 +344,7 @@ func TestCacheClusterQueueOperations(t *testing.T) { }, "b": { Name: "b", - AllocatableResourceGeneration: 2, + AllocatableResourceGeneration: 3, NamespaceSelector: labels.Everything(), FlavorFungibility: defaultFlavorFungibility, Status: active, @@ -353,7 +353,7 @@ func TestCacheClusterQueueOperations(t *testing.T) { }, "c": { Name: "c", - AllocatableResourceGeneration: 1, + AllocatableResourceGeneration: 5, NamespaceSelector: labels.Nothing(), FlavorFungibility: defaultFlavorFungibility, Status: active, @@ -371,7 +371,7 @@ func TestCacheClusterQueueOperations(t *testing.T) { }, "e": { Name: "e", - AllocatableResourceGeneration: 2, + AllocatableResourceGeneration: 4, NamespaceSelector: labels.Nothing(), FlavorFungibility: defaultFlavorFungibility, Status: active, @@ -380,7 +380,7 @@ func TestCacheClusterQueueOperations(t *testing.T) { }, "f": { Name: "f", - AllocatableResourceGeneration: 1, + AllocatableResourceGeneration: 3, NamespaceSelector: labels.Nothing(), Status: active, Preemption: defaultPreemption, @@ -509,7 +509,7 @@ func TestCacheClusterQueueOperations(t *testing.T) { wantClusterQueues: map[string]*clusterQueue{ "a": { Name: "a", - AllocatableResourceGeneration: 2, + AllocatableResourceGeneration: 4, FlavorFungibility: defaultFlavorFungibility, Status: active, Preemption: defaultPreemption, @@ -518,7 +518,7 @@ func TestCacheClusterQueueOperations(t *testing.T) { }, "b": { Name: "b", - AllocatableResourceGeneration: 2, + AllocatableResourceGeneration: 3, FlavorFungibility: defaultFlavorFungibility, Status: active, Preemption: defaultPreemption, @@ -527,7 +527,7 @@ func TestCacheClusterQueueOperations(t *testing.T) { }, "c": { Name: "c", - AllocatableResourceGeneration: 2, + AllocatableResourceGeneration: 4, FlavorFungibility: defaultFlavorFungibility, Status: active, Preemption: defaultPreemption, @@ -567,7 +567,7 @@ func TestCacheClusterQueueOperations(t *testing.T) { }, "c": { Name: "c", - AllocatableResourceGeneration: 1, + AllocatableResourceGeneration: 3, NamespaceSelector: labels.Nothing(), FlavorFungibility: defaultFlavorFungibility, Status: active, @@ -576,7 +576,7 @@ func TestCacheClusterQueueOperations(t *testing.T) { }, "e": { Name: "e", - AllocatableResourceGeneration: 1, + AllocatableResourceGeneration: 2, NamespaceSelector: labels.Nothing(), FlavorFungibility: defaultFlavorFungibility, Status: pending, @@ -616,7 +616,7 @@ func TestCacheClusterQueueOperations(t *testing.T) { wantClusterQueues: map[string]*clusterQueue{ "a": { Name: "a", - AllocatableResourceGeneration: 1, + AllocatableResourceGeneration: 2, NamespaceSelector: labels.Nothing(), FlavorFungibility: defaultFlavorFungibility, Status: active, @@ -634,7 +634,7 @@ func TestCacheClusterQueueOperations(t *testing.T) { }, "c": { Name: "c", - AllocatableResourceGeneration: 1, + AllocatableResourceGeneration: 3, NamespaceSelector: labels.Nothing(), FlavorFungibility: defaultFlavorFungibility, Status: active, @@ -652,7 +652,7 @@ func TestCacheClusterQueueOperations(t *testing.T) { }, "e": { Name: "e", - AllocatableResourceGeneration: 1, + AllocatableResourceGeneration: 2, NamespaceSelector: labels.Nothing(), FlavorFungibility: defaultFlavorFungibility, Status: active, @@ -1089,7 +1089,7 @@ func TestCacheClusterQueueOperations(t *testing.T) { NamespaceSelector: labels.Everything(), Status: active, Preemption: defaultPreemption, - AllocatableResourceGeneration: 1, + AllocatableResourceGeneration: 2, FlavorFungibility: defaultFlavorFungibility, FairWeight: oneQuantity, }, diff --git a/pkg/cache/clusterqueue.go b/pkg/cache/clusterqueue.go index 61fa63b436..7424bf825a 100644 --- a/pkg/cache/clusterqueue.go +++ b/pkg/cache/clusterqueue.go @@ -134,7 +134,6 @@ var defaultFlavorFungibility = kueue.FlavorFungibility{WhenCanBorrow: kueue.Borr func (c *clusterQueue) updateClusterQueue(in *kueue.ClusterQueue, resourceFlavors map[kueue.ResourceFlavorReference]*kueue.ResourceFlavor, admissionChecks map[string]AdmissionCheck, oldParent *cohort) error { if c.updateQuotasAndResourceGroups(in.Spec.ResourceGroups) || oldParent != c.Parent() { - c.AllocatableResourceGeneration += 1 if oldParent != nil && oldParent != c.Parent() { updateCohortResourceNode(oldParent) } diff --git a/pkg/cache/cohort_snapshot.go b/pkg/cache/cohort_snapshot.go index 31d09efedb..132006c416 100644 --- a/pkg/cache/cohort_snapshot.go +++ b/pkg/cache/cohort_snapshot.go @@ -25,10 +25,6 @@ type CohortSnapshot struct { Members sets.Set[*ClusterQueueSnapshot] ResourceNode ResourceNode - - // AllocatableResourceGeneration equals to - // the sum of allocatable generation among its members. - AllocatableResourceGeneration int64 } // The methods below implement hierarchicalResourceNode interface. diff --git a/pkg/cache/resource_node.go b/pkg/cache/resource_node.go index a9f893b19f..235523b525 100644 --- a/pkg/cache/resource_node.go +++ b/pkg/cache/resource_node.go @@ -154,6 +154,7 @@ func (r ResourceNode) calculateLendable() map[corev1.ResourceName]int64 { } func updateClusterQueueResourceNode(cq *clusterQueue) { + cq.AllocatableResourceGeneration += 1 cq.resourceNode.SubtreeQuota = make(resources.FlavorResourceQuantities, len(cq.resourceNode.Quotas)) for fr, quota := range cq.resourceNode.Quotas { cq.resourceNode.SubtreeQuota[fr] = quota.Nominal diff --git a/pkg/cache/snapshot.go b/pkg/cache/snapshot.go index 152019297e..c620d5064d 100644 --- a/pkg/cache/snapshot.go +++ b/pkg/cache/snapshot.go @@ -130,13 +130,11 @@ func (c *cohort) snapshotInto(cqs map[string]*ClusterQueueSnapshot) { Members: make(sets.Set[*ClusterQueueSnapshot], len(c.ChildCQs())), ResourceNode: c.resourceNode.Clone(), } - cohortSnap.AllocatableResourceGeneration = 0 for _, cq := range c.ChildCQs() { if cq.Active() { cqSnap := cqs[cq.Name] cqSnap.Cohort = cohortSnap cohortSnap.Members.Insert(cqSnap) - cohortSnap.AllocatableResourceGeneration += cqSnap.AllocatableResourceGeneration } } } diff --git a/pkg/cache/snapshot_test.go b/pkg/cache/snapshot_test.go index 6ff00dae52..b4f7f1a3c7 100644 --- a/pkg/cache/snapshot_test.go +++ b/pkg/cache/snapshot_test.go @@ -203,8 +203,7 @@ func TestSnapshot(t *testing.T) { }, wantSnapshot: func() Snapshot { cohort := &CohortSnapshot{ - Name: "borrowing", - AllocatableResourceGeneration: 2, + Name: "borrowing", ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "demand", Resource: corev1.ResourceCPU}: 10_000, @@ -223,7 +222,7 @@ func TestSnapshot(t *testing.T) { "a": { Name: "a", Cohort: cohort, - AllocatableResourceGeneration: 1, + AllocatableResourceGeneration: 2, ResourceGroups: []ResourceGroup{ { CoveredResources: sets.New(corev1.ResourceCPU), @@ -445,8 +444,7 @@ func TestSnapshot(t *testing.T) { }, wantSnapshot: func() Snapshot { cohort := &CohortSnapshot{ - Name: "lending", - AllocatableResourceGeneration: 2, + Name: "lending", ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "arm", Resource: corev1.ResourceCPU}: 10_000, @@ -462,7 +460,7 @@ func TestSnapshot(t *testing.T) { "a": { Name: "a", Cohort: cohort, - AllocatableResourceGeneration: 1, + AllocatableResourceGeneration: 2, ResourceGroups: []ResourceGroup{ { CoveredResources: sets.New(corev1.ResourceCPU), @@ -597,8 +595,7 @@ func TestSnapshot(t *testing.T) { }, wantSnapshot: func() Snapshot { cohort := &CohortSnapshot{ - Name: "lending", - AllocatableResourceGeneration: 2, + Name: "lending", ResourceNode: ResourceNode{ SubtreeQuota: resources.FlavorResourceQuantities{ {Flavor: "arm", Resource: corev1.ResourceCPU}: 20_000, @@ -615,7 +612,7 @@ func TestSnapshot(t *testing.T) { "a": { Name: "a", Cohort: cohort, - AllocatableResourceGeneration: 1, + AllocatableResourceGeneration: 2, ResourceGroups: []ResourceGroup{ { CoveredResources: sets.New(corev1.ResourceCPU), @@ -730,7 +727,7 @@ func TestSnapshot(t *testing.T) { ClusterQueues: map[string]*ClusterQueueSnapshot{ "cq": { Name: "cq", - AllocatableResourceGeneration: 1, + AllocatableResourceGeneration: 2, ResourceGroups: []ResourceGroup{ { CoveredResources: sets.New(corev1.ResourceCPU), @@ -753,8 +750,7 @@ func TestSnapshot(t *testing.T) { NamespaceSelector: labels.Everything(), Status: active, Cohort: &CohortSnapshot{ - Name: "cohort", - AllocatableResourceGeneration: 1, + Name: "cohort", ResourceNode: ResourceNode{ Quotas: map[resources.FlavorResource]ResourceQuota{ {Flavor: "arm", Resource: corev1.ResourceCPU}: {Nominal: 10_000, BorrowingLimit: nil, LendingLimit: nil}, @@ -900,8 +896,7 @@ func TestSnapshotAddRemoveWorkload(t *testing.T) { remove: []string{"/c1-cpu", "/c1-memory-alpha", "/c1-memory-beta", "/c2-cpu-1", "/c2-cpu-2"}, want: func() Snapshot { cohort := &CohortSnapshot{ - Name: "cohort", - AllocatableResourceGeneration: 2, + Name: "cohort", ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "default", Resource: corev1.ResourceCPU}: 0, @@ -914,13 +909,12 @@ func TestSnapshotAddRemoveWorkload(t *testing.T) { return Snapshot{ ClusterQueues: map[string]*ClusterQueueSnapshot{ "c1": { - Name: "c1", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["c1"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - AllocatableResourceGeneration: 1, + Name: "c1", + Cohort: cohort, + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["c1"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "default", Resource: corev1.ResourceCPU}: 0, @@ -959,8 +953,7 @@ func TestSnapshotAddRemoveWorkload(t *testing.T) { remove: []string{"/c1-cpu"}, want: func() Snapshot { cohort := &CohortSnapshot{ - Name: "cohort", - AllocatableResourceGeneration: 2, + Name: "cohort", ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "default", Resource: corev1.ResourceCPU}: 2_000, @@ -979,10 +972,9 @@ func TestSnapshotAddRemoveWorkload(t *testing.T) { "/c1-memory-alpha": nil, "/c1-memory-beta": nil, }, - AllocatableResourceGeneration: 1, - ResourceGroups: cqCache.hm.ClusterQueues["c1"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, + ResourceGroups: cqCache.hm.ClusterQueues["c1"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "default", Resource: corev1.ResourceCPU}: 0, @@ -1024,8 +1016,7 @@ func TestSnapshotAddRemoveWorkload(t *testing.T) { remove: []string{"/c1-memory-alpha"}, want: func() Snapshot { cohort := &CohortSnapshot{ - Name: "cohort", - AllocatableResourceGeneration: 2, + Name: "cohort", ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "default", Resource: corev1.ResourceCPU}: 3_000, @@ -1044,10 +1035,9 @@ func TestSnapshotAddRemoveWorkload(t *testing.T) { "/c1-memory-alpha": nil, "/c1-memory-beta": nil, }, - AllocatableResourceGeneration: 1, - ResourceGroups: cqCache.hm.ClusterQueues["c1"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, + ResourceGroups: cqCache.hm.ClusterQueues["c1"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "default", Resource: corev1.ResourceCPU}: 1_000, @@ -1068,10 +1058,9 @@ func TestSnapshotAddRemoveWorkload(t *testing.T) { "/c2-cpu-1": nil, "/c2-cpu-2": nil, }, - AllocatableResourceGeneration: 1, - ResourceGroups: cqCache.hm.ClusterQueues["c2"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, + ResourceGroups: cqCache.hm.ClusterQueues["c2"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "default", Resource: corev1.ResourceCPU}: 2_000, @@ -1087,7 +1076,7 @@ func TestSnapshotAddRemoveWorkload(t *testing.T) { }, } cmpOpts := append(snapCmpOpts, - cmpopts.IgnoreFields(ClusterQueueSnapshot{}, "NamespaceSelector", "Preemption", "Status"), + cmpopts.IgnoreFields(ClusterQueueSnapshot{}, "NamespaceSelector", "Preemption", "Status", "AllocatableResourceGeneration"), cmpopts.IgnoreFields(ResourceNode{}, "Quotas"), cmpopts.IgnoreFields(Snapshot{}, "ResourceFlavors"), cmpopts.IgnoreTypes(&workload.Info{})) @@ -1186,8 +1175,7 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { remove: []string{"/lend-a-1", "/lend-a-2", "/lend-a-3", "/lend-b-1"}, want: func() Snapshot { cohort := &CohortSnapshot{ - Name: "lend", - AllocatableResourceGeneration: 2, + Name: "lend", ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "default", Resource: corev1.ResourceCPU}: 0, @@ -1198,13 +1186,12 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { return Snapshot{ ClusterQueues: map[string]*ClusterQueueSnapshot{ "lend-a": { - Name: "lend-a", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - AllocatableResourceGeneration: 1, + Name: "lend-a", + Cohort: cohort, + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "default", Resource: corev1.ResourceCPU}: 0, @@ -1215,13 +1202,12 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { }, }, "lend-b": { - Name: "lend-b", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["lend-b"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - AllocatableResourceGeneration: 1, + Name: "lend-b", + Cohort: cohort, + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["lend-b"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "default", Resource: corev1.ResourceCPU}: 0, @@ -1239,8 +1225,7 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { remove: []string{"/lend-a-2"}, want: func() Snapshot { cohort := &CohortSnapshot{ - Name: "lend", - AllocatableResourceGeneration: 2, + Name: "lend", ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "default", Resource: corev1.ResourceCPU}: 1_000, @@ -1251,13 +1236,12 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { return Snapshot{ ClusterQueues: map[string]*ClusterQueueSnapshot{ "lend-a": { - Name: "lend-a", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - AllocatableResourceGeneration: 1, + Name: "lend-a", + Cohort: cohort, + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "default", Resource: corev1.ResourceCPU}: 7_000, @@ -1292,8 +1276,7 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { remove: []string{"/lend-a-1", "/lend-a-2"}, want: func() Snapshot { cohort := &CohortSnapshot{ - Name: "lend", - AllocatableResourceGeneration: 2, + Name: "lend", ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "default", Resource: corev1.ResourceCPU}: 0, @@ -1304,13 +1287,12 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { return Snapshot{ ClusterQueues: map[string]*ClusterQueueSnapshot{ "lend-a": { - Name: "lend-a", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - AllocatableResourceGeneration: 1, + Name: "lend-a", + Cohort: cohort, + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "default", Resource: corev1.ResourceCPU}: 6_000, @@ -1345,8 +1327,7 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { remove: []string{"/lend-a-2", "/lend-a-3"}, want: func() Snapshot { cohort := &CohortSnapshot{ - Name: "lend", - AllocatableResourceGeneration: 2, + Name: "lend", ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "default", Resource: corev1.ResourceCPU}: 0, @@ -1357,13 +1338,12 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { return Snapshot{ ClusterQueues: map[string]*ClusterQueueSnapshot{ "lend-a": { - Name: "lend-a", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - AllocatableResourceGeneration: 1, + Name: "lend-a", + Cohort: cohort, + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "default", Resource: corev1.ResourceCPU}: 1_000, @@ -1399,8 +1379,7 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { add: []string{"/lend-a-1"}, want: func() Snapshot { cohort := &CohortSnapshot{ - Name: "lend", - AllocatableResourceGeneration: 2, + Name: "lend", ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "default", Resource: corev1.ResourceCPU}: 0, @@ -1411,13 +1390,12 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { return Snapshot{ ClusterQueues: map[string]*ClusterQueueSnapshot{ "lend-a": { - Name: "lend-a", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - AllocatableResourceGeneration: 1, + Name: "lend-a", + Cohort: cohort, + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "default", Resource: corev1.ResourceCPU}: 1_000, @@ -1453,8 +1431,7 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { add: []string{"/lend-a-3"}, want: func() Snapshot { cohort := &CohortSnapshot{ - Name: "lend", - AllocatableResourceGeneration: 2, + Name: "lend", ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "default", Resource: corev1.ResourceCPU}: 0, @@ -1465,13 +1442,12 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { return Snapshot{ ClusterQueues: map[string]*ClusterQueueSnapshot{ "lend-a": { - Name: "lend-a", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - AllocatableResourceGeneration: 1, + Name: "lend-a", + Cohort: cohort, + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "default", Resource: corev1.ResourceCPU}: 6_000, @@ -1482,13 +1458,12 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { }, }, "lend-b": { - Name: "lend-b", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["lend-b"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - AllocatableResourceGeneration: 1, + Name: "lend-b", + Cohort: cohort, + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["lend-b"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "default", Resource: corev1.ResourceCPU}: 0, @@ -1507,8 +1482,7 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { add: []string{"/lend-a-2"}, want: func() Snapshot { cohort := &CohortSnapshot{ - Name: "lend", - AllocatableResourceGeneration: 2, + Name: "lend", ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "default", Resource: corev1.ResourceCPU}: 3_000, @@ -1519,13 +1493,12 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { return Snapshot{ ClusterQueues: map[string]*ClusterQueueSnapshot{ "lend-a": { - Name: "lend-a", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - AllocatableResourceGeneration: 1, + Name: "lend-a", + Cohort: cohort, + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, ResourceNode: ResourceNode{ Usage: resources.FlavorResourceQuantities{ {Flavor: "default", Resource: corev1.ResourceCPU}: 9_000, @@ -1558,7 +1531,7 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { }, } cmpOpts := append(snapCmpOpts, - cmpopts.IgnoreFields(ClusterQueueSnapshot{}, "NamespaceSelector", "Preemption", "Status"), + cmpopts.IgnoreFields(ClusterQueueSnapshot{}, "NamespaceSelector", "Preemption", "Status", "AllocatableResourceGeneration"), cmpopts.IgnoreFields(ResourceNode{}, "Quotas"), cmpopts.IgnoreFields(Snapshot{}, "ResourceFlavors"), cmpopts.IgnoreTypes(&workload.Info{})) diff --git a/pkg/scheduler/flavorassigner/flavorassigner.go b/pkg/scheduler/flavorassigner/flavorassigner.go index b5e606522b..bac68990b5 100644 --- a/pkg/scheduler/flavorassigner/flavorassigner.go +++ b/pkg/scheduler/flavorassigner/flavorassigner.go @@ -287,8 +287,7 @@ func New(wl *workload.Info, cq *cache.ClusterQueueSnapshot, resourceFlavors map[ } func lastAssignmentOutdated(wl *workload.Info, cq *cache.ClusterQueueSnapshot) bool { - return cq.AllocatableResourceGeneration > wl.LastAssignment.ClusterQueueGeneration || - (cq.Cohort != nil && cq.Cohort.AllocatableResourceGeneration > wl.LastAssignment.CohortGeneration) + return cq.AllocatableResourceGeneration > wl.LastAssignment.ClusterQueueGeneration } // Assign assigns a flavor to each of the resources requested in each pod set. @@ -302,12 +301,6 @@ func (a *FlavorAssigner) Assign(log logr.Logger, counts []int32) Assignment { "cq.AllocatableResourceGeneration", a.cq.AllocatableResourceGeneration, "wl.LastAssignment.ClusterQueueGeneration", a.wl.LastAssignment.ClusterQueueGeneration, } - if a.cq.Cohort != nil { - keysValues = append(keysValues, - "cq.Cohort.AllocatableResourceGeneration", a.cq.Cohort.AllocatableResourceGeneration, - "wl.LastAssignment.CohortGeneration", a.wl.LastAssignment.CohortGeneration, - ) - } logV.Info("Clearing Workload's last assignment because it was outdated", keysValues...) } a.wl.LastAssignment = nil @@ -330,13 +323,9 @@ func (a *FlavorAssigner) assignFlavors(log logr.Logger, requests []workload.PodS Usage: make(resources.FlavorResourceQuantities), LastState: workload.AssignmentClusterQueueState{ LastTriedFlavorIdx: make([]map[corev1.ResourceName]int, 0, len(requests)), - CohortGeneration: 0, ClusterQueueGeneration: a.cq.AllocatableResourceGeneration, }, } - if a.cq.Cohort != nil { - assignment.LastState.CohortGeneration = a.cq.Cohort.AllocatableResourceGeneration - } for i, podSet := range requests { if a.cq.RGByResource(corev1.ResourcePods) != nil { diff --git a/pkg/scheduler/flavorassigner/flavorassigner_test.go b/pkg/scheduler/flavorassigner/flavorassigner_test.go index 8e9bb123e8..b23031b8fd 100644 --- a/pkg/scheduler/flavorassigner/flavorassigner_test.go +++ b/pkg/scheduler/flavorassigner/flavorassigner_test.go @@ -2275,37 +2275,15 @@ func TestLastAssignmentOutdated(t *testing.T) { }, want: true, }, - { - name: "Cohort allocatableResourceIncreasedGen increased", - args: args{ - wl: &workload.Info{ - LastAssignment: &workload.AssignmentClusterQueueState{ - ClusterQueueGeneration: 0, - CohortGeneration: 0, - }, - }, - cq: &cache.ClusterQueueSnapshot{ - Cohort: &cache.CohortSnapshot{ - AllocatableResourceGeneration: 1, - }, - AllocatableResourceGeneration: 0, - }, - }, - want: true, - }, { name: "AllocatableResourceGeneration not increased", args: args{ wl: &workload.Info{ LastAssignment: &workload.AssignmentClusterQueueState{ ClusterQueueGeneration: 0, - CohortGeneration: 0, }, }, cq: &cache.ClusterQueueSnapshot{ - Cohort: &cache.CohortSnapshot{ - AllocatableResourceGeneration: 0, - }, AllocatableResourceGeneration: 0, }, }, diff --git a/pkg/scheduler/preemption/preemption_test.go b/pkg/scheduler/preemption/preemption_test.go index 7a4ba86964..ee5020205d 100644 --- a/pkg/scheduler/preemption/preemption_test.go +++ b/pkg/scheduler/preemption/preemption_test.go @@ -50,7 +50,6 @@ import ( var snapCmpOpts = []cmp.Option{ cmpopts.EquateEmpty(), cmpopts.IgnoreUnexported(cache.ClusterQueueSnapshot{}), - cmpopts.IgnoreFields(cache.CohortSnapshot{}, "AllocatableResourceGeneration"), cmpopts.IgnoreFields(cache.ClusterQueueSnapshot{}, "AllocatableResourceGeneration"), cmp.Transformer("Cohort.Members", func(s sets.Set[*cache.ClusterQueueSnapshot]) sets.Set[string] { result := make(sets.Set[string], len(s)) diff --git a/pkg/workload/workload.go b/pkg/workload/workload.go index 3b40a6589d..c152bf0e1f 100644 --- a/pkg/workload/workload.go +++ b/pkg/workload/workload.go @@ -78,7 +78,6 @@ func Status(w *kueue.Workload) string { type AssignmentClusterQueueState struct { LastTriedFlavorIdx []map[corev1.ResourceName]int - CohortGeneration int64 ClusterQueueGeneration int64 } @@ -100,7 +99,6 @@ func WithExcludedResourcePrefixes(n []string) InfoOption { func (s *AssignmentClusterQueueState) Clone() *AssignmentClusterQueueState { c := AssignmentClusterQueueState{ LastTriedFlavorIdx: make([]map[corev1.ResourceName]int, len(s.LastTriedFlavorIdx)), - CohortGeneration: s.CohortGeneration, ClusterQueueGeneration: s.ClusterQueueGeneration, } for ps, flavorIdx := range s.LastTriedFlavorIdx { From d40b300b26f2cef864531bc85680b328ea92590d Mon Sep 17 00:00:00 2001 From: gabesaba <15304068+gabesaba@users.noreply.github.com> Date: Thu, 5 Sep 2024 12:15:40 +0200 Subject: [PATCH 006/155] Update Snapshotting logic to use hierarchy.Manager (#2989) --- pkg/cache/clusterqueue_snapshot.go | 15 +- pkg/cache/cohort_snapshot.go | 18 +- pkg/cache/snapshot.go | 52 +- pkg/cache/snapshot_test.go | 1380 +++++++++-------- .../flavorassigner/flavorassigner.go | 2 +- .../flavorassigner/flavorassigner_test.go | 7 +- pkg/scheduler/preemption/preemption.go | 6 +- pkg/scheduler/preemption/preemption_test.go | 5 +- pkg/scheduler/scheduler.go | 18 +- 9 files changed, 777 insertions(+), 726 deletions(-) diff --git a/pkg/cache/clusterqueue_snapshot.go b/pkg/cache/clusterqueue_snapshot.go index b081cee98b..4f1e131399 100644 --- a/pkg/cache/clusterqueue_snapshot.go +++ b/pkg/cache/clusterqueue_snapshot.go @@ -23,6 +23,7 @@ import ( "k8s.io/apimachinery/pkg/util/sets" kueue "sigs.k8s.io/kueue/apis/kueue/v1beta1" + "sigs.k8s.io/kueue/pkg/hierarchy" "sigs.k8s.io/kueue/pkg/metrics" "sigs.k8s.io/kueue/pkg/resources" "sigs.k8s.io/kueue/pkg/workload" @@ -30,7 +31,6 @@ import ( type ClusterQueueSnapshot struct { Name string - Cohort *CohortSnapshot ResourceGroups []ResourceGroup Workloads map[string]*workload.Info WorkloadsNotReady sets.Set[string] @@ -48,6 +48,7 @@ type ClusterQueueSnapshot struct { AllocatableResourceGeneration int64 ResourceNode ResourceNode + hierarchy.ClusterQueue[*CohortSnapshot] } // RGByResource returns the ResourceGroup which contains capacity @@ -108,17 +109,9 @@ func (c *ClusterQueueSnapshot) PotentialAvailable(fr resources.FlavorResource) i return potentialAvailable(c, fr) } -func (c *ClusterQueueSnapshot) Parent() *CohortSnapshot { - return c.Cohort -} - // The methods below implement several interfaces. See // dominantResourceShareNode, resourceGroupNode, and netQuotaNode. -func (c *ClusterQueueSnapshot) HasParent() bool { - return c.Cohort != nil -} - func (c *ClusterQueueSnapshot) fairWeight() *resource.Quantity { return &c.FairWeight } @@ -135,6 +128,10 @@ func (c *ClusterQueueSnapshot) parentResources() ResourceNode { return c.Parent().ResourceNode } +func (c *ClusterQueueSnapshot) GetName() string { + return c.Name +} + // The methods below implement hierarchicalResourceNode interface. func (c *ClusterQueueSnapshot) getResourceNode() ResourceNode { diff --git a/pkg/cache/cohort_snapshot.go b/pkg/cache/cohort_snapshot.go index 132006c416..43cdfadbd2 100644 --- a/pkg/cache/cohort_snapshot.go +++ b/pkg/cache/cohort_snapshot.go @@ -16,27 +16,25 @@ limitations under the License. package cache -import ( - "k8s.io/apimachinery/pkg/util/sets" -) +import "sigs.k8s.io/kueue/pkg/hierarchy" type CohortSnapshot struct { - Name string - Members sets.Set[*ClusterQueueSnapshot] + Name string ResourceNode ResourceNode + hierarchy.Cohort[*ClusterQueueSnapshot, *CohortSnapshot] } -// The methods below implement hierarchicalResourceNode interface. - -func (c *CohortSnapshot) HasParent() bool { - return false +func (c *CohortSnapshot) GetName() string { + return c.Name } +// The methods below implement hierarchicalResourceNode interface. + func (c *CohortSnapshot) getResourceNode() ResourceNode { return c.ResourceNode } func (c *CohortSnapshot) parentHRN() hierarchicalResourceNode { - return nil + return c.Parent() } diff --git a/pkg/cache/snapshot.go b/pkg/cache/snapshot.go index c620d5064d..43cf225546 100644 --- a/pkg/cache/snapshot.go +++ b/pkg/cache/snapshot.go @@ -24,12 +24,13 @@ import ( "k8s.io/klog/v2" kueue "sigs.k8s.io/kueue/apis/kueue/v1beta1" + "sigs.k8s.io/kueue/pkg/hierarchy" utilmaps "sigs.k8s.io/kueue/pkg/util/maps" "sigs.k8s.io/kueue/pkg/workload" ) type Snapshot struct { - ClusterQueues map[string]*ClusterQueueSnapshot + hierarchy.Manager[*ClusterQueueSnapshot, *CohortSnapshot] ResourceFlavors map[kueue.ResourceFlavorReference]*kueue.ResourceFlavor InactiveClusterQueueSets sets.Set[string] } @@ -51,12 +52,10 @@ func (s *Snapshot) AddWorkload(wl *workload.Info) { } func (s *Snapshot) Log(log logr.Logger) { - cohorts := make(map[string]*CohortSnapshot) for name, cq := range s.ClusterQueues { cohortName := "" - if cq.Cohort != nil { - cohortName = cq.Cohort.Name - cohorts[cohortName] = cq.Cohort + if cq.HasParent() { + cohortName = cq.Parent().Name } log.Info("Found ClusterQueue", @@ -67,7 +66,7 @@ func (s *Snapshot) Log(log logr.Logger) { "workloads", utilmaps.Keys(cq.Workloads), ) } - for name, cohort := range cohorts { + for name, cohort := range s.Cohorts { log.Info("Found cohort", "cohort", name, "resources", cohort.ResourceNode.SubtreeQuota, @@ -81,30 +80,33 @@ func (c *Cache) Snapshot() Snapshot { defer c.RUnlock() snap := Snapshot{ - ClusterQueues: make(map[string]*ClusterQueueSnapshot, len(c.hm.ClusterQueues)), + Manager: hierarchy.NewManager(newCohortSnapshot), ResourceFlavors: make(map[kueue.ResourceFlavorReference]*kueue.ResourceFlavor, len(c.resourceFlavors)), InactiveClusterQueueSets: sets.New[string](), } + for _, cohort := range c.hm.Cohorts { + snap.AddCohort(snapshotCohort(cohort)) + } for _, cq := range c.hm.ClusterQueues { if !cq.Active() { snap.InactiveClusterQueueSets.Insert(cq.Name) continue } - snap.ClusterQueues[cq.Name] = cq.snapshot() + snap.AddClusterQueue(snapshotClusterQueue(cq)) + if cq.HasParent() { + snap.UpdateClusterQueueEdge(cq.Name, cq.Parent().Name) + } } for name, rf := range c.resourceFlavors { // Shallow copy is enough snap.ResourceFlavors[name] = rf } - for _, cohort := range c.hm.Cohorts { - cohort.snapshotInto(snap.ClusterQueues) - } return snap } -// snapshot creates a copy of ClusterQueue that includes references to immutable -// objects and deep copies of changing ones. A reference to the cohort is not included. -func (c *clusterQueue) snapshot() *ClusterQueueSnapshot { +// snapshotClusterQueue creates a copy of ClusterQueue that includes +// references to immutable objects and deep copies of changing ones. +func snapshotClusterQueue(c *clusterQueue) *ClusterQueueSnapshot { cc := &ClusterQueueSnapshot{ Name: c.Name, ResourceGroups: make([]ResourceGroup, len(c.ResourceGroups)), @@ -124,17 +126,15 @@ func (c *clusterQueue) snapshot() *ClusterQueueSnapshot { return cc } -func (c *cohort) snapshotInto(cqs map[string]*ClusterQueueSnapshot) { - cohortSnap := &CohortSnapshot{ - Name: c.Name, - Members: make(sets.Set[*ClusterQueueSnapshot], len(c.ChildCQs())), - ResourceNode: c.resourceNode.Clone(), - } - for _, cq := range c.ChildCQs() { - if cq.Active() { - cqSnap := cqs[cq.Name] - cqSnap.Cohort = cohortSnap - cohortSnap.Members.Insert(cqSnap) - } +func snapshotCohort(c *cohort) *CohortSnapshot { + snapshot := newCohortSnapshot(c.Name) + snapshot.ResourceNode = c.resourceNode.Clone() + return snapshot +} + +func newCohortSnapshot(name string) *CohortSnapshot { + return &CohortSnapshot{ + Name: name, + Cohort: hierarchy.NewCohort[*ClusterQueueSnapshot, *CohortSnapshot](), } } diff --git a/pkg/cache/snapshot_test.go b/pkg/cache/snapshot_test.go index b4f7f1a3c7..9c2d5f2cfa 100644 --- a/pkg/cache/snapshot_test.go +++ b/pkg/cache/snapshot_test.go @@ -32,6 +32,7 @@ import ( kueuealpha "sigs.k8s.io/kueue/apis/kueue/v1alpha1" kueue "sigs.k8s.io/kueue/apis/kueue/v1beta1" "sigs.k8s.io/kueue/pkg/features" + "sigs.k8s.io/kueue/pkg/hierarchy" "sigs.k8s.io/kueue/pkg/resources" utiltesting "sigs.k8s.io/kueue/pkg/util/testing" "sigs.k8s.io/kueue/pkg/workload" @@ -39,7 +40,9 @@ import ( var snapCmpOpts = []cmp.Option{ cmpopts.EquateEmpty(), - cmpopts.IgnoreFields(CohortSnapshot{}, "Members"), // avoid recursion. + cmpopts.IgnoreUnexported(hierarchy.Cohort[*ClusterQueueSnapshot, *CohortSnapshot]{}), + cmpopts.IgnoreUnexported(hierarchy.ClusterQueue[*CohortSnapshot]{}), + cmpopts.IgnoreUnexported(hierarchy.Manager[*ClusterQueueSnapshot, *CohortSnapshot]{}), cmpopts.IgnoreFields(metav1.Condition{}, "LastTransitionTime"), } @@ -65,34 +68,36 @@ func TestSnapshot(t *testing.T) { ReserveQuota(&kueue.Admission{ClusterQueue: "b"}).Obj(), }, wantSnapshot: Snapshot{ - ClusterQueues: map[string]*ClusterQueueSnapshot{ - "a": { - Name: "a", - NamespaceSelector: labels.Everything(), - Status: active, - FlavorFungibility: defaultFlavorFungibility, - AllocatableResourceGeneration: 1, - Workloads: map[string]*workload.Info{ - "/alpha": workload.NewInfo( - utiltesting.MakeWorkload("alpha", ""). - ReserveQuota(&kueue.Admission{ClusterQueue: "a"}).Obj()), + Manager: hierarchy.Manager[*ClusterQueueSnapshot, *CohortSnapshot]{ + ClusterQueues: map[string]*ClusterQueueSnapshot{ + "a": { + Name: "a", + NamespaceSelector: labels.Everything(), + Status: active, + FlavorFungibility: defaultFlavorFungibility, + AllocatableResourceGeneration: 1, + Workloads: map[string]*workload.Info{ + "/alpha": workload.NewInfo( + utiltesting.MakeWorkload("alpha", ""). + ReserveQuota(&kueue.Admission{ClusterQueue: "a"}).Obj()), + }, + Preemption: defaultPreemption, + FairWeight: oneQuantity, }, - Preemption: defaultPreemption, - FairWeight: oneQuantity, - }, - "b": { - Name: "b", - NamespaceSelector: labels.Everything(), - Status: active, - FlavorFungibility: defaultFlavorFungibility, - AllocatableResourceGeneration: 1, - Workloads: map[string]*workload.Info{ - "/beta": workload.NewInfo( - utiltesting.MakeWorkload("beta", ""). - ReserveQuota(&kueue.Admission{ClusterQueue: "b"}).Obj()), + "b": { + Name: "b", + NamespaceSelector: labels.Everything(), + Status: active, + FlavorFungibility: defaultFlavorFungibility, + AllocatableResourceGeneration: 1, + Workloads: map[string]*workload.Info{ + "/beta": workload.NewInfo( + utiltesting.MakeWorkload("beta", ""). + ReserveQuota(&kueue.Admission{ClusterQueue: "b"}).Obj()), + }, + Preemption: defaultPreemption, + FairWeight: oneQuantity, }, - Preemption: defaultPreemption, - FairWeight: oneQuantity, }, }, }, @@ -121,7 +126,9 @@ func TestSnapshot(t *testing.T) { utiltesting.MakeResourceFlavor("default").Obj(), }, wantSnapshot: Snapshot{ - ClusterQueues: map[string]*ClusterQueueSnapshot{}, + Manager: hierarchy.Manager[*ClusterQueueSnapshot, *CohortSnapshot]{ + ClusterQueues: map[string]*ClusterQueueSnapshot{}, + }, ResourceFlavors: map[kueue.ResourceFlavorReference]*kueue.ResourceFlavor{ "demand": utiltesting.MakeResourceFlavor("demand"). NodeLabel("a", "b"). @@ -218,130 +225,133 @@ func TestSnapshot(t *testing.T) { }, } return Snapshot{ - ClusterQueues: map[string]*ClusterQueueSnapshot{ - "a": { - Name: "a", - Cohort: cohort, - AllocatableResourceGeneration: 2, - ResourceGroups: []ResourceGroup{ - { - CoveredResources: sets.New(corev1.ResourceCPU), - Flavors: []kueue.ResourceFlavorReference{"demand", "spot"}, - LabelKeys: sets.New("instance"), - }, - }, - ResourceNode: ResourceNode{ - Quotas: map[resources.FlavorResource]ResourceQuota{ - {Flavor: "demand", Resource: corev1.ResourceCPU}: {Nominal: 100_000}, - {Flavor: "spot", Resource: corev1.ResourceCPU}: {Nominal: 200_000}, - }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "demand", Resource: "cpu"}: 100_000, - {Flavor: "spot", Resource: "cpu"}: 200_000, - }, - Usage: resources.FlavorResourceQuantities{ - {Flavor: "demand", Resource: corev1.ResourceCPU}: 10_000, - }, - }, - FlavorFungibility: defaultFlavorFungibility, - Workloads: map[string]*workload.Info{ - "/alpha": workload.NewInfo(utiltesting.MakeWorkload("alpha", ""). - PodSets(*utiltesting.MakePodSet("main", 5). - Request(corev1.ResourceCPU, "2").Obj()). - ReserveQuota(utiltesting.MakeAdmission("a", "main"). - Assignment(corev1.ResourceCPU, "demand", "10000m"). - AssignmentPodCount(5). - Obj()). - Obj()), - }, - Preemption: defaultPreemption, - FairWeight: oneQuantity, - NamespaceSelector: labels.Everything(), - Status: active, + Manager: hierarchy.Manager[*ClusterQueueSnapshot, *CohortSnapshot]{ + Cohorts: map[string]*CohortSnapshot{ + "borrowing": cohort, }, - "b": { - Name: "b", - Cohort: cohort, - AllocatableResourceGeneration: 1, - ResourceGroups: []ResourceGroup{ - { - CoveredResources: sets.New(corev1.ResourceCPU), - Flavors: []kueue.ResourceFlavorReference{"spot"}, - LabelKeys: sets.New("instance"), - }, - { - CoveredResources: sets.New[corev1.ResourceName]("example.com/gpu"), - Flavors: []kueue.ResourceFlavorReference{"default"}, - }, + ClusterQueues: map[string]*ClusterQueueSnapshot{ + "a": { + Name: "a", + AllocatableResourceGeneration: 2, + ResourceGroups: []ResourceGroup{ + { + CoveredResources: sets.New(corev1.ResourceCPU), + Flavors: []kueue.ResourceFlavorReference{"demand", "spot"}, + LabelKeys: sets.New("instance"), + }, + }, + ResourceNode: ResourceNode{ + Quotas: map[resources.FlavorResource]ResourceQuota{ + {Flavor: "demand", Resource: corev1.ResourceCPU}: {Nominal: 100_000}, + {Flavor: "spot", Resource: corev1.ResourceCPU}: {Nominal: 200_000}, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "demand", Resource: "cpu"}: 100_000, + {Flavor: "spot", Resource: "cpu"}: 200_000, + }, + Usage: resources.FlavorResourceQuantities{ + {Flavor: "demand", Resource: corev1.ResourceCPU}: 10_000, + }, + }, + FlavorFungibility: defaultFlavorFungibility, + Workloads: map[string]*workload.Info{ + "/alpha": workload.NewInfo(utiltesting.MakeWorkload("alpha", ""). + PodSets(*utiltesting.MakePodSet("main", 5). + Request(corev1.ResourceCPU, "2").Obj()). + ReserveQuota(utiltesting.MakeAdmission("a", "main"). + Assignment(corev1.ResourceCPU, "demand", "10000m"). + AssignmentPodCount(5). + Obj()). + Obj()), + }, + Preemption: defaultPreemption, + FairWeight: oneQuantity, + NamespaceSelector: labels.Everything(), + Status: active, }, - ResourceNode: ResourceNode{ - Quotas: map[resources.FlavorResource]ResourceQuota{ - {Flavor: "spot", Resource: corev1.ResourceCPU}: {Nominal: 100_000}, - {Flavor: "default", Resource: "example.com/gpu"}: {Nominal: 50}, - }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "spot", Resource: "cpu"}: 100_000, - {Flavor: "default", Resource: "example.com/gpu"}: 50, - }, - Usage: resources.FlavorResourceQuantities{ - {Flavor: "spot", Resource: corev1.ResourceCPU}: 10_000, - {Flavor: "default", Resource: "example.com/gpu"}: 15, - }, + "b": { + Name: "b", + AllocatableResourceGeneration: 1, + ResourceGroups: []ResourceGroup{ + { + CoveredResources: sets.New(corev1.ResourceCPU), + Flavors: []kueue.ResourceFlavorReference{"spot"}, + LabelKeys: sets.New("instance"), + }, + { + CoveredResources: sets.New[corev1.ResourceName]("example.com/gpu"), + Flavors: []kueue.ResourceFlavorReference{"default"}, + }, + }, + ResourceNode: ResourceNode{ + Quotas: map[resources.FlavorResource]ResourceQuota{ + {Flavor: "spot", Resource: corev1.ResourceCPU}: {Nominal: 100_000}, + {Flavor: "default", Resource: "example.com/gpu"}: {Nominal: 50}, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "spot", Resource: "cpu"}: 100_000, + {Flavor: "default", Resource: "example.com/gpu"}: 50, + }, + Usage: resources.FlavorResourceQuantities{ + {Flavor: "spot", Resource: corev1.ResourceCPU}: 10_000, + {Flavor: "default", Resource: "example.com/gpu"}: 15, + }, + }, + FlavorFungibility: defaultFlavorFungibility, + Workloads: map[string]*workload.Info{ + "/beta": workload.NewInfo(utiltesting.MakeWorkload("beta", ""). + PodSets(*utiltesting.MakePodSet("main", 5). + Request(corev1.ResourceCPU, "1"). + Request("example.com/gpu", "2"). + Obj()). + ReserveQuota(utiltesting.MakeAdmission("b", "main"). + Assignment(corev1.ResourceCPU, "spot", "5000m"). + Assignment("example.com/gpu", "default", "10"). + AssignmentPodCount(5). + Obj()). + Obj()), + "/gamma": workload.NewInfo(utiltesting.MakeWorkload("gamma", ""). + PodSets(*utiltesting.MakePodSet("main", 5). + Request(corev1.ResourceCPU, "1"). + Request("example.com/gpu", "1"). + Obj(), + ). + ReserveQuota(utiltesting.MakeAdmission("b", "main"). + Assignment(corev1.ResourceCPU, "spot", "5000m"). + Assignment("example.com/gpu", "default", "5"). + AssignmentPodCount(5). + Obj()). + Obj()), + }, + Preemption: defaultPreemption, + FairWeight: oneQuantity, + NamespaceSelector: labels.Everything(), + Status: active, }, - FlavorFungibility: defaultFlavorFungibility, - Workloads: map[string]*workload.Info{ - "/beta": workload.NewInfo(utiltesting.MakeWorkload("beta", ""). - PodSets(*utiltesting.MakePodSet("main", 5). - Request(corev1.ResourceCPU, "1"). - Request("example.com/gpu", "2"). - Obj()). - ReserveQuota(utiltesting.MakeAdmission("b", "main"). - Assignment(corev1.ResourceCPU, "spot", "5000m"). - Assignment("example.com/gpu", "default", "10"). - AssignmentPodCount(5). - Obj()). - Obj()), - "/gamma": workload.NewInfo(utiltesting.MakeWorkload("gamma", ""). - PodSets(*utiltesting.MakePodSet("main", 5). - Request(corev1.ResourceCPU, "1"). - Request("example.com/gpu", "1"). - Obj(), - ). - ReserveQuota(utiltesting.MakeAdmission("b", "main"). - Assignment(corev1.ResourceCPU, "spot", "5000m"). - Assignment("example.com/gpu", "default", "5"). - AssignmentPodCount(5). - Obj()). - Obj()), + "c": { + Name: "c", + AllocatableResourceGeneration: 1, + ResourceGroups: []ResourceGroup{ + { + CoveredResources: sets.New(corev1.ResourceCPU), + Flavors: []kueue.ResourceFlavorReference{"default"}, + }, + }, + ResourceNode: ResourceNode{ + Quotas: map[resources.FlavorResource]ResourceQuota{ + {Flavor: "default", Resource: corev1.ResourceCPU}: {Nominal: 100_000}, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: "cpu"}: 100_000, + }, + Usage: resources.FlavorResourceQuantities{}, + }, + FlavorFungibility: defaultFlavorFungibility, + Preemption: defaultPreemption, + FairWeight: oneQuantity, + NamespaceSelector: labels.Everything(), + Status: active, }, - Preemption: defaultPreemption, - FairWeight: oneQuantity, - NamespaceSelector: labels.Everything(), - Status: active, - }, - "c": { - Name: "c", - AllocatableResourceGeneration: 1, - ResourceGroups: []ResourceGroup{ - { - CoveredResources: sets.New(corev1.ResourceCPU), - Flavors: []kueue.ResourceFlavorReference{"default"}, - }, - }, - ResourceNode: ResourceNode{ - Quotas: map[resources.FlavorResource]ResourceQuota{ - {Flavor: "default", Resource: corev1.ResourceCPU}: {Nominal: 100_000}, - }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: "cpu"}: 100_000, - }, - Usage: resources.FlavorResourceQuantities{}, - }, - FlavorFungibility: defaultFlavorFungibility, - Preemption: defaultPreemption, - FairWeight: oneQuantity, - NamespaceSelector: labels.Everything(), - Status: active, }, }, ResourceFlavors: map[kueue.ResourceFlavorReference]*kueue.ResourceFlavor{ @@ -361,19 +371,21 @@ func TestSnapshot(t *testing.T) { }).Obj(), }, wantSnapshot: Snapshot{ - ClusterQueues: map[string]*ClusterQueueSnapshot{ - "with-preemption": { - Name: "with-preemption", - NamespaceSelector: labels.Everything(), - AllocatableResourceGeneration: 1, - Status: active, - Workloads: map[string]*workload.Info{}, - FlavorFungibility: defaultFlavorFungibility, - Preemption: kueue.ClusterQueuePreemption{ - ReclaimWithinCohort: kueue.PreemptionPolicyAny, - WithinClusterQueue: kueue.PreemptionPolicyLowerPriority, + Manager: hierarchy.Manager[*ClusterQueueSnapshot, *CohortSnapshot]{ + ClusterQueues: map[string]*ClusterQueueSnapshot{ + "with-preemption": { + Name: "with-preemption", + NamespaceSelector: labels.Everything(), + AllocatableResourceGeneration: 1, + Status: active, + Workloads: map[string]*workload.Info{}, + FlavorFungibility: defaultFlavorFungibility, + Preemption: kueue.ClusterQueuePreemption{ + ReclaimWithinCohort: kueue.PreemptionPolicyAny, + WithinClusterQueue: kueue.PreemptionPolicyLowerPriority, + }, + FairWeight: oneQuantity, }, - FairWeight: oneQuantity, }, }, }, @@ -383,16 +395,18 @@ func TestSnapshot(t *testing.T) { utiltesting.MakeClusterQueue("with-preemption").FairWeight(resource.MustParse("3")).Obj(), }, wantSnapshot: Snapshot{ - ClusterQueues: map[string]*ClusterQueueSnapshot{ - "with-preemption": { - Name: "with-preemption", - NamespaceSelector: labels.Everything(), - AllocatableResourceGeneration: 1, - Status: active, - Workloads: map[string]*workload.Info{}, - FlavorFungibility: defaultFlavorFungibility, - Preemption: defaultPreemption, - FairWeight: resource.MustParse("3"), + Manager: hierarchy.Manager[*ClusterQueueSnapshot, *CohortSnapshot]{ + ClusterQueues: map[string]*ClusterQueueSnapshot{ + "with-preemption": { + Name: "with-preemption", + NamespaceSelector: labels.Everything(), + AllocatableResourceGeneration: 1, + Status: active, + Workloads: map[string]*workload.Info{}, + FlavorFungibility: defaultFlavorFungibility, + Preemption: defaultPreemption, + FairWeight: resource.MustParse("3"), + }, }, }, }, @@ -456,88 +470,91 @@ func TestSnapshot(t *testing.T) { }, } return Snapshot{ - ClusterQueues: map[string]*ClusterQueueSnapshot{ - "a": { - Name: "a", - Cohort: cohort, - AllocatableResourceGeneration: 2, - ResourceGroups: []ResourceGroup{ - { - CoveredResources: sets.New(corev1.ResourceCPU), - Flavors: []kueue.ResourceFlavorReference{"arm", "x86"}, - LabelKeys: sets.New("arch"), - }, - }, - ResourceNode: ResourceNode{ - Quotas: map[resources.FlavorResource]ResourceQuota{ - {Flavor: "arm", Resource: corev1.ResourceCPU}: {Nominal: 10_000, BorrowingLimit: nil, LendingLimit: ptr.To[int64](5_000)}, - {Flavor: "x86", Resource: corev1.ResourceCPU}: {Nominal: 20_000, BorrowingLimit: nil, LendingLimit: ptr.To[int64](10_000)}, - }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "arm", Resource: corev1.ResourceCPU}: 10_000, - {Flavor: "x86", Resource: corev1.ResourceCPU}: 20_000, - }, - Usage: resources.FlavorResourceQuantities{ - {Flavor: "arm", Resource: corev1.ResourceCPU}: 15_000, - {Flavor: "x86", Resource: corev1.ResourceCPU}: 10_000, - }, - }, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - Workloads: map[string]*workload.Info{ - "/alpha": workload.NewInfo(utiltesting.MakeWorkload("alpha", ""). - PodSets(*utiltesting.MakePodSet("main", 5). - Request(corev1.ResourceCPU, "2").Obj()). - ReserveQuota(utiltesting.MakeAdmission("a", "main"). - Assignment(corev1.ResourceCPU, "arm", "10000m"). - AssignmentPodCount(5).Obj()). - Obj()), - "/beta": workload.NewInfo(utiltesting.MakeWorkload("beta", ""). - PodSets(*utiltesting.MakePodSet("main", 5). - Request(corev1.ResourceCPU, "1").Obj()). - ReserveQuota(utiltesting.MakeAdmission("a", "main"). - Assignment(corev1.ResourceCPU, "arm", "5000m"). - AssignmentPodCount(5).Obj()). - Obj()), - "/gamma": workload.NewInfo(utiltesting.MakeWorkload("gamma", ""). - PodSets(*utiltesting.MakePodSet("main", 5). - Request(corev1.ResourceCPU, "2").Obj()). - ReserveQuota(utiltesting.MakeAdmission("a", "main"). - Assignment(corev1.ResourceCPU, "x86", "10000m"). - AssignmentPodCount(5).Obj()). - Obj()), - }, - Preemption: defaultPreemption, - NamespaceSelector: labels.Everything(), - Status: active, + Manager: hierarchy.Manager[*ClusterQueueSnapshot, *CohortSnapshot]{ + Cohorts: map[string]*CohortSnapshot{ + "lending": cohort, }, - "b": { - Name: "b", - Cohort: cohort, - AllocatableResourceGeneration: 1, - ResourceGroups: []ResourceGroup{ - { - CoveredResources: sets.New(corev1.ResourceCPU), - Flavors: []kueue.ResourceFlavorReference{"arm", "x86"}, - LabelKeys: sets.New("arch"), - }, + ClusterQueues: map[string]*ClusterQueueSnapshot{ + "a": { + Name: "a", + AllocatableResourceGeneration: 2, + ResourceGroups: []ResourceGroup{ + { + CoveredResources: sets.New(corev1.ResourceCPU), + Flavors: []kueue.ResourceFlavorReference{"arm", "x86"}, + LabelKeys: sets.New("arch"), + }, + }, + ResourceNode: ResourceNode{ + Quotas: map[resources.FlavorResource]ResourceQuota{ + {Flavor: "arm", Resource: corev1.ResourceCPU}: {Nominal: 10_000, BorrowingLimit: nil, LendingLimit: ptr.To[int64](5_000)}, + {Flavor: "x86", Resource: corev1.ResourceCPU}: {Nominal: 20_000, BorrowingLimit: nil, LendingLimit: ptr.To[int64](10_000)}, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "arm", Resource: corev1.ResourceCPU}: 10_000, + {Flavor: "x86", Resource: corev1.ResourceCPU}: 20_000, + }, + Usage: resources.FlavorResourceQuantities{ + {Flavor: "arm", Resource: corev1.ResourceCPU}: 15_000, + {Flavor: "x86", Resource: corev1.ResourceCPU}: 10_000, + }, + }, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + Workloads: map[string]*workload.Info{ + "/alpha": workload.NewInfo(utiltesting.MakeWorkload("alpha", ""). + PodSets(*utiltesting.MakePodSet("main", 5). + Request(corev1.ResourceCPU, "2").Obj()). + ReserveQuota(utiltesting.MakeAdmission("a", "main"). + Assignment(corev1.ResourceCPU, "arm", "10000m"). + AssignmentPodCount(5).Obj()). + Obj()), + "/beta": workload.NewInfo(utiltesting.MakeWorkload("beta", ""). + PodSets(*utiltesting.MakePodSet("main", 5). + Request(corev1.ResourceCPU, "1").Obj()). + ReserveQuota(utiltesting.MakeAdmission("a", "main"). + Assignment(corev1.ResourceCPU, "arm", "5000m"). + AssignmentPodCount(5).Obj()). + Obj()), + "/gamma": workload.NewInfo(utiltesting.MakeWorkload("gamma", ""). + PodSets(*utiltesting.MakePodSet("main", 5). + Request(corev1.ResourceCPU, "2").Obj()). + ReserveQuota(utiltesting.MakeAdmission("a", "main"). + Assignment(corev1.ResourceCPU, "x86", "10000m"). + AssignmentPodCount(5).Obj()). + Obj()), + }, + Preemption: defaultPreemption, + NamespaceSelector: labels.Everything(), + Status: active, }, - ResourceNode: ResourceNode{ - Quotas: map[resources.FlavorResource]ResourceQuota{ - {Flavor: "arm", Resource: corev1.ResourceCPU}: {Nominal: 10_000, BorrowingLimit: nil, LendingLimit: ptr.To[int64](5_000)}, - {Flavor: "x86", Resource: corev1.ResourceCPU}: {Nominal: 20_000, BorrowingLimit: nil, LendingLimit: ptr.To[int64](10_000)}, - }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "arm", Resource: corev1.ResourceCPU}: 10_000, - {Flavor: "x86", Resource: corev1.ResourceCPU}: 20_000, - }, - Usage: resources.FlavorResourceQuantities{}, + "b": { + Name: "b", + AllocatableResourceGeneration: 1, + ResourceGroups: []ResourceGroup{ + { + CoveredResources: sets.New(corev1.ResourceCPU), + Flavors: []kueue.ResourceFlavorReference{"arm", "x86"}, + LabelKeys: sets.New("arch"), + }, + }, + ResourceNode: ResourceNode{ + Quotas: map[resources.FlavorResource]ResourceQuota{ + {Flavor: "arm", Resource: corev1.ResourceCPU}: {Nominal: 10_000, BorrowingLimit: nil, LendingLimit: ptr.To[int64](5_000)}, + {Flavor: "x86", Resource: corev1.ResourceCPU}: {Nominal: 20_000, BorrowingLimit: nil, LendingLimit: ptr.To[int64](10_000)}, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "arm", Resource: corev1.ResourceCPU}: 10_000, + {Flavor: "x86", Resource: corev1.ResourceCPU}: 20_000, + }, + Usage: resources.FlavorResourceQuantities{}, + }, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + Preemption: defaultPreemption, + NamespaceSelector: labels.Everything(), + Status: active, }, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - Preemption: defaultPreemption, - NamespaceSelector: labels.Everything(), - Status: active, }, }, ResourceFlavors: map[kueue.ResourceFlavorReference]*kueue.ResourceFlavor{ @@ -608,87 +625,90 @@ func TestSnapshot(t *testing.T) { }, } return Snapshot{ - ClusterQueues: map[string]*ClusterQueueSnapshot{ - "a": { - Name: "a", - Cohort: cohort, - AllocatableResourceGeneration: 2, - ResourceGroups: []ResourceGroup{ - { - CoveredResources: sets.New(corev1.ResourceCPU), - Flavors: []kueue.ResourceFlavorReference{"arm", "x86"}, - LabelKeys: sets.New("arch"), - }, - }, - ResourceNode: ResourceNode{ - Quotas: map[resources.FlavorResource]ResourceQuota{ - {Flavor: "arm", Resource: corev1.ResourceCPU}: {Nominal: 10_000, BorrowingLimit: nil, LendingLimit: nil}, - {Flavor: "x86", Resource: corev1.ResourceCPU}: {Nominal: 20_000, BorrowingLimit: nil, LendingLimit: nil}, - }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "arm", Resource: corev1.ResourceCPU}: 10_000, - {Flavor: "x86", Resource: corev1.ResourceCPU}: 20_000, - }, - Usage: resources.FlavorResourceQuantities{ - {Flavor: "arm", Resource: corev1.ResourceCPU}: 15_000, - {Flavor: "x86", Resource: corev1.ResourceCPU}: 10_000, - }, - }, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - Workloads: map[string]*workload.Info{ - "/alpha": workload.NewInfo(utiltesting.MakeWorkload("alpha", ""). - PodSets(*utiltesting.MakePodSet("main", 5). - Request(corev1.ResourceCPU, "2").Obj()). - ReserveQuota(utiltesting.MakeAdmission("a", "main"). - Assignment(corev1.ResourceCPU, "arm", "10000m"). - AssignmentPodCount(5).Obj()). - Obj()), - "/beta": workload.NewInfo(utiltesting.MakeWorkload("beta", ""). - PodSets(*utiltesting.MakePodSet("main", 5). - Request(corev1.ResourceCPU, "1").Obj()). - ReserveQuota(utiltesting.MakeAdmission("a", "main"). - Assignment(corev1.ResourceCPU, "arm", "5000m"). - AssignmentPodCount(5).Obj()). - Obj()), - "/gamma": workload.NewInfo(utiltesting.MakeWorkload("gamma", ""). - PodSets(*utiltesting.MakePodSet("main", 5). - Request(corev1.ResourceCPU, "2").Obj()). - ReserveQuota(utiltesting.MakeAdmission("a", "main"). - Assignment(corev1.ResourceCPU, "x86", "10000m"). - AssignmentPodCount(5).Obj()). - Obj()), - }, - Preemption: defaultPreemption, - NamespaceSelector: labels.Everything(), - Status: active, + Manager: hierarchy.Manager[*ClusterQueueSnapshot, *CohortSnapshot]{ + Cohorts: map[string]*CohortSnapshot{ + "lending": cohort, }, - "b": { - Name: "b", - Cohort: cohort, - AllocatableResourceGeneration: 1, - ResourceGroups: []ResourceGroup{ - { - CoveredResources: sets.New(corev1.ResourceCPU), - Flavors: []kueue.ResourceFlavorReference{"arm", "x86"}, - LabelKeys: sets.New("arch"), - }, + ClusterQueues: map[string]*ClusterQueueSnapshot{ + "a": { + Name: "a", + AllocatableResourceGeneration: 2, + ResourceGroups: []ResourceGroup{ + { + CoveredResources: sets.New(corev1.ResourceCPU), + Flavors: []kueue.ResourceFlavorReference{"arm", "x86"}, + LabelKeys: sets.New("arch"), + }, + }, + ResourceNode: ResourceNode{ + Quotas: map[resources.FlavorResource]ResourceQuota{ + {Flavor: "arm", Resource: corev1.ResourceCPU}: {Nominal: 10_000, BorrowingLimit: nil, LendingLimit: nil}, + {Flavor: "x86", Resource: corev1.ResourceCPU}: {Nominal: 20_000, BorrowingLimit: nil, LendingLimit: nil}, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "arm", Resource: corev1.ResourceCPU}: 10_000, + {Flavor: "x86", Resource: corev1.ResourceCPU}: 20_000, + }, + Usage: resources.FlavorResourceQuantities{ + {Flavor: "arm", Resource: corev1.ResourceCPU}: 15_000, + {Flavor: "x86", Resource: corev1.ResourceCPU}: 10_000, + }, + }, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + Workloads: map[string]*workload.Info{ + "/alpha": workload.NewInfo(utiltesting.MakeWorkload("alpha", ""). + PodSets(*utiltesting.MakePodSet("main", 5). + Request(corev1.ResourceCPU, "2").Obj()). + ReserveQuota(utiltesting.MakeAdmission("a", "main"). + Assignment(corev1.ResourceCPU, "arm", "10000m"). + AssignmentPodCount(5).Obj()). + Obj()), + "/beta": workload.NewInfo(utiltesting.MakeWorkload("beta", ""). + PodSets(*utiltesting.MakePodSet("main", 5). + Request(corev1.ResourceCPU, "1").Obj()). + ReserveQuota(utiltesting.MakeAdmission("a", "main"). + Assignment(corev1.ResourceCPU, "arm", "5000m"). + AssignmentPodCount(5).Obj()). + Obj()), + "/gamma": workload.NewInfo(utiltesting.MakeWorkload("gamma", ""). + PodSets(*utiltesting.MakePodSet("main", 5). + Request(corev1.ResourceCPU, "2").Obj()). + ReserveQuota(utiltesting.MakeAdmission("a", "main"). + Assignment(corev1.ResourceCPU, "x86", "10000m"). + AssignmentPodCount(5).Obj()). + Obj()), + }, + Preemption: defaultPreemption, + NamespaceSelector: labels.Everything(), + Status: active, }, - ResourceNode: ResourceNode{ - Quotas: map[resources.FlavorResource]ResourceQuota{ - {Flavor: "arm", Resource: corev1.ResourceCPU}: {Nominal: 10_000, BorrowingLimit: nil, LendingLimit: nil}, - {Flavor: "x86", Resource: corev1.ResourceCPU}: {Nominal: 20_000, BorrowingLimit: nil, LendingLimit: nil}, - }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "arm", Resource: corev1.ResourceCPU}: 10_000, - {Flavor: "x86", Resource: corev1.ResourceCPU}: 20_000, - }, + "b": { + Name: "b", + AllocatableResourceGeneration: 1, + ResourceGroups: []ResourceGroup{ + { + CoveredResources: sets.New(corev1.ResourceCPU), + Flavors: []kueue.ResourceFlavorReference{"arm", "x86"}, + LabelKeys: sets.New("arch"), + }, + }, + ResourceNode: ResourceNode{ + Quotas: map[resources.FlavorResource]ResourceQuota{ + {Flavor: "arm", Resource: corev1.ResourceCPU}: {Nominal: 10_000, BorrowingLimit: nil, LendingLimit: nil}, + {Flavor: "x86", Resource: corev1.ResourceCPU}: {Nominal: 20_000, BorrowingLimit: nil, LendingLimit: nil}, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "arm", Resource: corev1.ResourceCPU}: 10_000, + {Flavor: "x86", Resource: corev1.ResourceCPU}: 20_000, + }, + }, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + Preemption: defaultPreemption, + NamespaceSelector: labels.Everything(), + Status: active, }, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - Preemption: defaultPreemption, - NamespaceSelector: labels.Everything(), - Status: active, }, }, ResourceFlavors: map[kueue.ResourceFlavorReference]*kueue.ResourceFlavor{ @@ -724,32 +744,36 @@ func TestSnapshot(t *testing.T) { ).Obj(), }, wantSnapshot: Snapshot{ - ClusterQueues: map[string]*ClusterQueueSnapshot{ - "cq": { - Name: "cq", - AllocatableResourceGeneration: 2, - ResourceGroups: []ResourceGroup{ - { - CoveredResources: sets.New(corev1.ResourceCPU), - Flavors: []kueue.ResourceFlavorReference{"arm", "x86"}, - }, - }, - ResourceNode: ResourceNode{ - Quotas: map[resources.FlavorResource]ResourceQuota{ - {Flavor: "arm", Resource: corev1.ResourceCPU}: {Nominal: 7_000, BorrowingLimit: nil, LendingLimit: ptr.To[int64](3_000)}, - {Flavor: "x86", Resource: corev1.ResourceCPU}: {Nominal: 5_000, BorrowingLimit: nil, LendingLimit: nil}, + Manager: hierarchy.Manager[*ClusterQueueSnapshot, *CohortSnapshot]{ + ClusterQueues: map[string]*ClusterQueueSnapshot{ + "cq": { + Name: "cq", + AllocatableResourceGeneration: 2, + ResourceGroups: []ResourceGroup{ + { + CoveredResources: sets.New(corev1.ResourceCPU), + Flavors: []kueue.ResourceFlavorReference{"arm", "x86"}, + }, }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "arm", Resource: corev1.ResourceCPU}: 7_000, - {Flavor: "x86", Resource: corev1.ResourceCPU}: 5_000, + ResourceNode: ResourceNode{ + Quotas: map[resources.FlavorResource]ResourceQuota{ + {Flavor: "arm", Resource: corev1.ResourceCPU}: {Nominal: 7_000, BorrowingLimit: nil, LendingLimit: ptr.To[int64](3_000)}, + {Flavor: "x86", Resource: corev1.ResourceCPU}: {Nominal: 5_000, BorrowingLimit: nil, LendingLimit: nil}, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "arm", Resource: corev1.ResourceCPU}: 7_000, + {Flavor: "x86", Resource: corev1.ResourceCPU}: 5_000, + }, }, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + Preemption: defaultPreemption, + NamespaceSelector: labels.Everything(), + Status: active, }, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - Preemption: defaultPreemption, - NamespaceSelector: labels.Everything(), - Status: active, - Cohort: &CohortSnapshot{ + }, + Cohorts: map[string]*CohortSnapshot{ + "cohort": { Name: "cohort", ResourceNode: ResourceNode{ Quotas: map[resources.FlavorResource]ResourceQuota{ @@ -881,7 +905,7 @@ func TestSnapshotAddRemoveWorkload(t *testing.T) { } } initialSnapshot := cqCache.Snapshot() - initialCohortResources := initialSnapshot.ClusterQueues["c1"].Cohort.ResourceNode.SubtreeQuota + initialCohortResources := initialSnapshot.ClusterQueues["c1"].Parent().ResourceNode.SubtreeQuota cases := map[string]struct { remove []string add []string @@ -907,41 +931,44 @@ func TestSnapshotAddRemoveWorkload(t *testing.T) { }, } return Snapshot{ - ClusterQueues: map[string]*ClusterQueueSnapshot{ - "c1": { - Name: "c1", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["c1"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - ResourceNode: ResourceNode{ - Usage: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 0, - {Flavor: "alpha", Resource: corev1.ResourceMemory}: 0, - {Flavor: "beta", Resource: corev1.ResourceMemory}: 0, - }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 6_000, - {Flavor: "alpha", Resource: corev1.ResourceMemory}: utiltesting.Gi * 6, - {Flavor: "beta", Resource: corev1.ResourceMemory}: utiltesting.Gi * 6, - }, - }, + Manager: hierarchy.Manager[*ClusterQueueSnapshot, *CohortSnapshot]{ + Cohorts: map[string]*CohortSnapshot{ + "cohort": cohort, }, - "c2": { - Name: "c2", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["c2"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - AllocatableResourceGeneration: 1, - ResourceNode: ResourceNode{ - Usage: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 0, + ClusterQueues: map[string]*ClusterQueueSnapshot{ + "c1": { + Name: "c1", + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["c1"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + ResourceNode: ResourceNode{ + Usage: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 0, + {Flavor: "alpha", Resource: corev1.ResourceMemory}: 0, + {Flavor: "beta", Resource: corev1.ResourceMemory}: 0, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 6_000, + {Flavor: "alpha", Resource: corev1.ResourceMemory}: utiltesting.Gi * 6, + {Flavor: "beta", Resource: corev1.ResourceMemory}: utiltesting.Gi * 6, + }, }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 6_000, + }, + "c2": { + Name: "c2", + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["c2"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + AllocatableResourceGeneration: 1, + ResourceNode: ResourceNode{ + Usage: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 0, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 6_000, + }, }, }, }, @@ -964,47 +991,50 @@ func TestSnapshotAddRemoveWorkload(t *testing.T) { }, } return Snapshot{ - ClusterQueues: map[string]*ClusterQueueSnapshot{ - "c1": { - Name: "c1", - Cohort: cohort, - Workloads: map[string]*workload.Info{ - "/c1-memory-alpha": nil, - "/c1-memory-beta": nil, - }, - ResourceGroups: cqCache.hm.ClusterQueues["c1"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - ResourceNode: ResourceNode{ - Usage: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 0, - {Flavor: "alpha", Resource: corev1.ResourceMemory}: utiltesting.Gi, - {Flavor: "beta", Resource: corev1.ResourceMemory}: utiltesting.Gi, - }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 6_000, - {Flavor: "alpha", Resource: corev1.ResourceMemory}: utiltesting.Gi * 6, - {Flavor: "beta", Resource: corev1.ResourceMemory}: utiltesting.Gi * 6, - }, - }, + Manager: hierarchy.Manager[*ClusterQueueSnapshot, *CohortSnapshot]{ + Cohorts: map[string]*CohortSnapshot{ + "cohort": cohort, }, - "c2": { - Name: "c2", - Cohort: cohort, - Workloads: map[string]*workload.Info{ - "/c2-cpu-1": nil, - "/c2-cpu-2": nil, - }, - ResourceGroups: cqCache.hm.ClusterQueues["c2"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - AllocatableResourceGeneration: 1, - ResourceNode: ResourceNode{ - Usage: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 2_000, + ClusterQueues: map[string]*ClusterQueueSnapshot{ + "c1": { + Name: "c1", + Workloads: map[string]*workload.Info{ + "/c1-memory-alpha": nil, + "/c1-memory-beta": nil, + }, + ResourceGroups: cqCache.hm.ClusterQueues["c1"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + ResourceNode: ResourceNode{ + Usage: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 0, + {Flavor: "alpha", Resource: corev1.ResourceMemory}: utiltesting.Gi, + {Flavor: "beta", Resource: corev1.ResourceMemory}: utiltesting.Gi, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 6_000, + {Flavor: "alpha", Resource: corev1.ResourceMemory}: utiltesting.Gi * 6, + {Flavor: "beta", Resource: corev1.ResourceMemory}: utiltesting.Gi * 6, + }, }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 6_000, + }, + "c2": { + Name: "c2", + Workloads: map[string]*workload.Info{ + "/c2-cpu-1": nil, + "/c2-cpu-2": nil, + }, + ResourceGroups: cqCache.hm.ClusterQueues["c2"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + AllocatableResourceGeneration: 1, + ResourceNode: ResourceNode{ + Usage: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 2_000, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 6_000, + }, }, }, }, @@ -1027,46 +1057,49 @@ func TestSnapshotAddRemoveWorkload(t *testing.T) { }, } return Snapshot{ - ClusterQueues: map[string]*ClusterQueueSnapshot{ - "c1": { - Name: "c1", - Cohort: cohort, - Workloads: map[string]*workload.Info{ - "/c1-memory-alpha": nil, - "/c1-memory-beta": nil, - }, - ResourceGroups: cqCache.hm.ClusterQueues["c1"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - ResourceNode: ResourceNode{ - Usage: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 1_000, - {Flavor: "alpha", Resource: corev1.ResourceMemory}: 0, - {Flavor: "beta", Resource: corev1.ResourceMemory}: utiltesting.Gi, - }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 6_000, - {Flavor: "alpha", Resource: corev1.ResourceMemory}: utiltesting.Gi * 6, - {Flavor: "beta", Resource: corev1.ResourceMemory}: utiltesting.Gi * 6, - }, - }, + Manager: hierarchy.Manager[*ClusterQueueSnapshot, *CohortSnapshot]{ + Cohorts: map[string]*CohortSnapshot{ + "cohort": cohort, }, - "c2": { - Name: "c2", - Cohort: cohort, - Workloads: map[string]*workload.Info{ - "/c2-cpu-1": nil, - "/c2-cpu-2": nil, - }, - ResourceGroups: cqCache.hm.ClusterQueues["c2"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - ResourceNode: ResourceNode{ - Usage: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 2_000, + ClusterQueues: map[string]*ClusterQueueSnapshot{ + "c1": { + Name: "c1", + Workloads: map[string]*workload.Info{ + "/c1-memory-alpha": nil, + "/c1-memory-beta": nil, + }, + ResourceGroups: cqCache.hm.ClusterQueues["c1"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + ResourceNode: ResourceNode{ + Usage: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 1_000, + {Flavor: "alpha", Resource: corev1.ResourceMemory}: 0, + {Flavor: "beta", Resource: corev1.ResourceMemory}: utiltesting.Gi, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 6_000, + {Flavor: "alpha", Resource: corev1.ResourceMemory}: utiltesting.Gi * 6, + {Flavor: "beta", Resource: corev1.ResourceMemory}: utiltesting.Gi * 6, + }, }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 6_000, + }, + "c2": { + Name: "c2", + Workloads: map[string]*workload.Info{ + "/c2-cpu-1": nil, + "/c2-cpu-2": nil, + }, + ResourceGroups: cqCache.hm.ClusterQueues["c2"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + ResourceNode: ResourceNode{ + Usage: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 2_000, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 6_000, + }, }, }, }, @@ -1160,7 +1193,7 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { } } initialSnapshot := cqCache.Snapshot() - initialCohortResources := initialSnapshot.ClusterQueues["lend-a"].Cohort.ResourceNode.SubtreeQuota + initialCohortResources := initialSnapshot.ClusterQueues["lend-a"].Parent().ResourceNode.SubtreeQuota cases := map[string]struct { remove []string add []string @@ -1184,36 +1217,39 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { }, } return Snapshot{ - ClusterQueues: map[string]*ClusterQueueSnapshot{ - "lend-a": { - Name: "lend-a", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - ResourceNode: ResourceNode{ - Usage: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 0, - }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, - }, - }, + Manager: hierarchy.Manager[*ClusterQueueSnapshot, *CohortSnapshot]{ + Cohorts: map[string]*CohortSnapshot{ + "lend": cohort, }, - "lend-b": { - Name: "lend-b", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["lend-b"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - ResourceNode: ResourceNode{ - Usage: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 0, + ClusterQueues: map[string]*ClusterQueueSnapshot{ + "lend-a": { + Name: "lend-a", + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + ResourceNode: ResourceNode{ + Usage: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 0, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, + }, }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, + }, + "lend-b": { + Name: "lend-b", + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["lend-b"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + ResourceNode: ResourceNode{ + Usage: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 0, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, + }, }, }, }, @@ -1234,37 +1270,40 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { }, } return Snapshot{ - ClusterQueues: map[string]*ClusterQueueSnapshot{ - "lend-a": { - Name: "lend-a", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - ResourceNode: ResourceNode{ - Usage: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 7_000, - }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, - }, - }, + Manager: hierarchy.Manager[*ClusterQueueSnapshot, *CohortSnapshot]{ + Cohorts: map[string]*CohortSnapshot{ + "lend": cohort, }, - "lend-b": { - Name: "lend-b", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["lend-b"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - AllocatableResourceGeneration: 1, - ResourceNode: ResourceNode{ - Usage: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 4_000, + ClusterQueues: map[string]*ClusterQueueSnapshot{ + "lend-a": { + Name: "lend-a", + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + ResourceNode: ResourceNode{ + Usage: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 7_000, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, + }, }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, + }, + "lend-b": { + Name: "lend-b", + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["lend-b"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + AllocatableResourceGeneration: 1, + ResourceNode: ResourceNode{ + Usage: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 4_000, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, + }, }, }, }, @@ -1285,37 +1324,40 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { }, } return Snapshot{ - ClusterQueues: map[string]*ClusterQueueSnapshot{ - "lend-a": { - Name: "lend-a", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - ResourceNode: ResourceNode{ - Usage: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 6_000, - }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, - }, - }, + Manager: hierarchy.Manager[*ClusterQueueSnapshot, *CohortSnapshot]{ + Cohorts: map[string]*CohortSnapshot{ + "lend": cohort, }, - "lend-b": { - Name: "lend-b", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["lend-b"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - AllocatableResourceGeneration: 1, - ResourceNode: ResourceNode{ - Usage: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 4_000, + ClusterQueues: map[string]*ClusterQueueSnapshot{ + "lend-a": { + Name: "lend-a", + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + ResourceNode: ResourceNode{ + Usage: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 6_000, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, + }, }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, + }, + "lend-b": { + Name: "lend-b", + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["lend-b"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + AllocatableResourceGeneration: 1, + ResourceNode: ResourceNode{ + Usage: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 4_000, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, + }, }, }, }, @@ -1336,37 +1378,40 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { }, } return Snapshot{ - ClusterQueues: map[string]*ClusterQueueSnapshot{ - "lend-a": { - Name: "lend-a", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - ResourceNode: ResourceNode{ - Usage: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 1_000, - }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, - }, - }, + Manager: hierarchy.Manager[*ClusterQueueSnapshot, *CohortSnapshot]{ + Cohorts: map[string]*CohortSnapshot{ + "lend": cohort, }, - "lend-b": { - Name: "lend-b", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["lend-b"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - AllocatableResourceGeneration: 1, - ResourceNode: ResourceNode{ - Usage: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 4_000, + ClusterQueues: map[string]*ClusterQueueSnapshot{ + "lend-a": { + Name: "lend-a", + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + ResourceNode: ResourceNode{ + Usage: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 1_000, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, + }, }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, + }, + "lend-b": { + Name: "lend-b", + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["lend-b"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + AllocatableResourceGeneration: 1, + ResourceNode: ResourceNode{ + Usage: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 4_000, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, + }, }, }, }, @@ -1388,37 +1433,40 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { }, } return Snapshot{ - ClusterQueues: map[string]*ClusterQueueSnapshot{ - "lend-a": { - Name: "lend-a", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - ResourceNode: ResourceNode{ - Usage: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 1_000, - }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, - }, - }, + Manager: hierarchy.Manager[*ClusterQueueSnapshot, *CohortSnapshot]{ + Cohorts: map[string]*CohortSnapshot{ + "lend": cohort, }, - "lend-b": { - Name: "lend-b", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["lend-b"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - AllocatableResourceGeneration: 1, - ResourceNode: ResourceNode{ - Usage: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 0, + ClusterQueues: map[string]*ClusterQueueSnapshot{ + "lend-a": { + Name: "lend-a", + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + ResourceNode: ResourceNode{ + Usage: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 1_000, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, + }, }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, + }, + "lend-b": { + Name: "lend-b", + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["lend-b"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + AllocatableResourceGeneration: 1, + ResourceNode: ResourceNode{ + Usage: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 0, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, + }, }, }, }, @@ -1440,36 +1488,39 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { }, } return Snapshot{ - ClusterQueues: map[string]*ClusterQueueSnapshot{ - "lend-a": { - Name: "lend-a", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - ResourceNode: ResourceNode{ - Usage: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 6_000, - }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, - }, - }, + Manager: hierarchy.Manager[*ClusterQueueSnapshot, *CohortSnapshot]{ + Cohorts: map[string]*CohortSnapshot{ + "lend": cohort, }, - "lend-b": { - Name: "lend-b", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["lend-b"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - ResourceNode: ResourceNode{ - Usage: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 0, + ClusterQueues: map[string]*ClusterQueueSnapshot{ + "lend-a": { + Name: "lend-a", + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + ResourceNode: ResourceNode{ + Usage: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 6_000, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, + }, }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, + }, + "lend-b": { + Name: "lend-b", + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["lend-b"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + ResourceNode: ResourceNode{ + Usage: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 0, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, + }, }, }, }, @@ -1491,37 +1542,40 @@ func TestSnapshotAddRemoveWorkloadWithLendingLimit(t *testing.T) { }, } return Snapshot{ - ClusterQueues: map[string]*ClusterQueueSnapshot{ - "lend-a": { - Name: "lend-a", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - ResourceNode: ResourceNode{ - Usage: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 9_000, - }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, - }, - }, + Manager: hierarchy.Manager[*ClusterQueueSnapshot, *CohortSnapshot]{ + Cohorts: map[string]*CohortSnapshot{ + "lend": cohort, }, - "lend-b": { - Name: "lend-b", - Cohort: cohort, - Workloads: make(map[string]*workload.Info), - ResourceGroups: cqCache.hm.ClusterQueues["lend-b"].ResourceGroups, - FlavorFungibility: defaultFlavorFungibility, - FairWeight: oneQuantity, - AllocatableResourceGeneration: 1, - ResourceNode: ResourceNode{ - Usage: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 0, + ClusterQueues: map[string]*ClusterQueueSnapshot{ + "lend-a": { + Name: "lend-a", + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["lend-a"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + ResourceNode: ResourceNode{ + Usage: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 9_000, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, + }, }, - SubtreeQuota: resources.FlavorResourceQuantities{ - {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, + }, + "lend-b": { + Name: "lend-b", + Workloads: make(map[string]*workload.Info), + ResourceGroups: cqCache.hm.ClusterQueues["lend-b"].ResourceGroups, + FlavorFungibility: defaultFlavorFungibility, + FairWeight: oneQuantity, + AllocatableResourceGeneration: 1, + ResourceNode: ResourceNode{ + Usage: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 0, + }, + SubtreeQuota: resources.FlavorResourceQuantities{ + {Flavor: "default", Resource: corev1.ResourceCPU}: 10_000, + }, }, }, }, diff --git a/pkg/scheduler/flavorassigner/flavorassigner.go b/pkg/scheduler/flavorassigner/flavorassigner.go index bac68990b5..d38b77ce02 100644 --- a/pkg/scheduler/flavorassigner/flavorassigner.go +++ b/pkg/scheduler/flavorassigner/flavorassigner.go @@ -613,7 +613,7 @@ func (a *FlavorAssigner) fitsResourceQuota(log logr.Logger, fr resources.FlavorR lackQuantity := resources.ResourceQuantity(fr.Resource, lack) msg := fmt.Sprintf("insufficient unused quota in cohort for %s in flavor %s, %s more needed", fr.Resource, fr.Flavor, &lackQuantity) - if a.cq.Cohort == nil { + if !a.cq.HasParent() { if mode == noFit { msg = fmt.Sprintf("insufficient quota for %s in flavor %s in ClusterQueue", fr.Resource, fr.Flavor) } else { diff --git a/pkg/scheduler/flavorassigner/flavorassigner_test.go b/pkg/scheduler/flavorassigner/flavorassigner_test.go index b23031b8fd..c2493f2353 100644 --- a/pkg/scheduler/flavorassigner/flavorassigner_test.go +++ b/pkg/scheduler/flavorassigner/flavorassigner_test.go @@ -1954,11 +1954,11 @@ func TestAssignFlavors(t *testing.T) { } if tc.cohortResources != nil { - if clusterQueue.Cohort == nil { + if !clusterQueue.HasParent() { t.Fatalf("Test case has cohort resources, but cluster queue doesn't have cohort") } - clusterQueue.Cohort.ResourceNode.Usage = tc.cohortResources.usage - clusterQueue.Cohort.ResourceNode.SubtreeQuota = tc.cohortResources.requestableResources + clusterQueue.Parent().ResourceNode.Usage = tc.cohortResources.usage + clusterQueue.Parent().ResourceNode.SubtreeQuota = tc.cohortResources.requestableResources } clusterQueue.ResourceNode.Usage = tc.clusterQueueUsage @@ -2269,7 +2269,6 @@ func TestLastAssignmentOutdated(t *testing.T) { }, }, cq: &cache.ClusterQueueSnapshot{ - Cohort: nil, AllocatableResourceGeneration: 1, }, }, diff --git a/pkg/scheduler/preemption/preemption.go b/pkg/scheduler/preemption/preemption.go index f370afa577..3b061c7cdd 100644 --- a/pkg/scheduler/preemption/preemption.go +++ b/pkg/scheduler/preemption/preemption.go @@ -510,9 +510,9 @@ func (p *Preemptor) findCandidates(wl *kueue.Workload, cq *cache.ClusterQueueSna } } - if cq.Cohort != nil && cq.Preemption.ReclaimWithinCohort != kueue.PreemptionPolicyNever { + if cq.HasParent() && cq.Preemption.ReclaimWithinCohort != kueue.PreemptionPolicyNever { onlyLowerPriority := cq.Preemption.ReclaimWithinCohort != kueue.PreemptionPolicyAny - for cohortCQ := range cq.Cohort.Members { + for _, cohortCQ := range cq.Parent().ChildCQs() { if cq == cohortCQ || !cqIsBorrowing(cohortCQ, frsNeedPreemption) { // Can't reclaim quota from itself or ClusterQueues that are not borrowing. continue @@ -532,7 +532,7 @@ func (p *Preemptor) findCandidates(wl *kueue.Workload, cq *cache.ClusterQueueSna } func cqIsBorrowing(cq *cache.ClusterQueueSnapshot, frsNeedPreemption sets.Set[resources.FlavorResource]) bool { - if cq.Cohort == nil { + if !cq.HasParent() { return false } for fr := range frsNeedPreemption { diff --git a/pkg/scheduler/preemption/preemption_test.go b/pkg/scheduler/preemption/preemption_test.go index ee5020205d..4d6a533a8b 100644 --- a/pkg/scheduler/preemption/preemption_test.go +++ b/pkg/scheduler/preemption/preemption_test.go @@ -41,6 +41,7 @@ import ( "sigs.k8s.io/kueue/pkg/cache" "sigs.k8s.io/kueue/pkg/constants" "sigs.k8s.io/kueue/pkg/features" + "sigs.k8s.io/kueue/pkg/hierarchy" "sigs.k8s.io/kueue/pkg/scheduler/flavorassigner" "sigs.k8s.io/kueue/pkg/util/slices" utiltesting "sigs.k8s.io/kueue/pkg/util/testing" @@ -49,7 +50,9 @@ import ( var snapCmpOpts = []cmp.Option{ cmpopts.EquateEmpty(), - cmpopts.IgnoreUnexported(cache.ClusterQueueSnapshot{}), + cmpopts.IgnoreUnexported(hierarchy.Cohort[*cache.ClusterQueueSnapshot, *cache.CohortSnapshot]{}), + cmpopts.IgnoreUnexported(hierarchy.ClusterQueue[*cache.CohortSnapshot]{}), + cmpopts.IgnoreUnexported(hierarchy.Manager[*cache.ClusterQueueSnapshot, *cache.CohortSnapshot]{}), cmpopts.IgnoreFields(cache.ClusterQueueSnapshot{}, "AllocatableResourceGeneration"), cmp.Transformer("Cohort.Members", func(s sets.Set[*cache.ClusterQueueSnapshot]) sets.Set[string] { result := make(sets.Set[string], len(s)) diff --git a/pkg/scheduler/scheduler.go b/pkg/scheduler/scheduler.go index ff34f79565..f225603f6e 100644 --- a/pkg/scheduler/scheduler.go +++ b/pkg/scheduler/scheduler.go @@ -273,17 +273,17 @@ func (s *Scheduler) schedule(ctx context.Context) wait.SpeedSignal { } preemptedWorkloads.Insert(pendingPreemptions...) cq.AddUsage(usage) - } else if cq.Cohort != nil { - sum := cycleCohortsUsage.totalUsageForCommonFlavorResources(cq.Cohort.Name, e.assignment.Usage) + } else if cq.HasParent() { + sum := cycleCohortsUsage.totalUsageForCommonFlavorResources(cq.Parent().Name, e.assignment.Usage) // Check whether there was an assignment in this cycle that could render the next assignments invalid: // - If the workload no longer fits in the cohort. // - If there was another assignment in the cohort, then the preemption calculation is no longer valid. - if cycleCohortsUsage.hasCommonFlavorResources(cq.Cohort.Name, e.assignment.Usage) { + if cycleCohortsUsage.hasCommonFlavorResources(cq.Parent().Name, e.assignment.Usage) { if mode == flavorassigner.Fit && !cq.FitInCohort(sum) { setSkipped(e, "Workload no longer fits after processing another workload") continue } - if mode == flavorassigner.Preempt && cycleCohortsSkipPreemption.Has(cq.Cohort.Name) { + if mode == flavorassigner.Preempt && cycleCohortsSkipPreemption.Has(cq.Parent().Name) { setSkipped(e, "Workload skipped because its preemption calculations were invalidated by another workload") skippedPreemptions[cq.Name]++ continue @@ -291,7 +291,7 @@ func (s *Scheduler) schedule(ctx context.Context) wait.SpeedSignal { } // Even if the workload will not be admitted after this point, due to preemption pending or other failures, // we should still account for its usage. - cycleCohortsUsage.add(cq.Cohort.Name, resourcesToReserve(e, cq)) + cycleCohortsUsage.add(cq.Parent().Name, resourcesToReserve(e, cq)) } if e.assignment.RepresentativeMode() != flavorassigner.Fit { if len(e.preemptionTargets) != 0 { @@ -305,8 +305,8 @@ func (s *Scheduler) schedule(ctx context.Context) wait.SpeedSignal { e.inadmissibleMsg += fmt.Sprintf(". Pending the preemption of %d workload(s)", preempted) e.requeueReason = queue.RequeueReasonPendingPreemption } - if cq.Cohort != nil { - cycleCohortsSkipPreemption.Insert(cq.Cohort.Name) + if cq.HasParent() { + cycleCohortsSkipPreemption.Insert(cq.Parent().Name) } } else { log.V(2).Info("Workload requires preemption, but there are no candidate workloads allowed for preemption", "preemption", cq.Preemption) @@ -329,8 +329,8 @@ func (s *Scheduler) schedule(ctx context.Context) wait.SpeedSignal { if err := s.admit(ctx, e, cq); err != nil { e.inadmissibleMsg = fmt.Sprintf("Failed to admit workload: %v", err) } - if cq.Cohort != nil { - cycleCohortsSkipPreemption.Insert(cq.Cohort.Name) + if cq.HasParent() { + cycleCohortsSkipPreemption.Insert(cq.Parent().Name) } } From be27bb83d087783d7a227e2068bb874110ac9580 Mon Sep 17 00:00:00 2001 From: Yuki Iwai Date: Thu, 5 Sep 2024 21:17:50 +0900 Subject: [PATCH 007/155] Update the release issue template with new admin, Michal (#2986) Signed-off-by: Yuki Iwai --- .github/ISSUE_TEMPLATE/NEW_RELEASE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/NEW_RELEASE.md b/.github/ISSUE_TEMPLATE/NEW_RELEASE.md index 54e5942ed9..8b8e417a16 100644 --- a/.github/ISSUE_TEMPLATE/NEW_RELEASE.md +++ b/.github/ISSUE_TEMPLATE/NEW_RELEASE.md @@ -2,7 +2,7 @@ name: New Release about: Propose a new release title: Release v0.x.0 -assignees: ahg-g, alculquicondor, tenzen-y +assignees: alculquicondor, mimowo, tenzen-y --- From 973c6d658d4f6ff7e38582bf21211861058627c6 Mon Sep 17 00:00:00 2001 From: Mykhailo Bobrovskyi Date: Thu, 5 Sep 2024 16:40:34 +0300 Subject: [PATCH 008/155] [kjobctl] Fix create interactive command. (#2980) * [kjobctl] Fix create interactive command. * Skip interactive session on dry-run. * Test Run method on CreateOptions with Interactive mode. * Rename updatePodAfterCreation to createMutation. --- .../kjobctl/pkg/cmd/create/create.go | 8 +- .../kjobctl/pkg/cmd/create/create_test.go | 266 ++++++++++++------ .../testing/wrappers/container_wrappers.go | 12 + 3 files changed, 201 insertions(+), 85 deletions(-) diff --git a/cmd/experimental/kjobctl/pkg/cmd/create/create.go b/cmd/experimental/kjobctl/pkg/cmd/create/create.go index 88208a341d..4b3963ad91 100644 --- a/cmd/experimental/kjobctl/pkg/cmd/create/create.go +++ b/cmd/experimental/kjobctl/pkg/cmd/create/create.go @@ -588,21 +588,21 @@ func (o *CreateOptions) Run(ctx context.Context, clientGetter util.ClientGetter, return err } - for _, obj := range objs { + for i := range objs { if o.DryRunStrategy != util.DryRunClient { - obj, err = o.createObject(ctx, clientGetter, obj) + objs[i], err = o.createObject(ctx, clientGetter, objs[i]) if err != nil { return err } } - err = o.PrintObj(obj, o.Out) + err = o.PrintObj(objs[i], o.Out) if err != nil { return err } } - if o.ModeName == v1alpha1.InteractiveMode { + if o.DryRunStrategy == util.DryRunNone && o.ModeName == v1alpha1.InteractiveMode { pod := objs[0].(*corev1.Pod) return o.RunInteractivePod(ctx, clientGetter, pod.Name) } diff --git a/cmd/experimental/kjobctl/pkg/cmd/create/create_test.go b/cmd/experimental/kjobctl/pkg/cmd/create/create_test.go index aca79e78e4..62724f61c2 100644 --- a/cmd/experimental/kjobctl/pkg/cmd/create/create_test.go +++ b/cmd/experimental/kjobctl/pkg/cmd/create/create_test.go @@ -35,14 +35,18 @@ import ( "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + utilrand "k8s.io/apimachinery/pkg/util/rand" utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/cli-runtime/pkg/genericiooptions" "k8s.io/client-go/dynamic/fake" k8sfake "k8s.io/client-go/kubernetes/fake" k8sscheme "k8s.io/client-go/kubernetes/scheme" restclient "k8s.io/client-go/rest" + kubetesting "k8s.io/client-go/testing" "k8s.io/client-go/tools/remotecommand" clocktesting "k8s.io/utils/clock/testing" "k8s.io/utils/ptr" @@ -50,6 +54,7 @@ import ( "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" + cmdutil "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/cmd/util" "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/constants" "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/testing/wrappers" ) @@ -1123,94 +1128,144 @@ error_path=$(unmask_filename "$SBATCH_ERROR") } } -func TestInteractivePod(t *testing.T) { +func TestCreateOptionsRunInteractive(t *testing.T) { + testStartTime := time.Now() + userID := os.Getenv(constants.SystemEnvVarNameUser) + testCases := map[string]struct { - podName string - options *CreateOptions - pods []runtime.Object - wantErr string + options *CreateOptions + k8sObjs []runtime.Object + kjobctlObjs []runtime.Object + createMutation func(pod *corev1.Pod) + wantPodList *corev1.PodList + 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, - }, + Namespace: metav1.NamespaceDefault, + ProfileName: "profile", + ModeName: v1alpha1.InteractiveMode, + Attach: &fakeRemoteAttach{}, + AttachFunc: testAttachFunc, + }, + k8sObjs: []runtime.Object{ + wrappers.MakePodTemplate("pod-template", metav1.NamespaceDefault). + WithContainer(*wrappers.MakeContainer("c1", "sleep").Obj()). + Obj(), + }, + kjobctlObjs: []runtime.Object{ + wrappers.MakeApplicationProfile("profile", metav1.NamespaceDefault). + WithSupportedMode(*wrappers.MakeSupportedMode(v1alpha1.InteractiveMode, "pod-template").Obj()). + Obj(), + }, + createMutation: func(pod *corev1.Pod) { + pod.Status.Phase = corev1.PodRunning + }, + wantPodList: &corev1.PodList{ + Items: []corev1.Pod{ + *wrappers.MakePod("", metav1.NamespaceDefault). + GenerateName("profile-interactive-"). + Profile("profile"). + Mode(v1alpha1.InteractiveMode). + WithContainer(*wrappers.MakeContainer("c1", "sleep"). + TTY(). + Stdin(). + 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()). + Phase(corev1.PodRunning). + Obj(), }, }, }, - "tty not allocated": { - podName: "foo", + "success with remove interactive pod": { 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, - }, - }, + Namespace: metav1.NamespaceDefault, + ProfileName: "profile", + ModeName: v1alpha1.InteractiveMode, + RemoveInteractivePod: true, + Attach: &fakeRemoteAttach{}, + AttachFunc: testAttachFunc, + }, + k8sObjs: []runtime.Object{ + wrappers.MakePodTemplate("pod-template", metav1.NamespaceDefault). + WithContainer(*wrappers.MakeContainer("c1", "sleep").Obj()). + Obj(), + }, + kjobctlObjs: []runtime.Object{ + wrappers.MakeApplicationProfile("profile", metav1.NamespaceDefault). + WithSupportedMode(*wrappers.MakeSupportedMode(v1alpha1.InteractiveMode, "pod-template").Obj()). + Obj(), + }, + createMutation: func(pod *corev1.Pod) { + pod.Status.Phase = corev1.PodRunning + }, + wantPodList: &corev1.PodList{}, + }, + "success with dry-run client": { + options: &CreateOptions{ + Namespace: metav1.NamespaceDefault, + ProfileName: "profile", + ModeName: v1alpha1.InteractiveMode, + DryRunStrategy: cmdutil.DryRunClient, + Attach: &fakeRemoteAttach{}, + AttachFunc: testAttachFunc, + }, + k8sObjs: []runtime.Object{ + wrappers.MakePodTemplate("pod-template", metav1.NamespaceDefault). + WithContainer(*wrappers.MakeContainer("c1", "sleep").Obj()). + Obj(), + }, + kjobctlObjs: []runtime.Object{ + wrappers.MakeApplicationProfile("profile", metav1.NamespaceDefault). + WithSupportedMode(*wrappers.MakeSupportedMode(v1alpha1.InteractiveMode, "pod-template").Obj()). + Obj(), }, - wantErr: "error: Unable to use a TTY - container bar did not allocate one", + wantPodList: &corev1.PodList{}, }, "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, - }, + Namespace: metav1.NamespaceDefault, + ProfileName: "profile", + ModeName: v1alpha1.InteractiveMode, + Attach: &fakeRemoteAttach{}, + AttachFunc: testAttachFunc, + }, + k8sObjs: []runtime.Object{ + wrappers.MakePodTemplate("pod-template", metav1.NamespaceDefault). + WithContainer(*wrappers.MakeContainer("c1", "sleep").Obj()). + Obj(), + }, + kjobctlObjs: []runtime.Object{ + wrappers.MakeApplicationProfile("profile", metav1.NamespaceDefault). + WithSupportedMode(*wrappers.MakeSupportedMode(v1alpha1.InteractiveMode, "pod-template").Obj()). + Obj(), + }, + wantPodList: &corev1.PodList{ + Items: []corev1.Pod{ + *wrappers.MakePod("", metav1.NamespaceDefault). + GenerateName("profile-interactive-"). + Profile("profile"). + Mode(v1alpha1.InteractiveMode). + WithContainer(*wrappers.MakeContainer("c1", "sleep"). + TTY(). + Stdin(). + 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()). + Obj(), }, }, wantErr: "context deadline exceeded", @@ -1222,11 +1277,50 @@ func TestInteractivePod(t *testing.T) { tc.options.IOStreams = streams tc.options.Out = out tc.options.ErrOut = outErr + tc.options.PrintFlags = genericclioptions.NewPrintFlags("created").WithTypeSetter(k8sscheme.Scheme) + printer, err := tc.options.PrintFlags.ToPrinter() + if err != nil { + t.Fatal(err) + } + tc.options.PrintObj = printer.PrintObj - clientset := k8sfake.NewSimpleClientset(tc.pods...) - tcg := cmdtesting.NewTestClientGetter().WithK8sClientset(clientset) + k8sClientset := k8sfake.NewSimpleClientset(tc.k8sObjs...) + kjobctlClientset := kjobctlfake.NewSimpleClientset(tc.kjobctlObjs...) + dynamicClient := fake.NewSimpleDynamicClient(k8sscheme.Scheme) + restMapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{}) + restMapper.Add(schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"}, meta.RESTScopeNamespace) - gotErr := tc.options.RunInteractivePod(context.TODO(), tcg, tc.podName) + dynamicClient.PrependReactor("create", "pods", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { + createAction := action.(kubetesting.CreateAction) + + unstructuredObj := createAction.GetObject().(*unstructured.Unstructured) + unstructuredObj.SetName(unstructuredObj.GetGenerateName() + utilrand.String(5)) + + pod := &corev1.Pod{} + + if err = runtime.DefaultUnstructuredConverter.FromUnstructured(unstructuredObj.UnstructuredContent(), pod); err != nil { + return true, nil, err + } + + if tc.createMutation != nil { + tc.createMutation(pod) + } + + _, err = k8sClientset.CoreV1().Pods(pod.GetNamespace()).Create(context.Background(), pod, metav1.CreateOptions{}) + if err != nil { + return true, nil, err + } + + return true, unstructuredObj, err + }) + + tcg := cmdtesting.NewTestClientGetter(). + WithK8sClientset(k8sClientset). + WithKjobctlClientset(kjobctlClientset). + WithDynamicClient(dynamicClient). + WithRESTMapper(restMapper) + + gotErr := tc.options.Run(context.Background(), tcg, testStartTime) var gotErrStr string if gotErr != nil { @@ -1236,6 +1330,16 @@ func TestInteractivePod(t *testing.T) { if diff := cmp.Diff(tc.wantErr, gotErrStr); diff != "" { t.Errorf("Unexpected error (-want/+got)\n%s", diff) } + + gotPodList, err := k8sClientset.CoreV1().Pods(metav1.NamespaceDefault).List(context.Background(), metav1.ListOptions{}) + if err != nil { + t.Fatal(err) + } + + defaultCmpOpts := []cmp.Option{cmpopts.IgnoreFields(metav1.ObjectMeta{}, "Name")} + if diff := cmp.Diff(tc.wantPodList, gotPodList, defaultCmpOpts...); diff != "" { + t.Errorf("Unexpected error (-want/+got)\n%s", diff) + } }) } } @@ -1245,12 +1349,12 @@ type fakeRemoteAttach struct { 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 { +func (f *fakeRemoteAttach) Attach(url *url.URL, _ *restclient.Config, _ io.Reader, _, _ io.Writer, _ bool, _ remotecommand.TerminalSizeQueue) error { f.url = url return f.err } -func testAttachFunc(o *CreateOptions, containerToAttach *corev1.Container, sizeQueue remotecommand.TerminalSizeQueue, pod *corev1.Pod) func() error { +func testAttachFunc(o *CreateOptions, _ *corev1.Container, sizeQueue remotecommand.TerminalSizeQueue, _ *corev1.Pod) func() error { return func() error { u, err := url.Parse("http://kjobctl.test") if err != nil { diff --git a/cmd/experimental/kjobctl/pkg/testing/wrappers/container_wrappers.go b/cmd/experimental/kjobctl/pkg/testing/wrappers/container_wrappers.go index b22d4e60f7..4d434a55a8 100644 --- a/cmd/experimental/kjobctl/pkg/testing/wrappers/container_wrappers.go +++ b/cmd/experimental/kjobctl/pkg/testing/wrappers/container_wrappers.go @@ -68,3 +68,15 @@ func (c *ContainerWrapper) WithVolumeMount(volumeMount corev1.VolumeMount) *Cont c.Container.VolumeMounts = append(c.Container.VolumeMounts, volumeMount) return c } + +// TTY set tty=true. +func (c *ContainerWrapper) TTY() *ContainerWrapper { + c.Container.TTY = true + return c +} + +// Stdin set stdin=true. +func (c *ContainerWrapper) Stdin() *ContainerWrapper { + c.Container.Stdin = true + return c +} From 31b0603ae98179d478085437f928099fc83c974f Mon Sep 17 00:00:00 2001 From: Traian Schiau <55734665+trasc@users.noreply.github.com> Date: Thu, 5 Sep 2024 17:24:26 +0300 Subject: [PATCH 009/155] [config] Add cohorts CRD in the kustomization (#2995) --- config/components/crd/kustomization.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/components/crd/kustomization.yaml b/config/components/crd/kustomization.yaml index e2f85f1088..b87cb805af 100644 --- a/config/components/crd/kustomization.yaml +++ b/config/components/crd/kustomization.yaml @@ -4,6 +4,7 @@ resources: - bases/kueue.x-k8s.io_localqueues.yaml - bases/kueue.x-k8s.io_clusterqueues.yaml +- bases/kueue.x-k8s.io_cohorts.yaml - bases/kueue.x-k8s.io_workloads.yaml - bases/kueue.x-k8s.io_resourceflavors.yaml - bases/kueue.x-k8s.io_admissionchecks.yaml From ece18974690b4e59cfa179b4514da0cffcd53fda Mon Sep 17 00:00:00 2001 From: Mykhailo Bobrovskyi Date: Thu, 5 Sep 2024 17:47:28 +0300 Subject: [PATCH 010/155] [kjobctl] Add describe raycluster command. (#2966) --- .../pkg/cmd/describe/describe_printer.go | 73 ++++++++++++- .../kjobctl/pkg/cmd/describe/describe_test.go | 103 ++++++++++++++++++ .../wrappers/ray_cluster_spec_wrapper.go | 7 ++ .../testing/wrappers/ray_cluster_wrappers.go | 30 +++++ .../wrappers/worker_group_spec_wrapper.go | 6 + 5 files changed, 216 insertions(+), 3 deletions(-) diff --git a/cmd/experimental/kjobctl/pkg/cmd/describe/describe_printer.go b/cmd/experimental/kjobctl/pkg/cmd/describe/describe_printer.go index c8250c0cdd..4f1a82372a 100644 --- a/cmd/experimental/kjobctl/pkg/cmd/describe/describe_printer.go +++ b/cmd/experimental/kjobctl/pkg/cmd/describe/describe_printer.go @@ -30,6 +30,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/duration" describehelper "k8s.io/kubectl/pkg/describe" + "k8s.io/utils/ptr" ) // ResourceDescriber generates output for the named resource or an error @@ -52,9 +53,10 @@ func NewResourceDescriber(mapping *meta.RESTMapping) (ResourceDescriber, error) // Kubernetes types. func DescriberFor(kind schema.GroupKind) (ResourceDescriber, bool) { describers := map[schema.GroupKind]ResourceDescriber{ - {Group: batchv1.GroupName, Kind: "Job"}: &JobDescriber{}, - {Group: corev1.GroupName, Kind: "Pod"}: &PodDescriber{}, - {Group: rayv1.GroupVersion.Group, Kind: "RayJob"}: &RayJobDescriber{}, + {Group: batchv1.GroupName, Kind: "Job"}: &JobDescriber{}, + {Group: corev1.GroupName, Kind: "Pod"}: &PodDescriber{}, + {Group: rayv1.GroupVersion.Group, Kind: "RayJob"}: &RayJobDescriber{}, + {Group: rayv1.GroupVersion.Group, Kind: "RayCluster"}: &RayClusterDescriber{}, } f, ok := describers[kind] @@ -224,3 +226,68 @@ func describeRayJob(rayJob *rayv1.RayJob) (string, error) { return nil }) } + +// RayClusterDescriber generates information about a ray cluster. +type RayClusterDescriber struct{} + +func (d *RayClusterDescriber) Describe(object *unstructured.Unstructured) (string, error) { + rayCluster := &rayv1.RayCluster{} + err := runtime.DefaultUnstructuredConverter.FromUnstructured(object.UnstructuredContent(), rayCluster) + if err != nil { + return "", err + } + + return describeRayCluster(rayCluster) +} + +func describeRayCluster(rayCluster *rayv1.RayCluster) (string, error) { + return tabbedString(func(out io.Writer) error { + w := describehelper.NewPrefixWriter(out) + + w.Write(IndentLevelZero, "Name:\t%s\n", rayCluster.Name) + w.Write(IndentLevelZero, "Namespace:\t%s\n", rayCluster.Namespace) + + printLabelsMultiline(w, "Labels", rayCluster.Labels) + + w.Write(IndentLevelZero, "Suspend:\t%t\n", ptr.Deref(rayCluster.Spec.Suspend, false)) + w.Write(IndentLevelZero, "State:\t%s\n", string(rayCluster.Status.State)) + if len(rayCluster.Status.Reason) > 0 { + w.Write(IndentLevelZero, "Reason:\t%s\n", rayCluster.Status.Reason) + } + + w.Write(IndentLevelZero, "Desired CPU:\t%s\n", rayCluster.Status.DesiredCPU.String()) + w.Write(IndentLevelZero, "Desired GPU:\t%s\n", rayCluster.Status.DesiredGPU.String()) + w.Write(IndentLevelZero, "Desired Memory:\t%s\n", rayCluster.Status.DesiredMemory.String()) + w.Write(IndentLevelZero, "Desired TPU:\t%s\n", rayCluster.Status.DesiredTPU.String()) + + w.Write(IndentLevelZero, "Ready Worker Replicas:\t%d\n", rayCluster.Status.ReadyWorkerReplicas) + w.Write(IndentLevelZero, "Available Worker Replicas:\t%d\n", rayCluster.Status.AvailableWorkerReplicas) + w.Write(IndentLevelZero, "Desired Worker Replicas:\t%d\n", rayCluster.Status.DesiredWorkerReplicas) + w.Write(IndentLevelZero, "Min Worker Replicas:\t%d\n", rayCluster.Status.MinWorkerReplicas) + w.Write(IndentLevelZero, "Max Worker Replicas:\t%d\n", rayCluster.Status.MaxWorkerReplicas) + + w.Write(IndentLevelZero, "Head Group:\n") + headGroupWriter := describehelper.NewNestedPrefixWriter(w, 1) + printLabelsMultiline(headGroupWriter, "Start Params", rayCluster.Spec.HeadGroupSpec.RayStartParams) + describePodTemplate(&rayCluster.Spec.HeadGroupSpec.Template, headGroupWriter) + + w.Write(IndentLevelZero, "Worker Groups:\n") + for _, wg := range rayCluster.Spec.WorkerGroupSpecs { + w.Write(IndentLevelOne, fmt.Sprintf("%s:\n", wg.GroupName)) + workerGroupWriter := describehelper.NewNestedPrefixWriter(w, 2) + if wg.Replicas != nil { + workerGroupWriter.Write(IndentLevelZero, "Replicas:\t%d\n", *wg.Replicas) + } + if wg.MinReplicas != nil { + workerGroupWriter.Write(IndentLevelZero, "Min Replicas:\t%d\n", *wg.MinReplicas) + } + if wg.MaxReplicas != nil { + workerGroupWriter.Write(IndentLevelZero, "Max Replicas:\t%d\n", *wg.MaxReplicas) + } + printLabelsMultiline(workerGroupWriter, "Start Params", wg.RayStartParams) + describePodTemplate(&wg.Template, workerGroupWriter) + } + + return nil + }) +} diff --git a/cmd/experimental/kjobctl/pkg/cmd/describe/describe_test.go b/cmd/experimental/kjobctl/pkg/cmd/describe/describe_test.go index 9f9458b63e..f5e5630fa2 100644 --- a/cmd/experimental/kjobctl/pkg/cmd/describe/describe_test.go +++ b/cmd/experimental/kjobctl/pkg/cmd/describe/describe_test.go @@ -328,6 +328,109 @@ Ray Cluster Status: Desired GPU: 0 Desired Memory: 0 Desired TPU: 0 +`, + }, + "describe ray cluster with 'mode task' format": { + args: []string{"raycluster", "sample-ray-cluster"}, + argsFormat: modeTaskArgsFormat, + mapperKinds: []schema.GroupVersionKind{ + rayv1.SchemeGroupVersion.WithKind("RayCluster"), + }, + objs: []runtime.Object{ + wrappers.MakeRayCluster("sample-ray-job", metav1.NamespaceDefault). + Profile("my-profile"). + LocalQueue("lq"). + State(rayv1.Failed). + Reason("Reason message"). + DesiredCPU(apiresource.MustParse("1")). + DesiredGPU(apiresource.MustParse("5")). + DesiredMemory(apiresource.MustParse("2Gi")). + DesiredTPU(apiresource.MustParse("10")). + ReadyWorkerReplicas(1). + AvailableWorkerReplicas(1). + DesiredWorkerReplicas(1). + MinWorkerReplicas(1). + MaxWorkerReplicas(5). + Spec( + *wrappers.MakeRayClusterSpec(). + HeadGroupSpec(rayv1.HeadGroupSpec{ + RayStartParams: map[string]string{"p1": "v1", "p2": "v2"}, + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + *wrappers.MakeContainer("ray-head", "rayproject/ray:2.9.0"). + WithEnvVar(corev1.EnvVar{Name: "TASK_NAME", Value: "sample-interactive"}). + WithVolumeMount(corev1.VolumeMount{Name: "sample-volume", MountPath: "/sample"}). + Obj(), + }, + }, + }, + }). + WithWorkerGroupSpec( + *wrappers.MakeWorkerGroupSpec("group1"). + Replicas(1). + MinReplicas(1). + MaxReplicas(5). + RayStartParams(map[string]string{"p1": "v1", "p2": "v2"}). + WithContainer( + *wrappers.MakeContainer("ray-worker", "rayproject/ray:2.9.0"). + WithEnvVar(corev1.EnvVar{Name: "TASK_NAME", Value: "sample-interactive"}). + WithVolumeMount(corev1.VolumeMount{Name: "sample-volume", MountPath: "/sample"}). + Obj(), + ). + Obj(), + ). + Suspend(true). + Obj(), + ). + Obj(), + }, + wantOut: `Name: sample-ray-job +Namespace: default +Labels: kjobctl.x-k8s.io/profile=my-profile + kueue.x-k8s.io/queue-name=lq +Suspend: true +State: failed +Reason: Reason message +Desired CPU: 1 +Desired GPU: 5 +Desired Memory: 2Gi +Desired TPU: 10 +Ready Worker Replicas: 1 +Available Worker Replicas: 1 +Desired Worker Replicas: 1 +Min Worker Replicas: 1 +Max Worker Replicas: 5 +Head Group: + Start Params: p1=v1 + p2=v2 + Pod Template: + Containers: + ray-head: + Port: + Host Port: + Environment: + TASK_NAME: sample-interactive + Mounts: + /sample from sample-volume (rw) + Volumes: +Worker Groups: + group1: + Replicas: 1 + Min Replicas: 1 + Max Replicas: 5 + Start Params: p1=v1 + p2=v2 + Pod Template: + Containers: + ray-worker: + Port: + Host Port: + Environment: + TASK_NAME: sample-interactive + Mounts: + /sample from sample-volume (rw) + Volumes: `, }, } diff --git a/cmd/experimental/kjobctl/pkg/testing/wrappers/ray_cluster_spec_wrapper.go b/cmd/experimental/kjobctl/pkg/testing/wrappers/ray_cluster_spec_wrapper.go index 4be5a187c9..1d24779873 100644 --- a/cmd/experimental/kjobctl/pkg/testing/wrappers/ray_cluster_spec_wrapper.go +++ b/cmd/experimental/kjobctl/pkg/testing/wrappers/ray_cluster_spec_wrapper.go @@ -19,6 +19,7 @@ package wrappers import ( rayv1 "github.com/ray-project/kuberay/ray-operator/apis/ray/v1" corev1 "k8s.io/api/core/v1" + "k8s.io/utils/ptr" ) // RayClusterSpecWrapper wraps a RayClusterSpec. @@ -183,3 +184,9 @@ func (w *RayClusterSpecWrapper) MaxReplicas(groupName string, maxReplicas int32) return w } + +// Suspend set suspend. +func (w *RayClusterSpecWrapper) Suspend(suspend bool) *RayClusterSpecWrapper { + w.RayClusterSpec.Suspend = ptr.To(suspend) + return w +} diff --git a/cmd/experimental/kjobctl/pkg/testing/wrappers/ray_cluster_wrappers.go b/cmd/experimental/kjobctl/pkg/testing/wrappers/ray_cluster_wrappers.go index 48cbcc2e1e..6e6cf402f0 100644 --- a/cmd/experimental/kjobctl/pkg/testing/wrappers/ray_cluster_wrappers.go +++ b/cmd/experimental/kjobctl/pkg/testing/wrappers/ray_cluster_wrappers.go @@ -112,6 +112,12 @@ func (j *RayClusterWrapper) DesiredWorkerReplicas(desiredWorkerReplicas int32) * return j } +// ReadyWorkerReplicas set ReadyWorkerReplicas. +func (j *RayClusterWrapper) ReadyWorkerReplicas(readyWorkerReplicas int32) *RayClusterWrapper { + j.RayCluster.Status.ReadyWorkerReplicas = readyWorkerReplicas + return j +} + // AvailableWorkerReplicas set AvailableWorkerReplicas. func (j *RayClusterWrapper) AvailableWorkerReplicas(availableWorkerReplicas int32) *RayClusterWrapper { j.RayCluster.Status.AvailableWorkerReplicas = availableWorkerReplicas @@ -136,8 +142,32 @@ func (j *RayClusterWrapper) DesiredGPU(desiredGPU resource.Quantity) *RayCluster return j } +// DesiredTPU set DesiredTPU. +func (j *RayClusterWrapper) DesiredTPU(desiredTPU resource.Quantity) *RayClusterWrapper { + j.RayCluster.Status.DesiredTPU = desiredTPU + return j +} + +// MinWorkerReplicas set MinWorkerReplicas. +func (j *RayClusterWrapper) MinWorkerReplicas(minWorkerReplicas int32) *RayClusterWrapper { + j.RayCluster.Status.MinWorkerReplicas = minWorkerReplicas + return j +} + +// MaxWorkerReplicas set MaxWorkerReplicas. +func (j *RayClusterWrapper) MaxWorkerReplicas(maxWorkerReplicas int32) *RayClusterWrapper { + j.RayCluster.Status.MaxWorkerReplicas = maxWorkerReplicas + return j +} + // State set State. func (j *RayClusterWrapper) State(state rayv1.ClusterState) *RayClusterWrapper { j.RayCluster.Status.State = state return j } + +// Reason set Reason. +func (j *RayClusterWrapper) Reason(reason string) *RayClusterWrapper { + j.RayCluster.Status.Reason = reason + return j +} diff --git a/cmd/experimental/kjobctl/pkg/testing/wrappers/worker_group_spec_wrapper.go b/cmd/experimental/kjobctl/pkg/testing/wrappers/worker_group_spec_wrapper.go index 88b8d7c8e7..23f4c3dd39 100644 --- a/cmd/experimental/kjobctl/pkg/testing/wrappers/worker_group_spec_wrapper.go +++ b/cmd/experimental/kjobctl/pkg/testing/wrappers/worker_group_spec_wrapper.go @@ -86,3 +86,9 @@ func (w *WorkerGroupSpecWrapper) MaxReplicas(maxReplicas int32) *WorkerGroupSpec w.WorkerGroupSpec.MaxReplicas = &maxReplicas return w } + +// RayStartParams set rayStartParams on WorkerGroupSpec. +func (w *WorkerGroupSpecWrapper) RayStartParams(rayStartParams map[string]string) *WorkerGroupSpecWrapper { + w.WorkerGroupSpec.RayStartParams = rayStartParams + return w +} From 5db516f8076502ac721961742c59e66e9ad08b6d Mon Sep 17 00:00:00 2001 From: Mykhailo Bobrovskyi Date: Thu, 5 Sep 2024 19:33:58 +0300 Subject: [PATCH 011/155] Increase the timeout for waiting for zero pending workloads. (#2999) --- test/e2e/singlecluster/visibility_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/singlecluster/visibility_test.go b/test/e2e/singlecluster/visibility_test.go index a6c8035ab2..3fce2a1f0f 100644 --- a/test/e2e/singlecluster/visibility_test.go +++ b/test/e2e/singlecluster/visibility_test.go @@ -183,7 +183,7 @@ var _ = ginkgo.Describe("Kueue visibility server", func() { info, err := visibilityClient.ClusterQueues().GetPendingWorkloadsSummary(ctx, clusterQueue.Name, metav1.GetOptions{}) gomega.Expect(err).NotTo(gomega.HaveOccurred()) return info.Items - }, util.Timeout, util.Interval).Should(gomega.BeEmpty()) + }, util.LongTimeout, util.Interval).Should(gomega.BeEmpty()) }) }) From 014762081c4882768759d0618aa6bc18e5950d65 Mon Sep 17 00:00:00 2001 From: Alay Patel Date: Thu, 5 Sep 2024 14:32:59 -0400 Subject: [PATCH 012/155] import deployment package in jobs.go to register the deployment webhook (#2988) * import deployment package in jobs.go to register the deployment webhook * Add GVK to IntegrationCallbacks struct for fixing panicking unit test Signed-off-by: Alay Patel --------- Signed-off-by: Alay Patel --- charts/kueue/templates/webhook/webhook.yaml | 78 +++++++++---------- cmd/kueuectl/app/list/list_pods.go | 3 + config/components/webhook/manifests.yaml | 78 +++++++++---------- .../jobframework/integrationmanager.go | 13 +++- .../jobs/deployment/deployment_controller.go | 1 + pkg/controller/jobs/jobs.go | 1 + 6 files changed, 95 insertions(+), 79 deletions(-) diff --git a/charts/kueue/templates/webhook/webhook.yaml b/charts/kueue/templates/webhook/webhook.yaml index dcae76f14e..4e3bfa9189 100644 --- a/charts/kueue/templates/webhook/webhook.yaml +++ b/charts/kueue/templates/webhook/webhook.yaml @@ -11,6 +11,25 @@ metadata: {{- end }} namespace: '{{ .Release.Namespace }}' webhooks: + - admissionReviewVersions: + - v1 + clientConfig: + service: + name: '{{ include "kueue.fullname" . }}-webhook-service' + namespace: '{{ .Release.Namespace }}' + path: /mutate-apps-v1-deployment + failurePolicy: Fail + name: mdeployment.kb.io + rules: + - apiGroups: + - apps + apiVersions: + - v1 + operations: + - CREATE + resources: + - deployments + sideEffects: None - admissionReviewVersions: - v1 clientConfig: @@ -235,25 +254,6 @@ webhooks: resources: - rayjobs sideEffects: None - - admissionReviewVersions: - - v1 - clientConfig: - service: - name: '{{ include "kueue.fullname" . }}-webhook-service' - namespace: '{{ .Release.Namespace }}' - path: /mutate-apps-v1-deployment - failurePolicy: Fail - name: mdeployment.kb.io - rules: - - apiGroups: - - apps - apiVersions: - - v1 - operations: - - CREATE - resources: - - deployments - sideEffects: None - admissionReviewVersions: - v1 clientConfig: @@ -324,6 +324,26 @@ metadata: {{- end }} namespace: '{{ .Release.Namespace }}' webhooks: + - admissionReviewVersions: + - v1 + clientConfig: + service: + name: '{{ include "kueue.fullname" . }}-webhook-service' + namespace: '{{ .Release.Namespace }}' + path: /validate-apps-v1-deployment + failurePolicy: Fail + name: vdeployment.kb.io + rules: + - apiGroups: + - apps + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - deployments + sideEffects: None - admissionReviewVersions: - v1 clientConfig: @@ -559,26 +579,6 @@ webhooks: resources: - rayjobs sideEffects: None - - admissionReviewVersions: - - v1 - clientConfig: - service: - name: '{{ include "kueue.fullname" . }}-webhook-service' - namespace: '{{ .Release.Namespace }}' - path: /validate-apps-v1-deployment - failurePolicy: Fail - name: vdeployment.kb.io - rules: - - apiGroups: - - apps - apiVersions: - - v1 - operations: - - CREATE - - UPDATE - resources: - - deployments - sideEffects: None - admissionReviewVersions: - v1 clientConfig: diff --git a/cmd/kueuectl/app/list/list_pods.go b/cmd/kueuectl/app/list/list_pods.go index 532cad7c95..027b11437d 100644 --- a/cmd/kueuectl/app/list/list_pods.go +++ b/cmd/kueuectl/app/list/list_pods.go @@ -228,6 +228,9 @@ func (o *PodOptions) getPodLabelSelector() (string, error) { return "", nil } + if cbs.NewJob == nil { + return "", nil + } genericJob := cbs.NewJob() jobWithPodLabelSelector, ok := genericJob.(jobframework.JobWithPodLabelSelector) diff --git a/config/components/webhook/manifests.yaml b/config/components/webhook/manifests.yaml index 37ec2afb5e..f539fb5bb6 100644 --- a/config/components/webhook/manifests.yaml +++ b/config/components/webhook/manifests.yaml @@ -4,6 +4,25 @@ kind: MutatingWebhookConfiguration metadata: name: mutating-webhook-configuration webhooks: +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /mutate-apps-v1-deployment + failurePolicy: Fail + name: mdeployment.kb.io + rules: + - apiGroups: + - apps + apiVersions: + - v1 + operations: + - CREATE + resources: + - deployments + sideEffects: None - admissionReviewVersions: - v1 clientConfig: @@ -213,25 +232,6 @@ webhooks: resources: - rayjobs sideEffects: None -- admissionReviewVersions: - - v1 - clientConfig: - service: - name: webhook-service - namespace: system - path: /mutate-apps-v1-deployment - failurePolicy: Fail - name: mdeployment.kb.io - rules: - - apiGroups: - - apps - apiVersions: - - v1 - operations: - - CREATE - resources: - - deployments - sideEffects: None - admissionReviewVersions: - v1 clientConfig: @@ -295,6 +295,26 @@ kind: ValidatingWebhookConfiguration metadata: name: validating-webhook-configuration webhooks: +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-apps-v1-deployment + failurePolicy: Fail + name: vdeployment.kb.io + rules: + - apiGroups: + - apps + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - deployments + sideEffects: None - admissionReviewVersions: - v1 clientConfig: @@ -515,26 +535,6 @@ webhooks: resources: - rayjobs sideEffects: None -- admissionReviewVersions: - - v1 - clientConfig: - service: - name: webhook-service - namespace: system - path: /validate-apps-v1-deployment - failurePolicy: Fail - name: vdeployment.kb.io - rules: - - apiGroups: - - apps - apiVersions: - - v1 - operations: - - CREATE - - UPDATE - resources: - - deployments - sideEffects: None - admissionReviewVersions: - v1 clientConfig: diff --git a/pkg/controller/jobframework/integrationmanager.go b/pkg/controller/jobframework/integrationmanager.go index d08b1c1030..8d703f95ea 100644 --- a/pkg/controller/jobframework/integrationmanager.go +++ b/pkg/controller/jobframework/integrationmanager.go @@ -56,6 +56,9 @@ type ReconcilerFactory func(client client.Client, record record.EventRecorder, o type IntegrationCallbacks struct { // NewJob creates a new instance of job NewJob func() GenericJob + // GVK holds the schema information for the job + // (this callback is optional) + GVK schema.GroupVersionKind // NewReconciler creates a new reconciler NewReconciler ReconcilerFactory // SetupWebhook sets up the framework's webhook with the controllers manager @@ -265,13 +268,21 @@ func GetIntegration(name string) (IntegrationCallbacks, bool) { func GetIntegrationByGVK(gvk schema.GroupVersionKind) (IntegrationCallbacks, bool) { for _, name := range manager.getList() { integration, ok := GetIntegration(name) - if ok && gvk == integration.NewJob().GVK() { + if ok && matchingGVK(integration, gvk) { return integration, true } } return IntegrationCallbacks{}, false } +func matchingGVK(integration IntegrationCallbacks, gvk schema.GroupVersionKind) bool { + if integration.NewJob != nil { + return gvk == integration.NewJob().GVK() + } else { + return gvk == integration.GVK + } +} + // GetIntegrationsList returns the list of currently registered frameworks. func GetIntegrationsList() []string { return manager.getList() diff --git a/pkg/controller/jobs/deployment/deployment_controller.go b/pkg/controller/jobs/deployment/deployment_controller.go index 7dc50eff3f..df3a139305 100644 --- a/pkg/controller/jobs/deployment/deployment_controller.go +++ b/pkg/controller/jobs/deployment/deployment_controller.go @@ -40,6 +40,7 @@ func init() { utilruntime.Must(jobframework.RegisterIntegration(FrameworkName, jobframework.IntegrationCallbacks{ SetupIndexes: SetupIndexes, NewReconciler: jobframework.NewNoopReconcilerFactory(gvk), + GVK: gvk, SetupWebhook: SetupWebhook, JobType: &appsv1.Deployment{}, AddToScheme: appsv1.AddToScheme, diff --git a/pkg/controller/jobs/jobs.go b/pkg/controller/jobs/jobs.go index c2b075050b..ba6c0ccc45 100644 --- a/pkg/controller/jobs/jobs.go +++ b/pkg/controller/jobs/jobs.go @@ -18,6 +18,7 @@ package jobs // Reference the job framework integration packages to ensure linking. import ( + _ "sigs.k8s.io/kueue/pkg/controller/jobs/deployment" _ "sigs.k8s.io/kueue/pkg/controller/jobs/job" _ "sigs.k8s.io/kueue/pkg/controller/jobs/jobset" _ "sigs.k8s.io/kueue/pkg/controller/jobs/kubeflow/jobs" From 01b6b096f3b85fa002a887ccaa926a01184e3b9c Mon Sep 17 00:00:00 2001 From: gabesaba <15304068+gabesaba@users.noreply.github.com> Date: Fri, 6 Sep 2024 10:50:10 +0200 Subject: [PATCH 013/155] Support Hierarchical Cohorts in hierarchy.Manager (#3000) --- pkg/cache/cache.go | 4 +- pkg/cache/snapshot.go | 9 +- pkg/hierarchy/cohort.go | 35 +++++-- pkg/hierarchy/manager.go | 68 ++++++++++--- pkg/hierarchy/manager_test.go | 176 +++++++++++++++++++++++++++------- 5 files changed, 229 insertions(+), 63 deletions(-) diff --git a/pkg/cache/cache.go b/pkg/cache/cache.go index f431e80704..900aac632a 100644 --- a/pkg/cache/cache.go +++ b/pkg/cache/cache.go @@ -401,8 +401,8 @@ func (c *Cache) DeleteClusterQueue(cq *kueue.ClusterQueue) { func (c *Cache) AddCohort(apiCohort *kueuealpha.Cohort) { c.Lock() defer c.Unlock() - cohort := newCohort(apiCohort.Name) - c.hm.AddCohort(cohort) + c.hm.AddCohort(apiCohort.Name) + cohort := c.hm.Cohorts[apiCohort.Name] cohort.updateCohort(apiCohort) } diff --git a/pkg/cache/snapshot.go b/pkg/cache/snapshot.go index 43cf225546..0a2a9a3e28 100644 --- a/pkg/cache/snapshot.go +++ b/pkg/cache/snapshot.go @@ -85,7 +85,8 @@ func (c *Cache) Snapshot() Snapshot { InactiveClusterQueueSets: sets.New[string](), } for _, cohort := range c.hm.Cohorts { - snap.AddCohort(snapshotCohort(cohort)) + snap.AddCohort(cohort.Name) + snap.Cohorts[cohort.Name].ResourceNode = cohort.resourceNode.Clone() } for _, cq := range c.hm.ClusterQueues { if !cq.Active() { @@ -126,12 +127,6 @@ func snapshotClusterQueue(c *clusterQueue) *ClusterQueueSnapshot { return cc } -func snapshotCohort(c *cohort) *CohortSnapshot { - snapshot := newCohortSnapshot(c.Name) - snapshot.ResourceNode = c.resourceNode.Clone() - return snapshot -} - func newCohortSnapshot(name string) *CohortSnapshot { return &CohortSnapshot{ Name: name, diff --git a/pkg/hierarchy/cohort.go b/pkg/hierarchy/cohort.go index 15d0ce91b2..c5c35209c8 100644 --- a/pkg/hierarchy/cohort.go +++ b/pkg/hierarchy/cohort.go @@ -19,31 +19,52 @@ package hierarchy import "k8s.io/apimachinery/pkg/util/sets" type Cohort[CQ, C nodeBase] struct { - childCqs sets.Set[CQ] + parent C + childCohorts sets.Set[C] + childCqs sets.Set[CQ] // Indicates whether this Cohort is backed // by an API object. explicit bool } func (c *Cohort[CQ, C]) Parent() C { - var zero C - return zero + return c.parent } func (c *Cohort[CQ, C]) HasParent() bool { - return false + var zero C + return c.Parent() != zero } func (c *Cohort[CQ, C]) ChildCQs() []CQ { return c.childCqs.UnsortedList() } +func (c *Cohort[CQ, C]) ChildCohorts() []C { + return c.childCohorts.UnsortedList() +} + func NewCohort[CQ, C nodeBase]() Cohort[CQ, C] { - return Cohort[CQ, C]{childCqs: sets.New[CQ]()} + return Cohort[CQ, C]{ + childCohorts: sets.New[C](), + childCqs: sets.New[CQ](), + } } // implement cohortNode interface +func (c *Cohort[CQ, C]) setParent(cohort C) { + c.parent = cohort +} + +func (c *Cohort[CQ, C]) insertCohortChild(cohort C) { + c.childCohorts.Insert(cohort) +} + +func (c *Cohort[CQ, C]) deleteCohortChild(cohort C) { + c.childCohorts.Delete(cohort) +} + func (c *Cohort[CQ, C]) insertClusterQueue(cq CQ) { c.childCqs.Insert(cq) } @@ -52,8 +73,8 @@ func (c *Cohort[CQ, C]) deleteClusterQueue(cq CQ) { c.childCqs.Delete(cq) } -func (c *Cohort[CQ, C]) childCount() int { - return c.childCqs.Len() +func (c *Cohort[CQ, C]) hasChildren() bool { + return c.childCqs.Len()+c.childCohorts.Len() > 0 } func (c *Cohort[CQ, C]) isExplicit() bool { diff --git a/pkg/hierarchy/manager.go b/pkg/hierarchy/manager.go index b7b4f29406..f1da7cc878 100644 --- a/pkg/hierarchy/manager.go +++ b/pkg/hierarchy/manager.go @@ -18,7 +18,7 @@ package hierarchy // Manager stores Cohorts and ClusterQueues, and maintains the edges // between them. -type Manager[CQ clusterQueueNode[C], C cohortNode[CQ]] struct { +type Manager[CQ clusterQueueNode[C], C cohortNode[CQ, C]] struct { Cohorts map[string]C ClusterQueues map[string]CQ cohortFactory func(string) C @@ -27,7 +27,7 @@ type Manager[CQ clusterQueueNode[C], C cohortNode[CQ]] struct { // NewManager creates a new Manager. A newCohort function must // be provided to instantiate Cohorts in the case that a // ClusterQueue references a Cohort not backed by an API object. -func NewManager[CQ clusterQueueNode[C], C cohortNode[CQ]](newCohort func(string) C) Manager[CQ, C] { +func NewManager[CQ clusterQueueNode[C], C cohortNode[CQ, C]](newCohort func(string) C) Manager[CQ, C] { return Manager[CQ, C]{ make(map[string]C), make(map[string]CQ), @@ -56,32 +56,53 @@ func (c *Manager[CQ, C]) DeleteClusterQueue(name string) { } } -func (c *Manager[CQ, C]) AddCohort(cohort C) { - cohort.markExplicit() - if oldCohort, ok := c.Cohorts[cohort.GetName()]; ok { - c.rewireChildren(oldCohort, cohort) +func (c *Manager[CQ, C]) AddCohort(cohortName string) { + oldCohort, ok := c.Cohorts[cohortName] + if ok && oldCohort.isExplicit() { + return + } + if !ok { + c.Cohorts[cohortName] = c.cohortFactory(cohortName) + } + c.Cohorts[cohortName].markExplicit() +} + +func (c *Manager[CQ, C]) UpdateCohortEdge(name, parentName string) { + cohort := c.Cohorts[name] + c.detachCohortFromParent(cohort) + if parentName != "" { + parent := c.getOrCreateCohort(parentName) + parent.insertCohortChild(cohort) + cohort.setParent(parent) } - c.Cohorts[cohort.GetName()] = cohort } func (c *Manager[CQ, C]) DeleteCohort(name string) { cohort, ok := c.Cohorts[name] + if !ok { + return + } delete(c.Cohorts, name) - if !ok || cohort.childCount() == 0 { + c.detachCohortFromParent(cohort) + if !cohort.hasChildren() { return } implicitCohort := c.cohortFactory(name) c.Cohorts[implicitCohort.GetName()] = implicitCohort - c.rewireChildren(cohort, implicitCohort) + c.transferChildren(cohort, implicitCohort) } -// rewireChildren is used when we are changing a Cohort -// from an implicit to an explicit Cohort, or vice-versa. -func (c *Manager[CQ, C]) rewireChildren(old, new C) { +// transferChildren is used when we are changing a Cohort +// from an explicit to an implicit Cohort. +func (c *Manager[CQ, C]) transferChildren(old, new C) { for _, cq := range old.ChildCQs() { cq.setParent(new) new.insertClusterQueue(cq) } + for _, childCohort := range old.ChildCohorts() { + childCohort.setParent(new) + new.insertCohortChild(childCohort) + } } func (c *Manager[CQ, C]) unwireClusterQueue(cq CQ) { @@ -94,6 +115,16 @@ func (c *Manager[CQ, C]) unwireClusterQueue(cq CQ) { } } +func (c *Manager[CQ, C]) detachCohortFromParent(cohort C) { + if cohort.HasParent() { + parent := cohort.Parent() + parent.deleteCohortChild(cohort) + c.cleanupCohort(parent) + var zero C + cohort.setParent(zero) + } +} + func (c *Manager[CQ, C]) getOrCreateCohort(cohortName string) C { if _, ok := c.Cohorts[cohortName]; !ok { c.Cohorts[cohortName] = c.cohortFactory(cohortName) @@ -102,7 +133,7 @@ func (c *Manager[CQ, C]) getOrCreateCohort(cohortName string) C { } func (c *Manager[CQ, C]) cleanupCohort(cohort C) { - if !cohort.isExplicit() && cohort.childCount() == 0 { + if !cohort.isExplicit() && !cohort.hasChildren() { delete(c.Cohorts, cohort.GetName()) } } @@ -119,10 +150,17 @@ type clusterQueueNode[C nodeBase] interface { nodeBase } -type cohortNode[CQ nodeBase] interface { +type cohortNode[CQ, C nodeBase] interface { + Parent() C + HasParent() bool + setParent(C) + insertCohortChild(C) + deleteCohortChild(C) + ChildCohorts() []C + insertClusterQueue(CQ) deleteClusterQueue(CQ) - childCount() int + hasChildren() bool ChildCQs() []CQ isExplicit() bool markExplicit() diff --git a/pkg/hierarchy/manager_test.go b/pkg/hierarchy/manager_test.go index 3c902fcac0..5f6ca71ffd 100644 --- a/pkg/hierarchy/manager_test.go +++ b/pkg/hierarchy/manager_test.go @@ -26,22 +26,23 @@ import ( func TestManager(t *testing.T) { type M = Manager[*testClusterQueue, *testCohort] - type cqEdge struct { - cq string - cohort string + type edge struct { + child string + parent string } opts := []cmp.Option{ cmpopts.EquateEmpty(), - cmpopts.SortSlices(func(a, b cqEdge) bool { - return a.cq < b.cq + cmpopts.SortSlices(func(a, b edge) bool { + return a.child < b.child }), - cmp.AllowUnexported(cqEdge{}), + cmp.AllowUnexported(edge{}), } tests := map[string]struct { - operations func(M) - wantCqs sets.Set[string] - wantCohorts sets.Set[string] - wantCqEdge []cqEdge + operations func(M) + wantCqs sets.Set[string] + wantCohorts sets.Set[string] + wantCqEdge []edge + wantCohortEdge []edge }{ "create queues": { operations: func(m M) { @@ -77,7 +78,7 @@ func TestManager(t *testing.T) { "cohort-a", "cohort-b", ), - wantCqEdge: []cqEdge{ + wantCqEdge: []edge{ {"queue1", "cohort-a"}, {"queue2", "cohort-a"}, {"queue3", "cohort-b"}, @@ -95,12 +96,12 @@ func TestManager(t *testing.T) { }, wantCqs: sets.New("queue1", "queue2"), wantCohorts: sets.New("cohort-b", "cohort-c"), - wantCqEdge: []cqEdge{ + wantCqEdge: []edge{ {"queue1", "cohort-b"}, {"queue2", "cohort-c"}, }, }, - "updating idempotent": { + "updating cqs idempotent": { operations: func(m M) { m.AddClusterQueue(newCq("queue1")) m.AddClusterQueue(newCq("queue2")) @@ -111,16 +112,31 @@ func TestManager(t *testing.T) { m.UpdateClusterQueueEdge("queue2", "cohort-c") m.UpdateClusterQueueEdge("queue1", "cohort-b") m.UpdateClusterQueueEdge("queue2", "cohort-c") - m.UpdateClusterQueueEdge("queue2", "cohort-c") - m.UpdateClusterQueueEdge("queue1", "cohort-b") }, wantCqs: sets.New("queue1", "queue2"), wantCohorts: sets.New("cohort-b", "cohort-c"), - wantCqEdge: []cqEdge{ + wantCqEdge: []edge{ {"queue1", "cohort-b"}, {"queue2", "cohort-c"}, }, }, + "updating cohort idempotent": { + operations: func(m M) { + m.AddCohort("cohort") + m.UpdateCohortEdge("cohort", "root") + m.UpdateCohortEdge("cohort", "newroot") + m.UpdateCohortEdge("cohort", "newroot") + }, + wantCohorts: sets.New("cohort", "newroot"), + wantCohortEdge: []edge{{"cohort", "newroot"}}, + }, + "adding cohort idempotent": { + operations: func(m M) { + m.AddCohort("cohort") + m.AddCohort("cohort") + }, + wantCohorts: sets.New("cohort"), + }, "delete cohorts": { operations: func(m M) { m.AddClusterQueue(newCq("queue1")) @@ -150,7 +166,7 @@ func TestManager(t *testing.T) { }, wantCqs: sets.New[string](), }, - "cohort remains as long as one of its children remains": { + "cohort remains as long as one of its child cqs remains": { operations: func(m M) { m.AddClusterQueue(newCq("queue1")) m.AddClusterQueue(newCq("queue2")) @@ -164,17 +180,31 @@ func TestManager(t *testing.T) { }, wantCqs: sets.New("queue1"), wantCohorts: sets.New("cohort"), - wantCqEdge: []cqEdge{{"queue1", "cohort"}}, + wantCqEdge: []edge{{"queue1", "cohort"}}, + }, + "cohort remains as long as one of its child cohorts remains": { + operations: func(m M) { + m.AddCohort("cohort1") + m.AddCohort("cohort2") + m.AddCohort("cohort3") + m.UpdateCohortEdge("cohort1", "root") + m.UpdateCohortEdge("cohort2", "root") + m.UpdateCohortEdge("cohort3", "root") + m.DeleteCohort("cohort2") + m.DeleteCohort("cohort3") + }, + wantCohorts: sets.New("cohort1", "root"), + wantCohortEdge: []edge{{"cohort1", "root"}}, }, "explicit cohort": { operations: func(m M) { - m.AddCohort(newCohort("cohort")) + m.AddCohort("cohort") }, wantCohorts: sets.New("cohort"), }, "delete explicit cohort": { operations: func(m M) { - m.AddCohort(newCohort("cohort")) + m.AddCohort("cohort") m.DeleteCohort("cohort") }, wantCohorts: sets.New[string](), @@ -182,7 +212,7 @@ func TestManager(t *testing.T) { "delete explicit cohort idempotent": { operations: func(m M) { m.DeleteCohort("cohort") - m.AddCohort(newCohort("cohort")) + m.AddCohort("cohort") m.DeleteCohort("cohort") m.DeleteCohort("cohort") }, @@ -192,25 +222,25 @@ func TestManager(t *testing.T) { operations: func(m M) { m.AddClusterQueue(newCq("queue")) m.UpdateClusterQueueEdge("queue", "cohort") - m.AddCohort(newCohort("cohort")) + m.AddCohort("cohort") m.DeleteClusterQueue("queue") }, wantCohorts: sets.New("cohort"), }, "explicit cohort downgraded to implicit cohort": { operations: func(m M) { - m.AddCohort(newCohort("cohort")) + m.AddCohort("cohort") m.AddClusterQueue(newCq("queue")) m.UpdateClusterQueueEdge("queue", "cohort") m.DeleteCohort("cohort") }, wantCohorts: sets.New("cohort"), wantCqs: sets.New("queue"), - wantCqEdge: []cqEdge{{"queue", "cohort"}}, + wantCqEdge: []edge{{"queue", "cohort"}}, }, "cohort upgraded to explicit then downgraded to implicit then deleted": { operations: func(m M) { - m.AddCohort(newCohort("cohort")) + m.AddCohort("cohort") m.AddClusterQueue(newCq("queue")) m.UpdateClusterQueueEdge("queue", "cohort") m.DeleteCohort("cohort") @@ -218,7 +248,75 @@ func TestManager(t *testing.T) { }, wantCohorts: sets.New[string](), wantCqs: sets.New[string](), - wantCqEdge: []cqEdge{}, + wantCqEdge: []edge{}, + }, + "hierarchical cohorts": { + // root + // / \ + // left right + // / \ + // left-left right-right + operations: func(m M) { + m.AddCohort("root") + m.AddCohort("left") + m.AddCohort("right") + m.AddCohort("left-left") + m.AddCohort("right-right") + m.UpdateCohortEdge("left", "root") + m.UpdateCohortEdge("right", "root") + m.UpdateCohortEdge("left-left", "left") + m.UpdateCohortEdge("right-right", "right") + + m.AddClusterQueue(newCq("cq")) + m.UpdateClusterQueueEdge("cq", "right-right") + }, + wantCqs: sets.New("cq"), + wantCqEdge: []edge{ + {"cq", "right-right"}, + }, + wantCohorts: sets.New("root", "left", "right", "left-left", "right-right"), + wantCohortEdge: []edge{ + {"left", "root"}, + {"right", "root"}, + {"left-left", "left"}, + {"right-right", "right"}, + }, + }, + "delete node in middle of hierarchy": { + // Before: fully connected + // + // root + // / \ + // left right + // / \ + // left-left right-right + // + // After: left is an implicit Cohort + // + // root + // \ + // left right + // / \ + // left-left right-right + operations: func(m M) { + m.AddCohort("root") + m.AddCohort("left") + m.AddCohort("right") + m.AddCohort("left-left") + m.AddCohort("right-right") + m.UpdateCohortEdge("left", "root") + m.UpdateCohortEdge("right", "root") + m.UpdateCohortEdge("left-left", "left") + m.UpdateCohortEdge("right-right", "right") + + m.DeleteCohort("left") + }, + wantCohorts: sets.New("root", "left", "right", "left-left", "right-right"), + wantCohortEdge: []edge{ + {"right", "root"}, + {"left-left", "left"}, + {"right-right", "right"}, + }, }, } @@ -228,11 +326,11 @@ func TestManager(t *testing.T) { tc.operations(mgr) t.Run("verify clusterqueues", func(t *testing.T) { gotCqs := sets.New[string]() - gotEdges := make([]cqEdge, 0, len(tc.wantCqEdge)) + gotEdges := make([]edge, 0, len(tc.wantCqEdge)) for _, cq := range mgr.ClusterQueues { gotCqs.Insert(cq.GetName()) if cq.HasParent() { - gotEdges = append(gotEdges, cqEdge{cq.GetName(), cq.Parent().GetName()}) + gotEdges = append(gotEdges, edge{cq.GetName(), cq.Parent().GetName()}) } } if diff := cmp.Diff(tc.wantCqs, gotCqs); diff != "" { @@ -244,18 +342,32 @@ func TestManager(t *testing.T) { }) t.Run("verify cohorts", func(t *testing.T) { gotCohorts := sets.New[string]() - gotEdges := make([]cqEdge, 0, len(tc.wantCqEdge)) + gotCqEdges := make([]edge, 0, len(tc.wantCqEdge)) + gotCohortChildEdges := make([]edge, 0, len(tc.wantCohortEdge)) + gotCohortParentEdges := make([]edge, 0, len(tc.wantCohortEdge)) for _, cohort := range mgr.Cohorts { gotCohorts.Insert(cohort.GetName()) for _, cq := range cohort.ChildCQs() { - gotEdges = append(gotEdges, cqEdge{cq.GetName(), cohort.GetName()}) + gotCqEdges = append(gotCqEdges, edge{cq.GetName(), cohort.GetName()}) + } + for _, childCohort := range cohort.ChildCohorts() { + gotCohortChildEdges = append(gotCohortChildEdges, edge{childCohort.GetName(), cohort.GetName()}) + } + if cohort.HasParent() { + gotCohortParentEdges = append(gotCohortParentEdges, edge{cohort.GetName(), cohort.Parent().GetName()}) } } if diff := cmp.Diff(tc.wantCohorts, gotCohorts); diff != "" { t.Fatalf("Unexpected cohorts -want +got %s", diff) } - if diff := cmp.Diff(tc.wantCqEdge, gotEdges, opts...); diff != "" { - t.Fatalf("Unexpected Cohort->CQ edges -want +got %s", diff) + if diff := cmp.Diff(tc.wantCqEdge, gotCqEdges, opts...); diff != "" { + t.Fatalf("Unexpected CQ<-Cohort edges -want +got %s", diff) + } + if diff := cmp.Diff(tc.wantCohortEdge, gotCohortChildEdges, opts...); diff != "" { + t.Fatalf("Unexpected Cohort<-Cohort edges -want +got %s", diff) + } + if diff := cmp.Diff(tc.wantCohortEdge, gotCohortParentEdges, opts...); diff != "" { + t.Fatalf("Unexpected Cohort->Cohort edges -want +got %s", diff) } }) }) From 89d3ec1f9ec2254c04f3ea7e05dd669e32e71ba7 Mon Sep 17 00:00:00 2001 From: gabesaba <15304068+gabesaba@users.noreply.github.com> Date: Fri, 6 Sep 2024 11:20:23 +0200 Subject: [PATCH 014/155] Cleanup hierarchy.Manager (#3002) --- pkg/hierarchy/manager.go | 72 ++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/pkg/hierarchy/manager.go b/pkg/hierarchy/manager.go index f1da7cc878..f00f63b70d 100644 --- a/pkg/hierarchy/manager.go +++ b/pkg/hierarchy/manager.go @@ -35,66 +35,66 @@ func NewManager[CQ clusterQueueNode[C], C cohortNode[CQ, C]](newCohort func(stri } } -func (c *Manager[CQ, C]) AddClusterQueue(cq CQ) { - c.ClusterQueues[cq.GetName()] = cq +func (m *Manager[CQ, C]) AddClusterQueue(cq CQ) { + m.ClusterQueues[cq.GetName()] = cq } -func (c *Manager[CQ, C]) UpdateClusterQueueEdge(name, parentName string) { - cq := c.ClusterQueues[name] - c.unwireClusterQueue(cq) +func (m *Manager[CQ, C]) UpdateClusterQueueEdge(name, parentName string) { + cq := m.ClusterQueues[name] + m.detachClusterQueueFromParent(cq) if parentName != "" { - parent := c.getOrCreateCohort(parentName) + parent := m.getOrCreateCohort(parentName) parent.insertClusterQueue(cq) cq.setParent(parent) } } -func (c *Manager[CQ, C]) DeleteClusterQueue(name string) { - if cq, ok := c.ClusterQueues[name]; ok { - c.unwireClusterQueue(cq) - delete(c.ClusterQueues, name) +func (m *Manager[CQ, C]) DeleteClusterQueue(name string) { + if cq, ok := m.ClusterQueues[name]; ok { + m.detachClusterQueueFromParent(cq) + delete(m.ClusterQueues, name) } } -func (c *Manager[CQ, C]) AddCohort(cohortName string) { - oldCohort, ok := c.Cohorts[cohortName] +func (m *Manager[CQ, C]) AddCohort(cohortName string) { + oldCohort, ok := m.Cohorts[cohortName] if ok && oldCohort.isExplicit() { return } if !ok { - c.Cohorts[cohortName] = c.cohortFactory(cohortName) + m.Cohorts[cohortName] = m.cohortFactory(cohortName) } - c.Cohorts[cohortName].markExplicit() + m.Cohorts[cohortName].markExplicit() } -func (c *Manager[CQ, C]) UpdateCohortEdge(name, parentName string) { - cohort := c.Cohorts[name] - c.detachCohortFromParent(cohort) +func (m *Manager[CQ, C]) UpdateCohortEdge(name, parentName string) { + cohort := m.Cohorts[name] + m.detachCohortFromParent(cohort) if parentName != "" { - parent := c.getOrCreateCohort(parentName) + parent := m.getOrCreateCohort(parentName) parent.insertCohortChild(cohort) cohort.setParent(parent) } } -func (c *Manager[CQ, C]) DeleteCohort(name string) { - cohort, ok := c.Cohorts[name] +func (m *Manager[CQ, C]) DeleteCohort(name string) { + cohort, ok := m.Cohorts[name] if !ok { return } - delete(c.Cohorts, name) - c.detachCohortFromParent(cohort) + delete(m.Cohorts, name) + m.detachCohortFromParent(cohort) if !cohort.hasChildren() { return } - implicitCohort := c.cohortFactory(name) - c.Cohorts[implicitCohort.GetName()] = implicitCohort - c.transferChildren(cohort, implicitCohort) + implicitCohort := m.cohortFactory(name) + m.Cohorts[implicitCohort.GetName()] = implicitCohort + m.transferChildren(cohort, implicitCohort) } // transferChildren is used when we are changing a Cohort // from an explicit to an implicit Cohort. -func (c *Manager[CQ, C]) transferChildren(old, new C) { +func (m *Manager[CQ, C]) transferChildren(old, new C) { for _, cq := range old.ChildCQs() { cq.setParent(new) new.insertClusterQueue(cq) @@ -105,36 +105,36 @@ func (c *Manager[CQ, C]) transferChildren(old, new C) { } } -func (c *Manager[CQ, C]) unwireClusterQueue(cq CQ) { +func (m *Manager[CQ, C]) detachClusterQueueFromParent(cq CQ) { if cq.HasParent() { parent := cq.Parent() parent.deleteClusterQueue(cq) - c.cleanupCohort(parent) + m.cleanupCohort(parent) var zero C cq.setParent(zero) } } -func (c *Manager[CQ, C]) detachCohortFromParent(cohort C) { +func (m *Manager[CQ, C]) detachCohortFromParent(cohort C) { if cohort.HasParent() { parent := cohort.Parent() parent.deleteCohortChild(cohort) - c.cleanupCohort(parent) + m.cleanupCohort(parent) var zero C cohort.setParent(zero) } } -func (c *Manager[CQ, C]) getOrCreateCohort(cohortName string) C { - if _, ok := c.Cohorts[cohortName]; !ok { - c.Cohorts[cohortName] = c.cohortFactory(cohortName) +func (m *Manager[CQ, C]) getOrCreateCohort(cohortName string) C { + if _, ok := m.Cohorts[cohortName]; !ok { + m.Cohorts[cohortName] = m.cohortFactory(cohortName) } - return c.Cohorts[cohortName] + return m.Cohorts[cohortName] } -func (c *Manager[CQ, C]) cleanupCohort(cohort C) { +func (m *Manager[CQ, C]) cleanupCohort(cohort C) { if !cohort.isExplicit() && !cohort.hasChildren() { - delete(c.Cohorts, cohort.GetName()) + delete(m.Cohorts, cohort.GetName()) } } From 0051006dac638a173fbb130269f651fcfa88087b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Wo=C5=BAniak?= Date: Fri, 6 Sep 2024 16:47:43 +0200 Subject: [PATCH 015/155] Update latest version to v0.8.1 (#3007) --- CHANGELOG/CHANGELOG-0.8.md | 22 +++++++++++++++++++ Makefile | 2 +- README.md | 2 +- SECURITY-INSIGHTS.yaml | 12 +++++----- charts/kueue/Chart.yaml | 2 +- cmd/experimental/kjobctl/docs/installation.md | 2 +- site/hugo.toml | 2 +- 7 files changed, 33 insertions(+), 11 deletions(-) diff --git a/CHANGELOG/CHANGELOG-0.8.md b/CHANGELOG/CHANGELOG-0.8.md index 40c66b2199..27c1334b96 100644 --- a/CHANGELOG/CHANGELOG-0.8.md +++ b/CHANGELOG/CHANGELOG-0.8.md @@ -1,3 +1,25 @@ +## v0.8.1 + +Changes since `v0.8.0`: + +### Feature + +- Add gauge metric admission_cycle_preemption_skips that reports the number of Workloads in a ClusterQueue + that got preemptions candidates, but had to be skipped in the last cycle. (#2942, @alculquicondor) +- Publish images via artifact registry (#2832, @alculquicondor) + +### Bug or Regression + +- CLI: Support `-` and `.` in the resource flavor name on `create cq` (#2706, @trasc) +- Detect and enable support for job CRDs installed after Kueue starts. (#2991, @ChristianZaccaria) +- Fix over-admission after deleting resources from borrowing ClusterQueue. (#2879, @mbobrovskyi) +- Fix support for kuberay 1.2.x (#2983, @mbobrovskyi) +- Helm: Fix a bug for "unclosed action error". (#2688, @mbobrovskyi) +- Prevent infinite preemption loop when PrioritySortingWithinCohort=false + is used together with borrowWithinCohort. (#2831, @mimowo) +- Support for helm charts in the us-central1-docker.pkg.dev/k8s-staging-images/charts repository (#2834, @IrvingMg) +- Update Flavor selection logic to prefer Flavors which allow reclamation of lent nominal quota, over Flavors which require preempting workloads within the ClusterQueue. This matches the behavior in the single Flavor case. (#2829, @gabesaba) + ## v0.8.0 Changes since `v0.7.0`: diff --git a/Makefile b/Makefile index 1444ad9918..2e67d96e37 100644 --- a/Makefile +++ b/Makefile @@ -76,7 +76,7 @@ LD_FLAGS += -X '$(version_pkg).GitCommit=$(shell git rev-parse HEAD)' # Update these variables when preparing a new release or a release branch. # Then run `make prepare-release-branch` -RELEASE_VERSION=v0.8.0 +RELEASE_VERSION=v0.8.1 RELEASE_BRANCH=main .PHONY: all diff --git a/README.md b/README.md index 46e307b5c3..34d8020f52 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ Read the [overview](https://kueue.sigs.k8s.io/docs/overview/) to learn more. To install the latest release of Kueue in your cluster, run the following command: ```shell -kubectl apply --server-side -f https://github.com/kubernetes-sigs/kueue/releases/download/v0.8.0/manifests.yaml +kubectl apply --server-side -f https://github.com/kubernetes-sigs/kueue/releases/download/v0.8.1/manifests.yaml ``` The controller runs in the `kueue-system` namespace. diff --git a/SECURITY-INSIGHTS.yaml b/SECURITY-INSIGHTS.yaml index 0bb799439b..4126113178 100644 --- a/SECURITY-INSIGHTS.yaml +++ b/SECURITY-INSIGHTS.yaml @@ -1,11 +1,11 @@ header: schema-version: 1.0.0 expiration-date: '2024-09-28T01:00:00.000Z' - last-updated: '2024-07-19' - last-reviewed: '2024-07-19' - commit-hash: 58ef31e6ef674db0aa04cb587d41862570ad1d12 + last-updated: '2024-09-05' + last-reviewed: '2024-09-05' + commit-hash: 7cb1dfb41e178aeb0674e36c996e17c711325e89 project-url: 'https://github.com/kubernetes-sigs/kueue' - project-release: 0.8.0 + project-release: 0.8.1 changelog: 'https://github.com/kubernetes-sigs/kueue/tree/main/CHANGELOG' license: 'https://github.com/kubernetes-sigs/kueue/blob/main/LICENSE' project-lifecycle: @@ -28,7 +28,7 @@ documentation: - 'https://kueue.sigs.k8s.io/docs/' distribution-points: - >- - https://github.com/kubernetes-sigs/kueue/releases/download/v0.8.0/manifests.yaml + https://github.com/kubernetes-sigs/kueue/releases/download/v0.8.1/manifests.yaml security-artifacts: threat-model: threat-model-created: false @@ -62,5 +62,5 @@ dependencies: dependencies-lists: - 'https://github.com/kubernetes-sigs/kueue/blob/main/go.mod' sbom: - - sbom-file: https://github.com/kubernetes-sigs/kueue/releases/download/v0.8.0/kueue-v0.8.0.spdx.json + - sbom-file: https://github.com/kubernetes-sigs/kueue/releases/download/v0.8.1/kueue-v0.8.1.spdx.json sbom-format: SPDX diff --git a/charts/kueue/Chart.yaml b/charts/kueue/Chart.yaml index 61047ebf78..f18fd8fd1e 100644 --- a/charts/kueue/Chart.yaml +++ b/charts/kueue/Chart.yaml @@ -18,4 +18,4 @@ version: 0.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "v0.8.0" +appVersion: "v0.8.1" diff --git a/cmd/experimental/kjobctl/docs/installation.md b/cmd/experimental/kjobctl/docs/installation.md index 375321d512..5c9d87f38d 100644 --- a/cmd/experimental/kjobctl/docs/installation.md +++ b/cmd/experimental/kjobctl/docs/installation.md @@ -7,7 +7,7 @@ Installing the `kubectl-kjob` plugin, `kjobctl`. ### 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 +kubectl apply --server-side -f https://github.com/kubernetes-sigs/kueue/releases/download/v0.8.1/kubectl-kjob-manifests.yaml ``` ### 2. Download the latest release: diff --git a/site/hugo.toml b/site/hugo.toml index 978e8e5e98..a2656ecd41 100644 --- a/site/hugo.toml +++ b/site/hugo.toml @@ -90,7 +90,7 @@ ignoreFiles = [] # The major.minor version tag for the version of the docs represented in this # branch of the repository. Used in the "version-banner" partial to display a # version number for this doc set. - version = "v0.8.0" + version = "v0.8.1" # Flag used in the "version-banner" partial to decide whether to display a # banner on every page indicating that this is an archived version of the docs. From 196ee2a0891f5d03523514007824adfd5c91ae7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Wo=C5=BAniak?= Date: Fri, 6 Sep 2024 16:57:43 +0200 Subject: [PATCH 016/155] Update the new release steps (#3004) --- .github/ISSUE_TEMPLATE/NEW_RELEASE.md | 31 ++++++++++++++------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/NEW_RELEASE.md b/.github/ISSUE_TEMPLATE/NEW_RELEASE.md index 8b8e417a16..f54e219fe5 100644 --- a/.github/ISSUE_TEMPLATE/NEW_RELEASE.md +++ b/.github/ISSUE_TEMPLATE/NEW_RELEASE.md @@ -24,38 +24,39 @@ Please do not remove items from the checklist - [ ] Update `RELEASE_BRANCH` and `RELEASE_VERSION` in `Makefile` and run `make prepare-release-branch` - [ ] Update the `CHANGELOG` - [ ] Submit a pull request with the changes: -- [ ] An OWNER [prepares a draft release](https://github.com/kubernetes-sigs/kueue/releases) - - [ ] Write the change log into the draft release. - - [ ] Run - `make artifacts IMAGE_REGISTRY=registry.k8s.io/kueue GIT_TAG=$VERSION` - to generate the artifacts and upload the files in the `artifacts` folder - to the draft release. - [ ] An OWNER creates a signed tag running `git tag -s $VERSION` and inserts the changelog into the tag description. To perform this step, you need [a PGP key registered on github](https://docs.github.com/en/authentication/managing-commit-signature-verification/checking-for-existing-gpg-keys). - [ ] An OWNER pushes the tag with - `git push $VERSION` + `git push upstream $VERSION` - Triggers prow to build and publish a staging container image `us-central1-docker.pkg.dev/k8s-staging-images/kueue/kueue:$VERSION` +- [ ] An OWNER [prepares a draft release](https://github.com/kubernetes-sigs/kueue/releases) + - [ ] Create the draft release poiting out to the created tag. + - [ ] Write the change log into the draft release. + - [ ] Run + `make artifacts IMAGE_REGISTRY=registry.k8s.io/kueue GIT_TAG=$VERSION` + to generate the artifacts in the `artifacts` folder. + - [ ] Upload the files in the `artifacts` folder to the draft release - either + via UI or `gh release upload artifacts/*`. - [ ] 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) + [promote the container images](https://github.com/kubernetes/k8s.io/tree/main/registry.k8s.io#image-promoter) to production: - [ ] Wait for the PR to be merged and verify that the image `registry.k8s.io/kueue/kueue:$VERSION` is available. - [ ] Publish the draft release prepared at the [GitHub releases page](https://github.com/kubernetes-sigs/kueue/releases). Link: - [ ] Run the [openvex action](https://github.com/kubernetes-sigs/kueue/actions/workflows/openvex.yaml) to generate openvex data. The action will add the file to the release artifacts. +- [ ] Update the `main` branch : + - [ ] Update `RELEASE_VERSION` in `Makefile` and run `make prepare-release-branch` + - [ ] Release notes in the `CHANGELOG` + - [ ] `SECURITY-INSIGHTS.yaml` values by running `make update-security-insights GIT_TAG=$VERSION` + - [ ] Submit a pull request with the changes: + - [ ] Cherry-pick the pull request onto the `website` branch - [ ] Run the [SBOM action](https://github.com/kubernetes-sigs/kueue/actions/workflows/sbom.yaml) to generate the SBOM and add it to the release. - [ ] For major or minor releases, merge the `main` branch into the `website` branch to publish the updated documentation. - [ ] Send an announcement email to `sig-scheduling@kubernetes.io` and `wg-batch@kubernetes.io` with the subject `[ANNOUNCE] kueue $VERSION is released`. -- [ ] 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/hugo.toml` - - `appVersion` in `charts/kueue/Chart.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 From 7fed1235a645da375c332c470ecd4b9be6971322 Mon Sep 17 00:00:00 2001 From: Mykhailo Bobrovskyi Date: Fri, 6 Sep 2024 19:07:43 +0300 Subject: [PATCH 017/155] Use Note instead Warning on the LendingLimit is enabled by default info. (#3010) --- site/content/en/docs/concepts/cluster_queue.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/content/en/docs/concepts/cluster_queue.md b/site/content/en/docs/concepts/cluster_queue.md index 8dbad6eedc..fed3177654 100644 --- a/site/content/en/docs/concepts/cluster_queue.md +++ b/site/content/en/docs/concepts/cluster_queue.md @@ -359,7 +359,7 @@ you can set the `.spec.resourcesGroup[*].flavors[*].resource[*].lendingLimit` [quantity](https://kubernetes.io/docs/reference/kubernetes-api/common-definitions/quantity/) field. {{< feature-state state="beta" for_version="v0.9" >}} -{{% alert title="Warning" color="warning" %}} +{{% alert title="Note" color="primary" %}} `LendingLimit` is a Beta feature enabled by default. From 47034adee82fb2ab4e03561a6eba74c4f1f41be8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 10:46:28 +0100 Subject: [PATCH 018/155] Bump github.com/gohugoio/hugo in /hack/internal/tools (#3017) Bumps [github.com/gohugoio/hugo](https://github.com/gohugoio/hugo) from 0.133.1 to 0.134.1. - [Release notes](https://github.com/gohugoio/hugo/releases) - [Changelog](https://github.com/gohugoio/hugo/blob/master/hugoreleaser.toml) - [Commits](https://github.com/gohugoio/hugo/compare/v0.133.1...v0.134.1) --- updated-dependencies: - dependency-name: github.com/gohugoio/hugo dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- hack/internal/tools/go.mod | 4 ++-- hack/internal/tools/go.sum | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/hack/internal/tools/go.mod b/hack/internal/tools/go.mod index 7e8b18b12f..0a26775abe 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.6 require ( - github.com/gohugoio/hugo v0.133.1 + github.com/gohugoio/hugo v0.134.1 github.com/golangci/golangci-lint v1.60.3 github.com/mikefarah/yq/v4 v4.44.3 github.com/onsi/ginkgo/v2 v2.20.2 @@ -99,7 +99,7 @@ require ( 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/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.20.2 // indirect diff --git a/hack/internal/tools/go.sum b/hack/internal/tools/go.sum index 9ce608275a..b06ba3ce26 100644 --- a/hack/internal/tools/go.sum +++ b/hack/internal/tools/go.sum @@ -108,8 +108,8 @@ github.com/goccy/go-yaml v1.12.0 h1:/1WHjnMsI1dlIBQutrvSMGZRQufVO3asrHfTwfACoPM= github.com/goccy/go-yaml v1.12.0/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.133.1 h1:b9mDQu3HjKWJTSTGFQO1zL0IaOG7tiBfdHVValq1Z0Q= -github.com/gohugoio/hugo v0.133.1/go.mod h1:WcKqZK0xjiEbhr20RGFmWAFnCxNCYEE4XhFa+pv6IMA= +github.com/gohugoio/hugo v0.134.1 h1:tLFRqDJuAlifwXispNvIHh6K3CT7ughxbBxzfUTStXY= +github.com/gohugoio/hugo v0.134.1/go.mod h1:/1gnGxlWfAzQarxcQ+tMvKw4e/IMBwy0DFbRxORwOtY= 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= @@ -238,8 +238,8 @@ github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4 github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag= github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= -github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= -github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= 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/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= @@ -293,7 +293,6 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ 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/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/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= From 02e88df04ad4806c7146c66b3a0e72321bbd8b6b Mon Sep 17 00:00:00 2001 From: Mykhailo Bobrovskyi Date: Mon, 9 Sep 2024 13:50:27 +0300 Subject: [PATCH 019/155] Bump sigs.k8s.io/kueue from 0.8.0 to 0.8.1 in /cmd/experimental/kjobctl. (#3022) --- cmd/experimental/kjobctl/go.mod | 2 +- cmd/experimental/kjobctl/go.sum | 4 ++-- cmd/experimental/kjobctl/hack/tools/go.mod | 2 +- cmd/experimental/kjobctl/hack/tools/go.sum | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cmd/experimental/kjobctl/go.mod b/cmd/experimental/kjobctl/go.mod index 2cf490607b..a95e24a77b 100644 --- a/cmd/experimental/kjobctl/go.mod +++ b/cmd/experimental/kjobctl/go.mod @@ -17,7 +17,7 @@ require ( k8s.io/kubectl v0.30.4 k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 sigs.k8s.io/controller-runtime v0.18.4 - sigs.k8s.io/kueue v0.8.0 + sigs.k8s.io/kueue v0.8.1 ) require ( diff --git a/cmd/experimental/kjobctl/go.sum b/cmd/experimental/kjobctl/go.sum index 94d46c6e9b..b41ce15dac 100644 --- a/cmd/experimental/kjobctl/go.sum +++ b/cmd/experimental/kjobctl/go.sum @@ -307,8 +307,8 @@ sigs.k8s.io/controller-runtime v0.18.4 h1:87+guW1zhvuPLh1PHybKdYFLU0YJp4FhJRmiHv 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.8.0 h1:fMfZVcqmPFz4YoLwWiYzVwEHvcF4+QuiQBPFtUCW/64= -sigs.k8s.io/kueue v0.8.0/go.mod h1:rpiskRaOSf4iapxEWFrJ8Ryp5Uij442XSswav3mvdao= +sigs.k8s.io/kueue v0.8.1 h1:jK1ei/EkgmcpMqv4qjyt+6Fmz3TyVTrLUikgPkfREXw= +sigs.k8s.io/kueue v0.8.1/go.mod h1:1u80mOR4w6tny+a9cE9x/Hq9OJDAVuGNu7WIfyPtMTU= 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 677483d3dd..76bc0ee92b 100644 --- a/cmd/experimental/kjobctl/hack/tools/go.mod +++ b/cmd/experimental/kjobctl/hack/tools/go.mod @@ -110,7 +110,7 @@ require ( 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/kueue v0.8.0 // indirect + sigs.k8s.io/kueue v0.8.1 // 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 diff --git a/cmd/experimental/kjobctl/hack/tools/go.sum b/cmd/experimental/kjobctl/hack/tools/go.sum index 50c0bb8cdd..8ba1c333cd 100644 --- a/cmd/experimental/kjobctl/hack/tools/go.sum +++ b/cmd/experimental/kjobctl/hack/tools/go.sum @@ -165,8 +165,8 @@ github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4= github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag= -github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= -github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= +github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= +github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= 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= @@ -424,8 +424,8 @@ sigs.k8s.io/controller-tools v0.15.0 h1:4dxdABXGDhIa68Fiwaif0vcu32xfwmgQ+w8p+5Cx 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/kueue v0.8.0 h1:fMfZVcqmPFz4YoLwWiYzVwEHvcF4+QuiQBPFtUCW/64= -sigs.k8s.io/kueue v0.8.0/go.mod h1:rpiskRaOSf4iapxEWFrJ8Ryp5Uij442XSswav3mvdao= +sigs.k8s.io/kueue v0.8.1 h1:jK1ei/EkgmcpMqv4qjyt+6Fmz3TyVTrLUikgPkfREXw= +sigs.k8s.io/kueue v0.8.1/go.mod h1:1u80mOR4w6tny+a9cE9x/Hq9OJDAVuGNu7WIfyPtMTU= 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= From 687ee1e169cfa4f7cbdf4317353927fcb2320acf Mon Sep 17 00:00:00 2001 From: Mykhailo Bobrovskyi Date: Mon, 9 Sep 2024 14:10:31 +0300 Subject: [PATCH 020/155] Bump github.com/prometheus/client_golang from 1.20.2 to 1.20.3. (#3021) --- go.mod | 2 +- go.sum | 4 +- hack/internal/tools/go.mod | 2 +- hack/internal/tools/go.sum | 4 +- .../client_golang/prometheus/histogram.go | 92 +++++++++++++------ vendor/modules.txt | 2 +- 6 files changed, 73 insertions(+), 33 deletions(-) diff --git a/go.mod b/go.mod index c25e879ba9..0bb86b69aa 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/onsi/ginkgo/v2 v2.20.2 github.com/onsi/gomega v1.34.2 github.com/open-policy-agent/cert-controller v0.10.1 - github.com/prometheus/client_golang v1.20.2 + github.com/prometheus/client_golang v1.20.3 github.com/prometheus/client_model v0.6.1 github.com/ray-project/kuberay/ray-operator v1.2.1 github.com/spf13/cobra v1.8.1 diff --git a/go.sum b/go.sum index 0486a3a950..1c66636b2b 100644 --- a/go.sum +++ b/go.sum @@ -202,8 +202,8 @@ 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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg= -github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0qELP/7u83l4= +github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= diff --git a/hack/internal/tools/go.mod b/hack/internal/tools/go.mod index 0a26775abe..2b83d3d9fa 100644 --- a/hack/internal/tools/go.mod +++ b/hack/internal/tools/go.mod @@ -102,7 +102,7 @@ require ( github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_golang v1.20.2 // indirect + github.com/prometheus/client_golang v1.20.3 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.57.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect diff --git a/hack/internal/tools/go.sum b/hack/internal/tools/go.sum index b06ba3ce26..23f179378c 100644 --- a/hack/internal/tools/go.sum +++ b/hack/internal/tools/go.sum @@ -249,8 +249,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE 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/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg= -github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0qELP/7u83l4= +github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= diff --git a/vendor/github.com/prometheus/client_golang/prometheus/histogram.go b/vendor/github.com/prometheus/client_golang/prometheus/histogram.go index 8d35f2d8ae..8a4f49a4c5 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/histogram.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/histogram.go @@ -1658,7 +1658,10 @@ func addAndResetCounts(hot, cold *histogramCounts) { type nativeExemplars struct { sync.Mutex - ttl time.Duration + // Time-to-live for exemplars, it is set to -1 if exemplars are disabled, that is NativeHistogramMaxExemplars is below 0. + // The ttl is used on insertion to remove an exemplar that is older than ttl, if present. + ttl time.Duration + exemplars []*dto.Exemplar } @@ -1673,6 +1676,7 @@ func makeNativeExemplars(ttl time.Duration, maxCount int) nativeExemplars { if maxCount < 0 { maxCount = 0 + ttl = -1 } return nativeExemplars{ @@ -1682,20 +1686,18 @@ func makeNativeExemplars(ttl time.Duration, maxCount int) nativeExemplars { } func (n *nativeExemplars) addExemplar(e *dto.Exemplar) { - if cap(n.exemplars) == 0 { + if n.ttl == -1 { return } n.Lock() defer n.Unlock() - // The index where to insert the new exemplar. - var nIdx int = -1 - // When the number of exemplars has not yet exceeded or // is equal to cap(n.exemplars), then // insert the new exemplar directly. if len(n.exemplars) < cap(n.exemplars) { + var nIdx int for nIdx = 0; nIdx < len(n.exemplars); nIdx++ { if *e.Value < *n.exemplars[nIdx].Value { break @@ -1705,17 +1707,46 @@ func (n *nativeExemplars) addExemplar(e *dto.Exemplar) { return } + if len(n.exemplars) == 1 { + // When the number of exemplars is 1, then + // replace the existing exemplar with the new exemplar. + n.exemplars[0] = e + return + } + // From this point on, the number of exemplars is greater than 1. + // When the number of exemplars exceeds the limit, remove one exemplar. var ( - rIdx int // The index where to remove the old exemplar. - - ot = time.Now() // Oldest timestamp seen. - otIdx = -1 // Index of the exemplar with the oldest timestamp. - - md = -1.0 // Logarithm of the delta of the closest pair of exemplars. - mdIdx = -1 // Index of the older exemplar within the closest pair. - cLog float64 // Logarithm of the current exemplar. - pLog float64 // Logarithm of the previous exemplar. + ot = time.Time{} // Oldest timestamp seen. Initial value doesn't matter as we replace it due to otIdx == -1 in the loop. + otIdx = -1 // Index of the exemplar with the oldest timestamp. + + md = -1.0 // Logarithm of the delta of the closest pair of exemplars. + + // The insertion point of the new exemplar in the exemplars slice after insertion. + // This is calculated purely based on the order of the exemplars by value. + // nIdx == len(n.exemplars) means the new exemplar is to be inserted after the end. + nIdx = -1 + + // rIdx is ultimately the index for the exemplar that we are replacing with the new exemplar. + // The aim is to keep a good spread of exemplars by value and not let them bunch up too much. + // It is calculated in 3 steps: + // 1. First we set rIdx to the index of the older exemplar within the closest pair by value. + // That is the following will be true (on log scale): + // either the exemplar pair on index (rIdx-1, rIdx) or (rIdx, rIdx+1) will have + // the closest values to each other from all pairs. + // For example, suppose the values are distributed like this: + // |-----------x-------------x----------------x----x-----| + // ^--rIdx as this is older. + // Or like this: + // |-----------x-------------x----------------x----x-----| + // ^--rIdx as this is older. + // 2. If there is an exemplar that expired, then we simple reset rIdx to that index. + // 3. We check if by inserting the new exemplar we would create a closer pair at + // (nIdx-1, nIdx) or (nIdx, nIdx+1) and set rIdx to nIdx-1 or nIdx accordingly to + // keep the spread of exemplars by value; otherwise we keep rIdx as it is. + rIdx = -1 + cLog float64 // Logarithm of the current exemplar. + pLog float64 // Logarithm of the previous exemplar. ) for i, exemplar := range n.exemplars { @@ -1726,7 +1757,7 @@ func (n *nativeExemplars) addExemplar(e *dto.Exemplar) { } // Find the index at which to insert new the exemplar. - if *e.Value <= *exemplar.Value && nIdx == -1 { + if nIdx == -1 && *e.Value <= *exemplar.Value { nIdx = i } @@ -1738,11 +1769,13 @@ func (n *nativeExemplars) addExemplar(e *dto.Exemplar) { } diff := math.Abs(cLog - pLog) if md == -1 || diff < md { + // The closest exemplar pair is at index: i-1, i. + // Choose the exemplar with the older timestamp for replacement. md = diff if n.exemplars[i].Timestamp.AsTime().Before(n.exemplars[i-1].Timestamp.AsTime()) { - mdIdx = i + rIdx = i } else { - mdIdx = i - 1 + rIdx = i - 1 } } @@ -1753,8 +1786,12 @@ func (n *nativeExemplars) addExemplar(e *dto.Exemplar) { if nIdx == -1 { nIdx = len(n.exemplars) } + // Here, we have the following relationships: + // n.exemplars[nIdx-1].Value < e.Value (if nIdx > 0) + // e.Value <= n.exemplars[nIdx].Value (if nIdx < len(n.exemplars)) if otIdx != -1 && e.Timestamp.AsTime().Sub(ot) > n.ttl { + // If the oldest exemplar has expired, then replace it with the new exemplar. rIdx = otIdx } else { // In the previous for loop, when calculating the closest pair of exemplars, @@ -1764,23 +1801,26 @@ func (n *nativeExemplars) addExemplar(e *dto.Exemplar) { if nIdx > 0 { diff := math.Abs(elog - math.Log(n.exemplars[nIdx-1].GetValue())) if diff < md { + // The value we are about to insert is closer to the previous exemplar at the insertion point than what we calculated before in rIdx. + // v--rIdx + // |-----------x-n-----------x----------------x----x-----| + // nIdx-1--^ ^--new exemplar value + // Do not make the spread worse, replace nIdx-1 and not rIdx. md = diff - mdIdx = nIdx - if n.exemplars[nIdx-1].Timestamp.AsTime().Before(e.Timestamp.AsTime()) { - mdIdx = nIdx - 1 - } + rIdx = nIdx - 1 } } if nIdx < len(n.exemplars) { diff := math.Abs(math.Log(n.exemplars[nIdx].GetValue()) - elog) if diff < md { - mdIdx = nIdx - if n.exemplars[nIdx].Timestamp.AsTime().Before(e.Timestamp.AsTime()) { - mdIdx = nIdx - } + // The value we are about to insert is closer to the next exemplar at the insertion point than what we calculated before in rIdx. + // v--rIdx + // |-----------x-----------n-x----------------x----x-----| + // new exemplar value--^ ^--nIdx + // Do not make the spread worse, replace nIdx-1 and not rIdx. + rIdx = nIdx } } - rIdx = mdIdx } // Adjust the slice according to rIdx and nIdx. diff --git a/vendor/modules.txt b/vendor/modules.txt index 347ab51457..6f0f7e2d26 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -285,7 +285,7 @@ github.com/peterbourgon/diskv # github.com/pkg/errors v0.9.1 ## explicit github.com/pkg/errors -# github.com/prometheus/client_golang v1.20.2 +# github.com/prometheus/client_golang v1.20.3 ## explicit; go 1.20 github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil/header From 67113647f48754aff6b8b2ae317cfb8c61fd0aa0 Mon Sep 17 00:00:00 2001 From: Mykhailo Bobrovskyi Date: Mon, 9 Sep 2024 16:04:28 +0300 Subject: [PATCH 021/155] Use current version instead of $VERSION. (#3023) --- .../monitor_pending_workloads/pending_workloads_on_demand.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/content/en/docs/tasks/manage/monitor_pending_workloads/pending_workloads_on_demand.md b/site/content/en/docs/tasks/manage/monitor_pending_workloads/pending_workloads_on_demand.md index d3954bd1d4..d37ad00cf5 100644 --- a/site/content/en/docs/tasks/manage/monitor_pending_workloads/pending_workloads_on_demand.md +++ b/site/content/en/docs/tasks/manage/monitor_pending_workloads/pending_workloads_on_demand.md @@ -31,7 +31,7 @@ VisibilityOnDemand is an `Alpha` feature disabled by default. To use the visibil To install the visibility API, run the following command ```shell -kubectl apply --server-side -f https://github.com/kubernetes-sigs/kueue/releases/download/$VERSION/visibility-api.yaml +kubectl apply --server-side -f https://github.com/kubernetes-sigs/kueue/releases/download/{{< param "version" >}}/visibility-api.yaml ``` ## Monitor pending workloads on demand From 3009775dd48b2416f70acb6ad90f116d1d5d6bbf Mon Sep 17 00:00:00 2001 From: Traian Schiau <55734665+trasc@users.noreply.github.com> Date: Wed, 11 Sep 2024 11:37:11 +0300 Subject: [PATCH 022/155] [test][scalability] Retry performance test on failure (#3020) * [test][scalability] Retry performance test on failure * Review remarks --- Makefile-test.mk | 9 +++++++-- hack/performance-retry.sh | 41 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) create mode 100755 hack/performance-retry.sh diff --git a/Makefile-test.mk b/Makefile-test.mk index cb247ffd73..6c4c7bf1eb 100644 --- a/Makefile-test.mk +++ b/Makefile-test.mk @@ -139,13 +139,18 @@ run-performance-scheduler: envtest performance-scheduler-runner minimalkueue --generatorConfig=$(SCALABILITY_GENERATOR_CONFIG) \ --minimalKueue=$(MINIMALKUEUE_RUNNER) $(SCALABILITY_EXTRA_ARGS) $(SCALABILITY_SCRAPE_ARGS) -.PHONY: test-performance-scheduler -test-performance-scheduler: gotestsum run-performance-scheduler +.PHONY: test-performance-scheduler-once +test-performance-scheduler-once: gotestsum run-performance-scheduler $(GOTESTSUM) --junitfile $(ARTIFACTS)/junit.xml -- $(GO_TEST_FLAGS) ./test/performance/scheduler/checker \ --summary=$(SCALABILITY_RUN_DIR)/summary.yaml \ --cmdStats=$(SCALABILITY_RUN_DIR)/minimalkueue.stats.yaml \ --range=$(PROJECT_DIR)/test/performance/scheduler/default_rangespec.yaml +PERFORMANCE_RETRY_COUNT?=2 +.PHONY: test-performance-scheduler +test-performance-scheduler: + ARTIFACTS=$(ARTIFACTS) ./hack/performance-retry.sh $(PERFORMANCE_RETRY_COUNT) + .PHONY: run-performance-scheduler-in-cluster run-performance-scheduler-in-cluster: envtest performance-scheduler-runner mkdir -p $(ARTIFACTS)/run-performance-scheduler-in-cluster diff --git a/hack/performance-retry.sh b/hack/performance-retry.sh new file mode 100755 index 0000000000..c81e2b32cb --- /dev/null +++ b/hack/performance-retry.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +# 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. + +set -o errexit +set -o nounset +set -o pipefail + +if [[ "$#" -lt 1 ]]; then + echo "Usage: ${0} " + exit 1 +fi + + +for i in $(seq 1 "$1"); do + echo "Try ${i}" + err=0 + make test-performance-scheduler-once || err=$? + if [ $err -eq 0 ]; then + break + else + if [ "$i" -lt "$1" ]; then + mv "${ARTIFACTS}/junit.xml" "${ARTIFACTS}/junit-fail-${i}.xml" || echo "Unable to back-up ${ARTIFACTS}/junit.xml" + mv "${ARTIFACTS}/run-performance-scheduler" "${ARTIFACTS}/run-performance-scheduler-fail-${i}" || echo "Unable to back-up ${ARTIFACTS}/run-performance-scheduler" + else + exit $err + fi + fi +done From d4331979e09c7096f1f17426c9551476b3fe77fc Mon Sep 17 00:00:00 2001 From: gabesaba <15304068+gabesaba@users.noreply.github.com> Date: Wed, 11 Sep 2024 16:37:12 +0200 Subject: [PATCH 023/155] Implement Cohort Webhook (#2982) --- charts/kueue/templates/webhook/webhook.yaml | 20 ++ config/components/webhook/manifests.yaml | 20 ++ pkg/util/testing/wrappers.go | 5 + pkg/webhooks/clusterqueue_webhook.go | 34 +- pkg/webhooks/clusterqueue_webhook_test.go | 2 +- pkg/webhooks/cohort_webhook.go | 77 +++++ pkg/webhooks/common.go | 5 + pkg/webhooks/webhooks.go | 8 +- test/integration/webhook/cohort_test.go | 362 ++++++++++++++++++++ 9 files changed, 515 insertions(+), 18 deletions(-) create mode 100644 pkg/webhooks/cohort_webhook.go create mode 100644 test/integration/webhook/cohort_test.go diff --git a/charts/kueue/templates/webhook/webhook.yaml b/charts/kueue/templates/webhook/webhook.yaml index 4e3bfa9189..08dcb17f2f 100644 --- a/charts/kueue/templates/webhook/webhook.yaml +++ b/charts/kueue/templates/webhook/webhook.yaml @@ -599,6 +599,26 @@ webhooks: resources: - clusterqueues sideEffects: None + - admissionReviewVersions: + - v1 + clientConfig: + service: + name: '{{ include "kueue.fullname" . }}-webhook-service' + namespace: '{{ .Release.Namespace }}' + path: /validate-kueue-x-k8s-io-v1alpha1-cohort + failurePolicy: Fail + name: vcohort.kb.io + rules: + - apiGroups: + - kueue.x-k8s.io + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - cohorts + sideEffects: None - admissionReviewVersions: - v1 clientConfig: diff --git a/config/components/webhook/manifests.yaml b/config/components/webhook/manifests.yaml index f539fb5bb6..8424f0e674 100644 --- a/config/components/webhook/manifests.yaml +++ b/config/components/webhook/manifests.yaml @@ -555,6 +555,26 @@ webhooks: resources: - clusterqueues sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-kueue-x-k8s-io-v1alpha1-cohort + failurePolicy: Fail + name: vcohort.kb.io + rules: + - apiGroups: + - kueue.x-k8s.io + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - cohorts + sideEffects: None - admissionReviewVersions: - v1 clientConfig: diff --git a/pkg/util/testing/wrappers.go b/pkg/util/testing/wrappers.go index 74c7eb0e67..6213b38976 100644 --- a/pkg/util/testing/wrappers.go +++ b/pkg/util/testing/wrappers.go @@ -600,6 +600,11 @@ func (c *CohortWrapper) Obj() *kueuealpha.Cohort { return &c.Cohort } +func (c *CohortWrapper) Parent(parentName string) *CohortWrapper { + c.Cohort.Spec.Parent = parentName + return c +} + // ResourceGroup adds a ResourceGroup with flavors. func (c *CohortWrapper) ResourceGroup(flavors ...kueue.FlavorQuotas) *CohortWrapper { c.Spec.ResourceGroups = append(c.Spec.ResourceGroups, createResourceGroup(flavors...)) diff --git a/pkg/webhooks/clusterqueue_webhook.go b/pkg/webhooks/clusterqueue_webhook.go index ae6474b995..e3c5f21f69 100644 --- a/pkg/webhooks/clusterqueue_webhook.go +++ b/pkg/webhooks/clusterqueue_webhook.go @@ -82,11 +82,10 @@ func (w *ClusterQueueWebhook) ValidateCreate(ctx context.Context, obj runtime.Ob // ValidateUpdate implements webhook.CustomValidator so a webhook will be registered for the type func (w *ClusterQueueWebhook) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) { newCQ := newObj.(*kueue.ClusterQueue) - oldCQ := oldObj.(*kueue.ClusterQueue) log := ctrl.LoggerFrom(ctx).WithName("clusterqueue-webhook") log.V(5).Info("Validating update", "clusterQueue", klog.KObj(newCQ)) - allErrs := ValidateClusterQueueUpdate(newCQ, oldCQ) + allErrs := ValidateClusterQueueUpdate(newCQ) return nil, allErrs.ToAggregate() } @@ -99,7 +98,11 @@ func ValidateClusterQueue(cq *kueue.ClusterQueue) field.ErrorList { path := field.NewPath("spec") var allErrs field.ErrorList - allErrs = append(allErrs, validateResourceGroups(cq.Spec.ResourceGroups, cq.Spec.Cohort, path.Child("resourceGroups"))...) + config := validationConfig{ + hasParent: cq.Spec.Cohort != "", + enforceNominalGreaterThanLending: true, + } + allErrs = append(allErrs, validateResourceGroups(cq.Spec.ResourceGroups, config, path.Child("resourceGroups"))...) allErrs = append(allErrs, validation.ValidateLabelSelector(cq.Spec.NamespaceSelector, validation.LabelSelectorValidationOptions{}, path.Child("namespaceSelector"))...) allErrs = append(allErrs, validateCQAdmissionChecks(&cq.Spec, path)...) @@ -112,10 +115,8 @@ func ValidateClusterQueue(cq *kueue.ClusterQueue) field.ErrorList { return allErrs } -func ValidateClusterQueueUpdate(newObj, _ *kueue.ClusterQueue) field.ErrorList { - var allErrs field.ErrorList - allErrs = append(allErrs, ValidateClusterQueue(newObj)...) - return allErrs +func ValidateClusterQueueUpdate(newObj *kueue.ClusterQueue) field.ErrorList { + return ValidateClusterQueue(newObj) } func validatePreemption(preemption *kueue.ClusterQueuePreemption, path *field.Path) field.ErrorList { @@ -137,7 +138,7 @@ func validateCQAdmissionChecks(spec *kueue.ClusterQueueSpec, path *field.Path) f return allErrs } -func validateResourceGroups(resourceGroups []kueue.ResourceGroup, cohort string, path *field.Path) field.ErrorList { +func validateResourceGroups(resourceGroups []kueue.ResourceGroup, config validationConfig, path *field.Path) field.ErrorList { var allErrs field.ErrorList seenResources := sets.New[corev1.ResourceName]() seenFlavors := sets.New[kueue.ResourceFlavorReference]() @@ -155,7 +156,7 @@ func validateResourceGroups(resourceGroups []kueue.ResourceGroup, cohort string, } for j, fqs := range rg.Flavors { path := path.Child("flavors").Index(j) - allErrs = append(allErrs, validateFlavorQuotas(fqs, rg.CoveredResources, cohort, path)...) + allErrs = append(allErrs, validateFlavorQuotas(fqs, rg.CoveredResources, config, path)...) if seenFlavors.Has(fqs.Name) { allErrs = append(allErrs, field.Duplicate(path.Child("name"), fqs.Name)) } else { @@ -166,7 +167,7 @@ func validateResourceGroups(resourceGroups []kueue.ResourceGroup, cohort string, return allErrs } -func validateFlavorQuotas(flavorQuotas kueue.FlavorQuotas, coveredResources []corev1.ResourceName, cohort string, path *field.Path) field.ErrorList { +func validateFlavorQuotas(flavorQuotas kueue.FlavorQuotas, coveredResources []corev1.ResourceName, config validationConfig, path *field.Path) field.ErrorList { var allErrs field.ErrorList for i, rq := range flavorQuotas.Resources { @@ -180,13 +181,14 @@ func validateFlavorQuotas(flavorQuotas kueue.FlavorQuotas, coveredResources []co allErrs = append(allErrs, validateResourceQuantity(rq.NominalQuota, path.Child("nominalQuota"))...) if rq.BorrowingLimit != nil { borrowingLimitPath := path.Child("borrowingLimit") + allErrs = append(allErrs, validateLimit(*rq.BorrowingLimit, config, borrowingLimitPath)...) allErrs = append(allErrs, validateResourceQuantity(*rq.BorrowingLimit, borrowingLimitPath)...) } if features.Enabled(features.LendingLimit) && rq.LendingLimit != nil { lendingLimitPath := path.Child("lendingLimit") allErrs = append(allErrs, validateResourceQuantity(*rq.LendingLimit, lendingLimitPath)...) - allErrs = append(allErrs, validateLimit(*rq.LendingLimit, cohort, lendingLimitPath)...) - allErrs = append(allErrs, validateLendingLimit(*rq.LendingLimit, rq.NominalQuota, lendingLimitPath)...) + allErrs = append(allErrs, validateLimit(*rq.LendingLimit, config, lendingLimitPath)...) + allErrs = append(allErrs, validateLendingLimit(*rq.LendingLimit, rq.NominalQuota, config, lendingLimitPath)...) } } return allErrs @@ -202,18 +204,18 @@ func validateResourceQuantity(value resource.Quantity, fldPath *field.Path) fiel } // validateLimit enforces that BorrowingLimit or LendingLimit must be nil when cohort is empty -func validateLimit(limit resource.Quantity, cohort string, fldPath *field.Path) field.ErrorList { +func validateLimit(limit resource.Quantity, config validationConfig, fldPath *field.Path) field.ErrorList { var allErrs field.ErrorList - if len(cohort) == 0 { + if !config.hasParent { allErrs = append(allErrs, field.Invalid(fldPath, limit.String(), limitIsEmptyErrorMsg)) } return allErrs } // validateLendingLimit enforces that LendingLimit is not greater than NominalQuota -func validateLendingLimit(lend, nominal resource.Quantity, fldPath *field.Path) field.ErrorList { +func validateLendingLimit(lend, nominal resource.Quantity, config validationConfig, fldPath *field.Path) field.ErrorList { var allErrs field.ErrorList - if lend.Cmp(nominal) > 0 { + if config.enforceNominalGreaterThanLending && lend.Cmp(nominal) > 0 { allErrs = append(allErrs, field.Invalid(fldPath, lend.String(), lendingLimitErrorMsg)) } return allErrs diff --git a/pkg/webhooks/clusterqueue_webhook_test.go b/pkg/webhooks/clusterqueue_webhook_test.go index 19732b08cc..f2cefdfeaf 100644 --- a/pkg/webhooks/clusterqueue_webhook_test.go +++ b/pkg/webhooks/clusterqueue_webhook_test.go @@ -361,7 +361,7 @@ func TestValidateClusterQueueUpdate(t *testing.T) { for _, tc := range testcases { t.Run(tc.name, func(t *testing.T) { - gotErr := ValidateClusterQueueUpdate(tc.newClusterQueue, tc.oldClusterQueue) + gotErr := ValidateClusterQueueUpdate(tc.newClusterQueue) if diff := cmp.Diff(tc.wantErr, gotErr, cmpopts.IgnoreFields(field.Error{}, "Detail", "BadValue")); diff != "" { t.Errorf("ValidateResources() mismatch (-want +got):\n%s", diff) } diff --git a/pkg/webhooks/cohort_webhook.go b/pkg/webhooks/cohort_webhook.go new file mode 100644 index 0000000000..5146eb398f --- /dev/null +++ b/pkg/webhooks/cohort_webhook.go @@ -0,0 +1,77 @@ +/* +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 webhooks + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/klog/v2" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/webhook" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + + kueuealpha "sigs.k8s.io/kueue/apis/kueue/v1alpha1" +) + +type CohortWebhook struct{} + +func setupWebhookForCohort(mgr ctrl.Manager) error { + return ctrl.NewWebhookManagedBy(mgr). + For(&kueuealpha.Cohort{}). + WithValidator(&CohortWebhook{}). + Complete() +} + +func (w *CohortWebhook) Default(ctx context.Context, obj runtime.Object) error { + return nil +} + +//+kubebuilder:webhook:path=/validate-kueue-x-k8s-io-v1alpha1-cohort,mutating=false,failurePolicy=fail,sideEffects=None,groups=kueue.x-k8s.io,resources=cohorts,verbs=create;update,versions=v1alpha1,name=vcohort.kb.io,admissionReviewVersions=v1 + +var _ webhook.CustomValidator = &CohortWebhook{} + +// ValidateCreate implements webhook.CustomValidator so a webhook will be registered for the type +func (w *CohortWebhook) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { + cohort := obj.(*kueuealpha.Cohort) + log := ctrl.LoggerFrom(ctx).WithName("cohort-webhook") + log.V(5).Info("Validating Cohort create", "cohort", klog.KObj(cohort)) + return nil, validateCohort(cohort).ToAggregate() +} + +// ValidateUpdate implements webhook.CustomValidator so a webhook will be registered for the type +func (w *CohortWebhook) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) { + cohort := newObj.(*kueuealpha.Cohort) + log := ctrl.LoggerFrom(ctx).WithName("cohort-webhook") + log.V(5).Info("Validating Cohort update", "cohort", klog.KObj(cohort)) + return nil, validateCohort(cohort).ToAggregate() +} + +// ValidateDelete implements webhook.CustomValidator so a webhook will be registered for the type +func (w *CohortWebhook) ValidateDelete(_ context.Context, _ runtime.Object) (admission.Warnings, error) { + return nil, nil +} + +func validateCohort(cohort *kueuealpha.Cohort) field.ErrorList { + path := field.NewPath("spec") + config := validationConfig{ + hasParent: cohort.Spec.Parent != "", + enforceNominalGreaterThanLending: false, + } + return validateResourceGroups(cohort.Spec.ResourceGroups, config, path.Child("resourceGroups")) +} diff --git a/pkg/webhooks/common.go b/pkg/webhooks/common.go index 703cb3fe75..dcea7b45f2 100644 --- a/pkg/webhooks/common.go +++ b/pkg/webhooks/common.go @@ -29,3 +29,8 @@ func validateResourceName(name corev1.ResourceName, fldPath *field.Path) field.E } return allErrs } + +type validationConfig struct { + hasParent bool + enforceNominalGreaterThanLending bool +} diff --git a/pkg/webhooks/webhooks.go b/pkg/webhooks/webhooks.go index 5e172c573b..6ac550dd24 100644 --- a/pkg/webhooks/webhooks.go +++ b/pkg/webhooks/webhooks.go @@ -16,7 +16,9 @@ limitations under the License. package webhooks -import ctrl "sigs.k8s.io/controller-runtime" +import ( + ctrl "sigs.k8s.io/controller-runtime" +) // Setup sets up the webhooks for core controllers. It returns the name of the // webhook that failed to create and an error, if any. @@ -33,5 +35,9 @@ func Setup(mgr ctrl.Manager) (string, error) { return "ClusterQueue", err } + if err := setupWebhookForCohort(mgr); err != nil { + return "Cohort", err + } + return "", nil } diff --git a/test/integration/webhook/cohort_test.go b/test/integration/webhook/cohort_test.go new file mode 100644 index 0000000000..de69cbd4fd --- /dev/null +++ b/test/integration/webhook/cohort_test.go @@ -0,0 +1,362 @@ +/* +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 webhook + +import ( + "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + kueuealpha "sigs.k8s.io/kueue/apis/kueue/v1alpha1" + kueue "sigs.k8s.io/kueue/apis/kueue/v1beta1" + "sigs.k8s.io/kueue/pkg/util/testing" + "sigs.k8s.io/kueue/test/util" +) + +var _ = ginkgo.Describe("Cohort Webhook", func() { + ginkgo.When("Creating a Cohort", func() { + ginkgo.DescribeTable("Validate Cohort on creation", func(cohort *kueuealpha.Cohort, errorType int) { + err := k8sClient.Create(ctx, cohort) + if err == nil { + defer func() { + util.ExpectObjectToBeDeleted(ctx, k8sClient, cohort, true) + }() + } + switch errorType { + case isForbidden: + gomega.Expect(err).Should(gomega.HaveOccurred()) + gomega.Expect(errors.IsForbidden(err)).Should(gomega.BeTrue(), "error: %v", err) + case isInvalid: + gomega.Expect(err).Should(gomega.HaveOccurred()) + gomega.Expect(err).Should(testing.BeAPIError(testing.InvalidError), "error: %v", err) + default: + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + } + }, + ginkgo.Entry("Should disallow empty name", + testing.MakeCohort("").Obj(), + isInvalid), + ginkgo.Entry("Should allow default Cohort", + testing.MakeCohort("cohort").Obj(), + isValid), + ginkgo.Entry("Should allow valid parent name", + testing.MakeCohort("cohort").Parent("prod").Obj(), + isValid), + ginkgo.Entry("Should reject invalid parent name", + testing.MakeCohort("cohort").Parent("@prod").Obj(), + isInvalid), + ginkgo.Entry("ResourceGroup should have at least one flavor", + testing.MakeCohort("cohort").ResourceGroup().Obj(), + isInvalid), + ginkgo.Entry("FlavorQuota should have at least one resource", + testing.MakeCohort("cohort"). + ResourceGroup(*testing.MakeFlavorQuotas("foo").Obj()). + Obj(), + isInvalid), + ginkgo.Entry("Should reject invalid flavor name", + testing.MakeCohort("cohort"). + ResourceGroup(*testing.MakeFlavorQuotas("@x86").Resource("cpu", "5").Obj()). + Obj(), + isInvalid), + ginkgo.Entry("Should allow valid resource name", + testing.MakeCohort("cohort"). + ResourceGroup(*testing.MakeFlavorQuotas("x86").Resource("@cpu", "5").Obj()). + Obj(), + isForbidden), + ginkgo.Entry("Should reject too many flavors in resource group", + testing.MakeCohort("cohort").ResourceGroup( + testing.MakeFlavorQuotas("f0").Resource("cpu").FlavorQuotas, + testing.MakeFlavorQuotas("f1").Resource("cpu").FlavorQuotas, + testing.MakeFlavorQuotas("f2").Resource("cpu").FlavorQuotas, + testing.MakeFlavorQuotas("f3").Resource("cpu").FlavorQuotas, + testing.MakeFlavorQuotas("f4").Resource("cpu").FlavorQuotas, + testing.MakeFlavorQuotas("f5").Resource("cpu").FlavorQuotas, + testing.MakeFlavorQuotas("f6").Resource("cpu").FlavorQuotas, + testing.MakeFlavorQuotas("f7").Resource("cpu").FlavorQuotas, + testing.MakeFlavorQuotas("f8").Resource("cpu").FlavorQuotas, + testing.MakeFlavorQuotas("f9").Resource("cpu").FlavorQuotas, + testing.MakeFlavorQuotas("f10").Resource("cpu").FlavorQuotas, + testing.MakeFlavorQuotas("f11").Resource("cpu").FlavorQuotas, + testing.MakeFlavorQuotas("f12").Resource("cpu").FlavorQuotas, + testing.MakeFlavorQuotas("f13").Resource("cpu").FlavorQuotas, + testing.MakeFlavorQuotas("f14").Resource("cpu").FlavorQuotas, + testing.MakeFlavorQuotas("f15").Resource("cpu").FlavorQuotas, + testing.MakeFlavorQuotas("f16").Resource("cpu").FlavorQuotas).Obj(), + isInvalid), + ginkgo.Entry("Should reject too many resources in resource group", + testing.MakeCohort("cohort").ResourceGroup( + testing.MakeFlavorQuotas("flavor"). + Resource("cpu0"). + Resource("cpu1"). + Resource("cpu2"). + Resource("cpu3"). + Resource("cpu4"). + Resource("cpu5"). + Resource("cpu6"). + Resource("cpu7"). + Resource("cpu8"). + Resource("cpu9"). + Resource("cpu10"). + Resource("cpu11"). + Resource("cpu12"). + Resource("cpu13"). + Resource("cpu14"). + Resource("cpu15"). + Resource("cpu16").FlavorQuotas).Obj(), + isInvalid), + ginkgo.Entry("Should allow resource with valid name", + testing.MakeCohort("cohort"). + ResourceGroup(*testing.MakeFlavorQuotas("default").Resource("cpu").Obj()). + Obj(), + isValid), + ginkgo.Entry("Should reject resource with invalid name", + testing.MakeCohort("cohort"). + ResourceGroup(*testing.MakeFlavorQuotas("default").Resource("@cpu").Obj()). + Obj(), + isForbidden), + ginkgo.Entry("Should allow extended resources with valid name", + testing.MakeCohort("cohort"). + ResourceGroup(*testing.MakeFlavorQuotas("default").Resource("example.com/gpu").Obj()). + Obj(), + isValid), + ginkgo.Entry("Should allow flavor with valid name", + testing.MakeCohort("cohort"). + ResourceGroup(*testing.MakeFlavorQuotas("x86").Resource("cpu").Obj()). + Obj(), + isValid), + ginkgo.Entry("Should reject flavor with invalid name", + testing.MakeCohort("cohort"). + ResourceGroup(*testing.MakeFlavorQuotas("x_86").Resource("cpu").Obj()). + Obj(), + isInvalid), + ginkgo.Entry("Should reject negative nominal quota", + testing.MakeCohort("cohort"). + ResourceGroup(*testing.MakeFlavorQuotas("x86").Resource("cpu", "-1").Obj()). + Obj(), + isForbidden), + ginkgo.Entry("Should reject negative borrowing limit", + testing.MakeCohort("cohort"). + ResourceGroup(*testing.MakeFlavorQuotas("x86").Resource("cpu", "1", "-1").Obj()). + Obj(), + isForbidden), + ginkgo.Entry("Should reject negative lending limit", + testing.MakeCohort("cohort"). + ResourceGroup(*testing.MakeFlavorQuotas("x86").Resource("cpu", "1", "", "-1").Obj()). + Obj(), + isForbidden), + ginkgo.Entry("Should reject borrowingLimit when no parent", + testing.MakeCohort("cohort"). + ResourceGroup( + *testing.MakeFlavorQuotas("x86").Resource("cpu", "1", "1").Obj()). + Obj(), + isForbidden), + ginkgo.Entry("Should allow borrowingLimit 0 when parent exists", + testing.MakeCohort("cohort"). + ResourceGroup( + *testing.MakeFlavorQuotas("x86").Resource("cpu", "1", "0").Obj()). + Parent("parent"). + Obj(), + isValid), + ginkgo.Entry("Should allow borrowingLimit when parent exists", + testing.MakeCohort("cohort"). + ResourceGroup( + *testing.MakeFlavorQuotas("x86").Resource("cpu", "1", "1").Obj()). + Parent("parent"). + Obj(), + isValid), + ginkgo.Entry("Should reject lendingLimit when no parent", + testing.MakeCohort("cohort"). + ResourceGroup( + testing.MakeFlavorQuotas("x86"). + ResourceQuotaWrapper("cpu").NominalQuota("1").LendingLimit("1").Append(). + FlavorQuotas, + ). + Obj(), + isForbidden), + ginkgo.Entry("Should allow lendingLimit when parent exists", + testing.MakeCohort("cohort"). + ResourceGroup( + testing.MakeFlavorQuotas("x86"). + ResourceQuotaWrapper("cpu").NominalQuota("1").LendingLimit("1").Append(). + FlavorQuotas, + ). + Parent("parent"). + Obj(), + isValid), + ginkgo.Entry("Should allow lendingLimit 0 when parent exists", + testing.MakeCohort("cohort"). + ResourceGroup( + testing.MakeFlavorQuotas("x86"). + ResourceQuotaWrapper("cpu").NominalQuota("0").LendingLimit("0").Append(). + FlavorQuotas, + ). + Parent("parent"). + Obj(), + isValid), + ginkgo.Entry("Should allow lending limit to exceed nominal quota", + testing.MakeCohort("cohort"). + ResourceGroup( + testing.MakeFlavorQuotas("x86"). + ResourceQuotaWrapper("cpu").NominalQuota("3").LendingLimit("5").Append(). + FlavorQuotas, + ). + Parent("parent"). + Obj(), + isValid), + ginkgo.Entry("Should allow multiple resource groups", + testing.MakeCohort("cohort"). + ResourceGroup( + *testing.MakeFlavorQuotas("alpha"). + Resource("cpu", "0"). + Resource("memory", "0"). + Obj(), + *testing.MakeFlavorQuotas("beta"). + Resource("cpu", "0"). + Resource("memory", "0"). + Obj(), + ). + ResourceGroup( + *testing.MakeFlavorQuotas("gamma"). + Resource("example.com/gpu", "0"). + Obj(), + *testing.MakeFlavorQuotas("omega"). + Resource("example.com/gpu", "0"). + Obj(), + ). + Obj(), + isValid), + ginkgo.Entry("Should reject resources in a flavor in different order", + &kueuealpha.Cohort{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cohort", + }, + Spec: kueuealpha.CohortSpec{ + ResourceGroups: []kueue.ResourceGroup{ + { + CoveredResources: []corev1.ResourceName{"cpu", "memory"}, + Flavors: []kueue.FlavorQuotas{ + *testing.MakeFlavorQuotas("alpha"). + Resource("cpu", "0"). + Resource("memory", "0"). + Obj(), + *testing.MakeFlavorQuotas("beta"). + Resource("memory", "0"). + Resource("cpu", "0"). + Obj(), + }, + }, + }, + }, + }, + isForbidden), + ginkgo.Entry("Should reject missing resources in a flavor", + &kueuealpha.Cohort{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cohort", + }, + Spec: kueuealpha.CohortSpec{ + ResourceGroups: []kueue.ResourceGroup{ + { + CoveredResources: []corev1.ResourceName{"cpu", "memory"}, + Flavors: []kueue.FlavorQuotas{ + *testing.MakeFlavorQuotas("alpha"). + Resource("cpu", "0"). + Obj(), + }, + }, + }, + }, + }, + isInvalid), + ginkgo.Entry("Should reject resource not defined in resource group", + &kueuealpha.Cohort{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cohort", + }, + Spec: kueuealpha.CohortSpec{ + ResourceGroups: []kueue.ResourceGroup{ + { + CoveredResources: []corev1.ResourceName{"cpu"}, + Flavors: []kueue.FlavorQuotas{ + *testing.MakeFlavorQuotas("alpha"). + Resource("cpu", "0"). + Resource("memory", "0"). + Obj(), + }, + }, + }, + }, + }, + isInvalid), + ginkgo.Entry("Should reject resource in more than one resource group", + testing.MakeCohort("cohort"). + ResourceGroup( + *testing.MakeFlavorQuotas("alpha"). + Resource("cpu", "0"). + Resource("memory", "0"). + Obj(), + ). + ResourceGroup( + *testing.MakeFlavorQuotas("beta"). + Resource("memory", "0"). + Obj(), + ). + Obj(), + isForbidden), + ginkgo.Entry("Should reject flavor in more than one resource group", + testing.MakeCohort("cohort"). + ResourceGroup( + *testing.MakeFlavorQuotas("alpha").Resource("cpu").Obj(), + *testing.MakeFlavorQuotas("beta").Resource("cpu").Obj(), + ). + ResourceGroup( + *testing.MakeFlavorQuotas("beta").Resource("memory").Obj(), + ). + Obj(), + isForbidden), + ) + }) + + ginkgo.When("Updating a Cohort", func() { + ginkgo.It("Should update parent", func() { + cohort := testing.MakeCohort("cohort").Obj() + gomega.Expect(k8sClient.Create(ctx, cohort)).Should(gomega.Succeed()) + + updated := cohort.DeepCopy() + updated.Spec.Parent = "cohort2" + + gomega.Expect(k8sClient.Update(ctx, updated)).Should(gomega.Succeed()) + util.ExpectObjectToBeDeleted(ctx, k8sClient, cohort, true) + }) + ginkgo.It("Should reject invalid parent", func() { + cohort := testing.MakeCohort("cohort").Obj() + gomega.Expect(k8sClient.Create(ctx, cohort)).Should(gomega.Succeed()) + + updated := cohort.DeepCopy() + updated.Spec.Parent = "@cohort2" + + gomega.Expect(k8sClient.Update(ctx, updated)).ShouldNot(gomega.Succeed()) + util.ExpectObjectToBeDeleted(ctx, k8sClient, cohort, true) + }) + ginkgo.It("Should reject negative borrowing limit", func() { + cohort := testing.MakeCohort("cohort"). + ResourceGroup(testing.MakeFlavorQuotas("x86").Resource("cpu", "-1").FlavorQuotas).Cohort + + gomega.Expect(k8sClient.Create(ctx, &cohort)).ShouldNot(gomega.Succeed()) + util.ExpectObjectToBeDeleted(ctx, k8sClient, &cohort, true) + }) + }) +}) From fde44baceac8c161eaa3a2fbed14ddd49062d65f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Szadkowski?= Date: Thu, 12 Sep 2024 04:03:12 +0200 Subject: [PATCH 024/155] [Feature] Support Kubeflow MPIJob in MultiKueue (#2880) * Introduce MultiKueue adapter for MPIJob * Add MPIJobs integration tests * Update access rights for mpijob * Remove v1 MPIJob yaml from training-operator dep-crds * Update MPIJob version to v2beta1 * Introduce mpi-operator to multikueue e2e tests Modify training-operator setup to be able to work along side mpi-operator * Reduce the amount of KFJob e2e multikueue tests due to consolidation of MultiKueue adapters for the KFJobs * Add e2e Multikueue tests for MPIJob * Apply suggestions from verify * Use one makefile target to prep kubeflow traiing-operator manifest and crds * Apply code review changes * Yet another small fix * Rework after code review * move modifications of training-operator deployment and crds to kustomize * Another rework after code review * Cleanup after manager kustomize modification --- Makefile-deps.mk | 17 +- Makefile-test.mk | 11 +- charts/kueue/templates/rbac/role.yaml | 1 + config/components/rbac/role.yaml | 1 + hack/e2e-common.sh | 24 ++- hack/multikueue-e2e-test.sh | 17 +- .../jobframework/reconciler_test.go | 10 +- pkg/controller/jobframework/setup_test.go | 16 +- pkg/controller/jobframework/validation.go | 4 +- .../jobs/mpijob/mpijob_controller.go | 45 ++-- .../jobs/mpijob/mpijob_controller_test.go | 98 ++++----- .../jobs/mpijob/mpijob_multikueue_adapter.go | 115 +++++++++++ .../mpijob/mpijob_multikueue_adapter_test.go | 160 +++++++++++++++ pkg/controller/jobs/mpijob/mpijob_webhook.go | 4 +- .../jobs/mpijob/mpijob_webhook_test.go | 6 +- .../testingjobs/mpijob/wrappers_mpijob.go | 139 +++++++++---- .../en/docs/tasks/run/kubeflow/mpijobs.md | 5 + .../create-multikueue-kubeconfig.sh | 16 ++ .../multikueue/manager/kustomization.yaml | 12 ++ .../config/multikueue/manager/patch_crds.yaml | 5 + .../multikueue/worker/kustomization.yaml | 8 + .../config/multikueue/worker/patch_crds.yaml | 5 + .../multikueue/worker/patch_deployment.yaml | 15 ++ test/e2e/multikueue/e2e_test.go | 192 +++--------------- test/e2e/multikueue/suite_test.go | 10 +- .../jobs/mpijob/mpijob_controller_test.go | 117 ++++++----- .../controller/jobs/mxjob/suite_test.go | 2 +- .../controller/jobs/paddlejob/suite_test.go | 2 +- .../controller/jobs/pytorchjob/suite_test.go | 2 +- .../controller/jobs/tfjob/suite_test.go | 2 +- .../controller/jobs/xgboostjob/suite_test.go | 2 +- test/integration/framework/framework.go | 4 +- .../integration/multikueue/multikueue_test.go | 85 +++++++- test/integration/multikueue/suite_test.go | 22 +- test/util/e2e.go | 11 +- 35 files changed, 804 insertions(+), 381 deletions(-) create mode 100644 pkg/controller/jobs/mpijob/mpijob_multikueue_adapter.go create mode 100644 pkg/controller/jobs/mpijob/mpijob_multikueue_adapter_test.go create mode 100644 test/e2e/config/multikueue/manager/kustomization.yaml create mode 100644 test/e2e/config/multikueue/manager/patch_crds.yaml create mode 100644 test/e2e/config/multikueue/worker/kustomization.yaml create mode 100644 test/e2e/config/multikueue/worker/patch_crds.yaml create mode 100644 test/e2e/config/multikueue/worker/patch_deployment.yaml diff --git a/Makefile-deps.mk b/Makefile-deps.mk index 942faf9994..dc3abe241e 100644 --- a/Makefile-deps.mk +++ b/Makefile-deps.mk @@ -111,8 +111,19 @@ mpi-operator-crd: ## Copy the CRDs from the mpi-operator to the dep-crds directo KF_TRAINING_ROOT = $(shell $(GO_CMD) list -m -mod=readonly -f "{{.Dir}}" github.com/kubeflow/training-operator) .PHONY: kf-training-operator-crd kf-training-operator-crd: ## Copy the CRDs from the training-operator to the dep-crds directory. - mkdir -p $(EXTERNAL_CRDS_DIR)/training-operator/ - cp -f $(KF_TRAINING_ROOT)/manifests/base/crds/* $(EXTERNAL_CRDS_DIR)/training-operator/ + ## Removing kubeflow.org_mpijobs.yaml is required as the version of MPIJob is conflicting between training-operator and mpi-operator - in integration tests. + mkdir -p $(EXTERNAL_CRDS_DIR)/training-operator-crds/ + find $(KF_TRAINING_ROOT)/manifests/base/crds/* -type f -not -name "kubeflow.org_mpijobs.yaml" -exec cp -pf {} $(EXTERNAL_CRDS_DIR)/training-operator-crds/ \; + +.PHONY: kf-training-operator-manifests +kf-training-operator-manifests: ## Copy whole manifests folder from the training-operator to the dep-crds directory. + ## Full version of the manifest is required for e2e multikueue tests. + if [ -d "$(EXTERNAL_CRDS_DIR)/training-operator" ]; then \ + chmod -R u+w "$(EXTERNAL_CRDS_DIR)/training-operator" && \ + rm -rf "$(EXTERNAL_CRDS_DIR)/training-operator"; \ + fi + mkdir -p "$(EXTERNAL_CRDS_DIR)/training-operator" + cp -rf "$(KF_TRAINING_ROOT)/manifests" "$(EXTERNAL_CRDS_DIR)/training-operator" RAY_ROOT = $(shell $(GO_CMD) list -m -mod=readonly -f "{{.Dir}}" github.com/ray-project/kuberay/ray-operator) .PHONY: ray-operator-crd @@ -133,7 +144,7 @@ cluster-autoscaler-crd: ## Copy the CRDs from the cluster-autoscaler to the dep- cp -f $(CLUSTER_AUTOSCALER_ROOT)/config/crd/* $(EXTERNAL_CRDS_DIR)/cluster-autoscaler/ .PHONY: dep-crds -dep-crds: mpi-operator-crd kf-training-operator-crd ray-operator-crd jobset-operator-crd cluster-autoscaler-crd ## Copy the CRDs from the external operators to the dep-crds directory. +dep-crds: mpi-operator-crd kf-training-operator-crd ray-operator-crd jobset-operator-crd cluster-autoscaler-crd kf-training-operator-manifests ## Copy the CRDs from the external operators to the dep-crds directory. @echo "Copying CRDs from external operators to dep-crds directory" .PHONY: kueuectl-docs diff --git a/Makefile-test.mk b/Makefile-test.mk index 6c4c7bf1eb..261a51c415 100644 --- a/Makefile-test.mk +++ b/Makefile-test.mk @@ -59,6 +59,7 @@ IMAGE_TAG ?= $(IMAGE_REPO):$(GIT_TAG) # JobSet Version JOBSET_VERSION = $(shell $(GO_CMD) list -m -f "{{.Version}}" sigs.k8s.io/jobset) KUBEFLOW_VERSION = $(shell $(GO_CMD) list -m -f "{{.Version}}" github.com/kubeflow/training-operator) +KUBEFLOW_MPI_VERSION = $(shell $(GO_CMD) list -m -f "{{.Version}}" github.com/kubeflow/mpi-operator) ##@ Tests @@ -67,7 +68,7 @@ test: gotestsum ## Run tests. $(GOTESTSUM) --junitfile $(ARTIFACTS)/junit.xml -- $(GO_TEST_FLAGS) $(shell $(GO_CMD) list ./... | grep -v '/test/') -coverpkg=./... -coverprofile $(ARTIFACTS)/cover.out .PHONY: test-integration -test-integration: gomod-download envtest ginkgo mpi-operator-crd ray-operator-crd jobset-operator-crd kf-training-operator-crd cluster-autoscaler-crd kueuectl ## Run tests. +test-integration: gomod-download envtest ginkgo dep-crds kueuectl ## Run tests. KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" \ KUEUE_BIN=$(PROJECT_DIR)/bin \ ENVTEST_K8S_VERSION=$(ENVTEST_K8S_VERSION) \ @@ -76,10 +77,10 @@ test-integration: gomod-download envtest ginkgo mpi-operator-crd ray-operator-cr CREATE_KIND_CLUSTER ?= true .PHONY: test-e2e -test-e2e: kustomize ginkgo yq gomod-download jobset-operator-crd kf-training-operator-crd kueuectl run-test-e2e-$(E2E_KIND_VERSION:kindest/node:v%=%) +test-e2e: kustomize ginkgo yq gomod-download dep-crds kueuectl run-test-e2e-$(E2E_KIND_VERSION:kindest/node:v%=%) .PHONY: test-multikueue-e2e -test-multikueue-e2e: kustomize ginkgo yq gomod-download jobset-operator-crd kf-training-operator-crd run-test-multikueue-e2e-$(E2E_KIND_VERSION:kindest/node:v%=%) +test-multikueue-e2e: kustomize ginkgo yq gomod-download dep-crds run-test-multikueue-e2e-$(E2E_KIND_VERSION:kindest/node:v%=%) E2E_TARGETS := $(addprefix run-test-e2e-,${E2E_K8S_VERSIONS}) @@ -92,12 +93,12 @@ FORCE: run-test-e2e-%: K8S_VERSION = $(@:run-test-e2e-%=%) run-test-e2e-%: FORCE @echo Running e2e for k8s ${K8S_VERSION} - E2E_KIND_VERSION="kindest/node:v$(K8S_VERSION)" KIND_CLUSTER_NAME=$(KIND_CLUSTER_NAME) CREATE_KIND_CLUSTER=$(CREATE_KIND_CLUSTER) ARTIFACTS="$(ARTIFACTS)/$@" IMAGE_TAG=$(IMAGE_TAG) GINKGO_ARGS="$(GINKGO_ARGS)" JOBSET_VERSION=$(JOBSET_VERSION) KUBEFLOW_VERSION=$(KUBEFLOW_VERSION) ./hack/e2e-test.sh + E2E_KIND_VERSION="kindest/node:v$(K8S_VERSION)" KIND_CLUSTER_NAME=$(KIND_CLUSTER_NAME) CREATE_KIND_CLUSTER=$(CREATE_KIND_CLUSTER) ARTIFACTS="$(ARTIFACTS)/$@" IMAGE_TAG=$(IMAGE_TAG) GINKGO_ARGS="$(GINKGO_ARGS)" JOBSET_VERSION=$(JOBSET_VERSION) KUBEFLOW_VERSION=$(KUBEFLOW_VERSION) KUBEFLOW_MPI_VERSION=$(KUBEFLOW_MPI_VERSION) ./hack/e2e-test.sh run-test-multikueue-e2e-%: K8S_VERSION = $(@:run-test-multikueue-e2e-%=%) run-test-multikueue-e2e-%: FORCE @echo Running multikueue e2e for k8s ${K8S_VERSION} - E2E_KIND_VERSION="kindest/node:v$(K8S_VERSION)" KIND_CLUSTER_NAME=$(KIND_CLUSTER_NAME) CREATE_KIND_CLUSTER=$(CREATE_KIND_CLUSTER) ARTIFACTS="$(ARTIFACTS)/$@" IMAGE_TAG=$(IMAGE_TAG) GINKGO_ARGS="$(GINKGO_ARGS)" JOBSET_VERSION=$(JOBSET_VERSION) KUBEFLOW_VERSION=$(KUBEFLOW_VERSION) ./hack/multikueue-e2e-test.sh + E2E_KIND_VERSION="kindest/node:v$(K8S_VERSION)" KIND_CLUSTER_NAME=$(KIND_CLUSTER_NAME) CREATE_KIND_CLUSTER=$(CREATE_KIND_CLUSTER) ARTIFACTS="$(ARTIFACTS)/$@" IMAGE_TAG=$(IMAGE_TAG) GINKGO_ARGS="$(GINKGO_ARGS)" JOBSET_VERSION=$(JOBSET_VERSION) KUBEFLOW_VERSION=$(KUBEFLOW_VERSION) KUBEFLOW_MPI_VERSION=$(KUBEFLOW_MPI_VERSION) ./hack/multikueue-e2e-test.sh SCALABILITY_RUNNER := $(PROJECT_DIR)/bin/performance-scheduler-runner .PHONY: performance-scheduler-runner diff --git a/charts/kueue/templates/rbac/role.yaml b/charts/kueue/templates/rbac/role.yaml index 5ad1221638..41f948e72d 100644 --- a/charts/kueue/templates/rbac/role.yaml +++ b/charts/kueue/templates/rbac/role.yaml @@ -205,6 +205,7 @@ rules: - mpijobs/status verbs: - get + - patch - update - apiGroups: - kubeflow.org diff --git a/config/components/rbac/role.yaml b/config/components/rbac/role.yaml index 4296c83b70..3eaef50b2b 100644 --- a/config/components/rbac/role.yaml +++ b/config/components/rbac/role.yaml @@ -204,6 +204,7 @@ rules: - mpijobs/status verbs: - get + - patch - update - apiGroups: - kubeflow.org diff --git a/hack/e2e-common.sh b/hack/e2e-common.sh index 850e17f098..5c1b5e9b3a 100644 --- a/hack/e2e-common.sh +++ b/hack/e2e-common.sh @@ -23,10 +23,15 @@ export JOBSET_MANIFEST="https://github.com/kubernetes-sigs/jobset/releases/downl export JOBSET_IMAGE=registry.k8s.io/jobset/jobset:${JOBSET_VERSION} export JOBSET_CRDS=${ROOT_DIR}/dep-crds/jobset-operator/ -export KUBEFLOW_MANIFEST="https://github.com/kubeflow/training-operator/manifests/overlays/standalone?ref=${KUBEFLOW_VERSION}" -#no matching semver tag unfortunately -export KUBEFLOW_IMAGE=kubeflow/training-operator:v1-855e096 -export KUBEFLOW_CRDS=${ROOT_DIR}/dep-crds/training-operator/ +export KUBEFLOW_MANIFEST_MANAGER=${ROOT_DIR}/test/e2e/config/multikueue/manager +export KUBEFLOW_MANIFEST_WORKER=${ROOT_DIR}/test/e2e/config/multikueue/worker +KUBEFLOW_IMAGE_VERSION=$($KUSTOMIZE build "$KUBEFLOW_MANIFEST_WORKER" | $YQ e 'select(.kind == "Deployment") | .spec.template.spec.containers[0].image | split(":") | .[1]') +export KUBEFLOW_IMAGE_VERSION +export KUBEFLOW_IMAGE=kubeflow/training-operator:${KUBEFLOW_IMAGE_VERSION} + +export KUBEFLOW_MPI_MANIFEST="https://raw.githubusercontent.com/kubeflow/mpi-operator/${KUBEFLOW_MPI_VERSION}/deploy/v2beta1/mpi-operator.yaml" +export KUBEFLOW_MPI_IMAGE=mpioperator/mpi-operator:${KUBEFLOW_MPI_VERSION/#v} +export KUBEFLOW_MPI_CRD=${ROOT_DIR}/dep-crds/mpi-operator/kubeflow.org_mpijobs.yaml # $1 - cluster name function cluster_cleanup { @@ -74,9 +79,16 @@ function install_jobset { #$1 - cluster name function install_kubeflow { - cluster_kind_load_image "${1}" ${KUBEFLOW_IMAGE} + cluster_kind_load_image "${1}" "${KUBEFLOW_IMAGE}" + kubectl config use-context "kind-${1}" + kubectl apply -k "${KUBEFLOW_MANIFEST_WORKER}" +} + +#$1 - cluster name +function install_mpi { + cluster_kind_load_image "${1}" "${KUBEFLOW_MPI_IMAGE/#v}" kubectl config use-context "kind-${1}" - kubectl apply -k "${KUBEFLOW_MANIFEST}" + kubectl apply --server-side -f "${KUBEFLOW_MPI_MANIFEST}" } INITIAL_IMAGE=$($YQ '.images[] | select(.name == "controller") | [.newName, .newTag] | join(":")' config/components/manager/kustomization.yaml) diff --git a/hack/multikueue-e2e-test.sh b/hack/multikueue-e2e-test.sh index 0d470bbb89..54925f56ce 100755 --- a/hack/multikueue-e2e-test.sh +++ b/hack/multikueue-e2e-test.sh @@ -41,6 +41,8 @@ function cleanup { fi #do the image restore here for the case when an error happened during deploy restore_managers_image + # Remove the `newTag` for the `kubeflow/training-operator` to revert to the default version + $YQ eval 'del(.images[] | select(.name == "kubeflow/training-operator").newTag)' -i "$KUBEFLOW_MANIFEST_MANAGER/kustomization.yaml" } @@ -80,16 +82,27 @@ function kind_load { install_jobset "$WORKER2_KIND_CLUSTER_NAME" # KUBEFLOW SETUP + # In order for MPI-operator and Training-operator to work on the same cluster it is required that: + # 1. 'kubeflow.org_mpijobs.yaml' is removed from base/crds/kustomization.yaml - https://github.com/kubeflow/training-operator/issues/1930 + # 2. Training-operator deployment is modified to enable all kubeflow jobs except for mpi - https://github.com/kubeflow/training-operator/issues/1777 + + # Modify the `newTag` for the `kubeflow/training-operator` to use the one training-operator version + $YQ eval '(.images[] | select(.name == "kubeflow/training-operator").newTag) = env(KUBEFLOW_IMAGE_VERSION)' -i "$KUBEFLOW_MANIFEST_MANAGER/kustomization.yaml" # MANAGER # Only install the CRDs and not the controller to be able to # have Kubeflow Jobs admitted without execution in the manager cluster. kubectl config use-context "kind-${MANAGER_KIND_CLUSTER_NAME}" - kubectl apply -k "${KUBEFLOW_CRDS}" + kubectl apply -k "${KUBEFLOW_MANIFEST_MANAGER}" + ## MPI + kubectl apply --server-side -f "${KUBEFLOW_MPI_CRD}" # WORKERS - docker pull kubeflow/training-operator:v1-855e096 + docker pull "${KUBEFLOW_IMAGE}" + docker pull "${KUBEFLOW_MPI_IMAGE}" install_kubeflow "$WORKER1_KIND_CLUSTER_NAME" install_kubeflow "$WORKER2_KIND_CLUSTER_NAME" + install_mpi "$WORKER1_KIND_CLUSTER_NAME" + install_mpi "$WORKER2_KIND_CLUSTER_NAME" fi } diff --git a/pkg/controller/jobframework/reconciler_test.go b/pkg/controller/jobframework/reconciler_test.go index e2d1b6ffb1..d536e3e2f9 100644 --- a/pkg/controller/jobframework/reconciler_test.go +++ b/pkg/controller/jobframework/reconciler_test.go @@ -22,7 +22,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - kubeflow "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" + kfmpi "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -59,7 +59,7 @@ func TestIsParentJobManaged(t *testing.T) { }, "child job has ownerReference with known non-existing workload owner": { job: testingjob.MakeJob(childJobName, jobNamespace). - OwnerReference(parentJobName, kubeflow.SchemeGroupVersionKind). + OwnerReference(parentJobName, kfmpi.SchemeGroupVersionKind). Obj(), wantErr: ErrWorkloadOwnerNotFound, }, @@ -69,7 +69,7 @@ func TestIsParentJobManaged(t *testing.T) { Queue("test-q"). Obj(), job: testingjob.MakeJob(childJobName, jobNamespace). - OwnerReference(parentJobName, kubeflow.SchemeGroupVersionKind). + OwnerReference(parentJobName, kfmpi.SchemeGroupVersionKind). Obj(), wantManaged: true, }, @@ -78,14 +78,14 @@ func TestIsParentJobManaged(t *testing.T) { UID(parentJobName). Obj(), job: testingjob.MakeJob(childJobName, jobNamespace). - OwnerReference(parentJobName, kubeflow.SchemeGroupVersionKind). + OwnerReference(parentJobName, kfmpi.SchemeGroupVersionKind). Obj(), }, } for name, tc := range cases { t.Run(name, func(t *testing.T) { t.Cleanup(EnableIntegrationsForTest(t, "kubeflow.org/mpijob")) - builder := utiltesting.NewClientBuilder(kubeflow.AddToScheme) + builder := utiltesting.NewClientBuilder(kfmpi.AddToScheme) if tc.parentJob != nil { builder = builder.WithObjects(tc.parentJob) } diff --git a/pkg/controller/jobframework/setup_test.go b/pkg/controller/jobframework/setup_test.go index 69f6e5cf08..988db4d408 100644 --- a/pkg/controller/jobframework/setup_test.go +++ b/pkg/controller/jobframework/setup_test.go @@ -26,7 +26,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - kubeflow "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" + kfmpi "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" kftraining "github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1" rayv1 "github.com/ray-project/kuberay/ray-operator/apis/ray/v1" batchv1 "k8s.io/api/batch/v1" @@ -58,7 +58,7 @@ func TestSetupControllers(t *testing.T) { "kubeflow.org/mpijob": { NewReconciler: testNewReconciler, SetupWebhook: testSetupWebhook, - JobType: &kubeflow.MPIJob{}, + JobType: &kfmpi.MPIJob{}, SetupIndexes: testSetupIndexes, AddToScheme: testAddToScheme, CanSupportIntegration: testCanSupportIntegration, @@ -98,7 +98,7 @@ func TestSetupControllers(t *testing.T) { }, mapperGVKs: []schema.GroupVersionKind{ batchv1.SchemeGroupVersion.WithKind("Job"), - kubeflow.SchemeGroupVersionKind, + kfmpi.SchemeGroupVersionKind, }, wantEnabledIntegrations: []string{"batch/job", "kubeflow.org/mpijob"}, }, @@ -117,7 +117,7 @@ func TestSetupControllers(t *testing.T) { }, mapperGVKs: []schema.GroupVersionKind{ batchv1.SchemeGroupVersion.WithKind("Job"), - kubeflow.SchemeGroupVersionKind, + kfmpi.SchemeGroupVersionKind, // Not including RayCluster }, delayedGVKs: []*schema.GroupVersionKind{ @@ -137,7 +137,7 @@ func TestSetupControllers(t *testing.T) { } ctx, logger := utiltesting.ContextWithLog(t) - k8sClient := utiltesting.NewClientBuilder(jobset.AddToScheme, kubeflow.AddToScheme, kftraining.AddToScheme, rayv1.AddToScheme).Build() + k8sClient := utiltesting.NewClientBuilder(jobset.AddToScheme, kfmpi.AddToScheme, kftraining.AddToScheme, rayv1.AddToScheme).Build() mgrOpts := ctrlmgr.Options{ Scheme: k8sClient.Scheme(), @@ -245,16 +245,16 @@ func TestSetupIndexes(t *testing.T) { "kubeflow.org/mpijob is disabled in the configAPI": { workloads: []kueue.Workload{ *utiltesting.MakeWorkload("alpha-wl", testNamespace). - ControllerReference(kubeflow.SchemeGroupVersionKind, "alpha", "mpijob"). + ControllerReference(kfmpi.SchemeGroupVersionKind, "alpha", "mpijob"). Obj(), *utiltesting.MakeWorkload("beta-wl", testNamespace). - ControllerReference(kubeflow.SchemeGroupVersionKind, "beta", "mpijob"). + ControllerReference(kfmpi.SchemeGroupVersionKind, "beta", "mpijob"). Obj(), }, opts: []Option{ WithEnabledFrameworks([]string{"batch/job"}), }, - filter: client.MatchingFields{GetOwnerKey(kubeflow.SchemeGroupVersionKind): "alpha"}, + filter: client.MatchingFields{GetOwnerKey(kfmpi.SchemeGroupVersionKind): "alpha"}, wantFieldMatcherError: true, }, } diff --git a/pkg/controller/jobframework/validation.go b/pkg/controller/jobframework/validation.go index 6478648c87..da355f35a0 100644 --- a/pkg/controller/jobframework/validation.go +++ b/pkg/controller/jobframework/validation.go @@ -20,6 +20,7 @@ import ( "fmt" "strings" + kfmpi "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" kftraining "github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1" batchv1 "k8s.io/api/batch/v1" apivalidation "k8s.io/apimachinery/pkg/api/validation" @@ -42,7 +43,8 @@ var ( kftraining.SchemeGroupVersion.WithKind(kftraining.TFJobKind).String(), kftraining.SchemeGroupVersion.WithKind(kftraining.PaddleJobKind).String(), kftraining.SchemeGroupVersion.WithKind(kftraining.PyTorchJobKind).String(), - kftraining.SchemeGroupVersion.WithKind(kftraining.XGBoostJobKind).String()) + kftraining.SchemeGroupVersion.WithKind(kftraining.XGBoostJobKind).String(), + kfmpi.SchemeGroupVersion.WithKind(kfmpi.Kind).String()) ) // ValidateJobOnCreate encapsulates all GenericJob validations that must be performed on a Create operation diff --git a/pkg/controller/jobs/mpijob/mpijob_controller.go b/pkg/controller/jobs/mpijob/mpijob_controller.go index 2dc7113d76..43b2c6dba1 100644 --- a/pkg/controller/jobs/mpijob/mpijob_controller.go +++ b/pkg/controller/jobs/mpijob/mpijob_controller.go @@ -21,7 +21,7 @@ import ( "fmt" "strings" - kubeflow "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" + kfmpi "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -37,7 +37,7 @@ import ( ) var ( - gvk = kubeflow.SchemeGroupVersionKind + gvk = kfmpi.SchemeGroupVersionKind FrameworkName = "kubeflow.org/mpijob" ) @@ -48,16 +48,17 @@ func init() { NewJob: NewJob, NewReconciler: NewReconciler, SetupWebhook: SetupMPIJobWebhook, - JobType: &kubeflow.MPIJob{}, - AddToScheme: kubeflow.AddToScheme, + JobType: &kfmpi.MPIJob{}, + AddToScheme: kfmpi.AddToScheme, IsManagingObjectsOwner: isMPIJob, + MultiKueueAdapter: &multikueueAdapter{}, })) } // +kubebuilder:rbac:groups=scheduling.k8s.io,resources=priorityclasses,verbs=list;get;watch // +kubebuilder:rbac:groups="",resources=events,verbs=create;watch;update;patch // +kubebuilder:rbac:groups=kubeflow.org,resources=mpijobs,verbs=get;list;watch;update;patch -// +kubebuilder:rbac:groups=kubeflow.org,resources=mpijobs/status,verbs=get;update +// +kubebuilder:rbac:groups=kubeflow.org,resources=mpijobs/status,verbs=get;update;patch // +kubebuilder:rbac:groups=kubeflow.org,resources=mpijobs/finalizers,verbs=get;update // +kubebuilder:rbac:groups=kueue.x-k8s.io,resources=workloads,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=kueue.x-k8s.io,resources=workloads/status,verbs=get;update;patch @@ -72,20 +73,20 @@ func NewJob() jobframework.GenericJob { var NewReconciler = jobframework.NewGenericReconcilerFactory(NewJob) func isMPIJob(owner *metav1.OwnerReference) bool { - return owner.Kind == "MPIJob" && strings.HasPrefix(owner.APIVersion, "kubeflow.org/v2") + return owner.Kind == "MPIJob" && strings.HasPrefix(owner.APIVersion, kfmpi.SchemeGroupVersion.Group) } -type MPIJob kubeflow.MPIJob +type MPIJob kfmpi.MPIJob var _ jobframework.GenericJob = (*MPIJob)(nil) var _ jobframework.JobWithPriorityClass = (*MPIJob)(nil) func (j *MPIJob) Object() client.Object { - return (*kubeflow.MPIJob)(j) + return (*kfmpi.MPIJob)(j) } func fromObject(o runtime.Object) *MPIJob { - return (*MPIJob)(o.(*kubeflow.MPIJob)) + return (*MPIJob)(o.(*kfmpi.MPIJob)) } func (j *MPIJob) IsSuspended() bool { @@ -110,7 +111,7 @@ func (j *MPIJob) GVK() schema.GroupVersionKind { } func (j *MPIJob) PodLabelSelector() string { - return fmt.Sprintf("%s=%s,%s=%s", kubeflow.JobNameLabel, j.Name, kubeflow.OperatorNameLabel, kubeflow.OperatorName) + return fmt.Sprintf("%s=%s,%s=%s", kfmpi.JobNameLabel, j.Name, kfmpi.OperatorNameLabel, kfmpi.OperatorName) } func (j *MPIJob) PodSets() []kueue.PodSet { @@ -160,8 +161,8 @@ func (j *MPIJob) RestorePodSetsInfo(podSetsInfo []podset.PodSetInfo) bool { func (j *MPIJob) Finished() (message string, success, finished bool) { for _, c := range j.Status.Conditions { - if (c.Type == kubeflow.JobSucceeded || c.Type == kubeflow.JobFailed) && c.Status == corev1.ConditionTrue { - return c.Message, c.Type != kubeflow.JobFailed, true + if (c.Type == kfmpi.JobSucceeded || c.Type == kfmpi.JobFailed) && c.Status == corev1.ConditionTrue { + return c.Message, c.Type != kfmpi.JobFailed, true } } @@ -178,9 +179,9 @@ func (j *MPIJob) Finished() (message string, success, finished bool) { func (j *MPIJob) PriorityClass() string { if j.Spec.RunPolicy.SchedulingPolicy != nil && len(j.Spec.RunPolicy.SchedulingPolicy.PriorityClass) != 0 { return j.Spec.RunPolicy.SchedulingPolicy.PriorityClass - } else if l := j.Spec.MPIReplicaSpecs[kubeflow.MPIReplicaTypeLauncher]; l != nil && len(l.Template.Spec.PriorityClassName) != 0 { + } else if l := j.Spec.MPIReplicaSpecs[kfmpi.MPIReplicaTypeLauncher]; l != nil && len(l.Template.Spec.PriorityClassName) != 0 { return l.Template.Spec.PriorityClassName - } else if w := j.Spec.MPIReplicaSpecs[kubeflow.MPIReplicaTypeWorker]; w != nil && len(w.Template.Spec.PriorityClassName) != 0 { + } else if w := j.Spec.MPIReplicaSpecs[kfmpi.MPIReplicaTypeWorker]; w != nil && len(w.Template.Spec.PriorityClassName) != 0 { return w.Template.Spec.PriorityClassName } return "" @@ -188,7 +189,7 @@ func (j *MPIJob) PriorityClass() string { func (j *MPIJob) PodsReady() bool { for _, c := range j.Status.Conditions { - if c.Type == kubeflow.JobRunning && c.Status == corev1.ConditionTrue { + if c.Type == kfmpi.JobRunning && c.Status == corev1.ConditionTrue { return true } } @@ -199,18 +200,18 @@ func SetupIndexes(ctx context.Context, indexer client.FieldIndexer) error { return jobframework.SetupWorkloadOwnerIndex(ctx, indexer, gvk) } -func orderedReplicaTypes(jobSpec *kubeflow.MPIJobSpec) []kubeflow.MPIReplicaType { - var result []kubeflow.MPIReplicaType - if _, ok := jobSpec.MPIReplicaSpecs[kubeflow.MPIReplicaTypeLauncher]; ok { - result = append(result, kubeflow.MPIReplicaTypeLauncher) +func orderedReplicaTypes(jobSpec *kfmpi.MPIJobSpec) []kfmpi.MPIReplicaType { + var result []kfmpi.MPIReplicaType + if _, ok := jobSpec.MPIReplicaSpecs[kfmpi.MPIReplicaTypeLauncher]; ok { + result = append(result, kfmpi.MPIReplicaTypeLauncher) } - if _, ok := jobSpec.MPIReplicaSpecs[kubeflow.MPIReplicaTypeWorker]; ok { - result = append(result, kubeflow.MPIReplicaTypeWorker) + if _, ok := jobSpec.MPIReplicaSpecs[kfmpi.MPIReplicaTypeWorker]; ok { + result = append(result, kfmpi.MPIReplicaTypeWorker) } return result } -func podsCount(jobSpec *kubeflow.MPIJobSpec, mpiReplicaType kubeflow.MPIReplicaType) int32 { +func podsCount(jobSpec *kfmpi.MPIJobSpec, mpiReplicaType kfmpi.MPIReplicaType) int32 { return ptr.Deref(jobSpec.MPIReplicaSpecs[mpiReplicaType].Replicas, 1) } diff --git a/pkg/controller/jobs/mpijob/mpijob_controller_test.go b/pkg/controller/jobs/mpijob/mpijob_controller_test.go index a051520921..095c4d869a 100644 --- a/pkg/controller/jobs/mpijob/mpijob_controller_test.go +++ b/pkg/controller/jobs/mpijob/mpijob_controller_test.go @@ -21,7 +21,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - kubeflow "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" + kfmpi "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/record" @@ -37,30 +37,30 @@ import ( func TestCalcPriorityClassName(t *testing.T) { testcases := map[string]struct { - job kubeflow.MPIJob + job kfmpi.MPIJob wantPriorityClassName string }{ "none priority class name specified": { - job: kubeflow.MPIJob{}, + job: kfmpi.MPIJob{}, wantPriorityClassName: "", }, "priority specified at runPolicy and replicas; use priority in runPolicy": { - job: kubeflow.MPIJob{ - Spec: kubeflow.MPIJobSpec{ - RunPolicy: kubeflow.RunPolicy{ - SchedulingPolicy: &kubeflow.SchedulingPolicy{ + job: kfmpi.MPIJob{ + Spec: kfmpi.MPIJobSpec{ + RunPolicy: kfmpi.RunPolicy{ + SchedulingPolicy: &kfmpi.SchedulingPolicy{ PriorityClass: "scheduling-priority", }, }, - MPIReplicaSpecs: map[kubeflow.MPIReplicaType]*kubeflow.ReplicaSpec{ - kubeflow.MPIReplicaTypeLauncher: { + MPIReplicaSpecs: map[kfmpi.MPIReplicaType]*kfmpi.ReplicaSpec{ + kfmpi.MPIReplicaTypeLauncher: { Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ PriorityClassName: "launcher-priority", }, }, }, - kubeflow.MPIReplicaTypeWorker: { + kfmpi.MPIReplicaTypeWorker: { Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ PriorityClassName: "worker-priority", @@ -73,13 +73,13 @@ func TestCalcPriorityClassName(t *testing.T) { wantPriorityClassName: "scheduling-priority", }, "runPolicy present, but without priority; fallback to launcher": { - job: kubeflow.MPIJob{ - Spec: kubeflow.MPIJobSpec{ - RunPolicy: kubeflow.RunPolicy{ - SchedulingPolicy: &kubeflow.SchedulingPolicy{}, + job: kfmpi.MPIJob{ + Spec: kfmpi.MPIJobSpec{ + RunPolicy: kfmpi.RunPolicy{ + SchedulingPolicy: &kfmpi.SchedulingPolicy{}, }, - MPIReplicaSpecs: map[kubeflow.MPIReplicaType]*kubeflow.ReplicaSpec{ - kubeflow.MPIReplicaTypeLauncher: { + MPIReplicaSpecs: map[kfmpi.MPIReplicaType]*kfmpi.ReplicaSpec{ + kfmpi.MPIReplicaTypeLauncher: { Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ PriorityClassName: "launcher-priority", @@ -92,17 +92,17 @@ func TestCalcPriorityClassName(t *testing.T) { wantPriorityClassName: "launcher-priority", }, "specified on launcher takes precedence over worker": { - job: kubeflow.MPIJob{ - Spec: kubeflow.MPIJobSpec{ - MPIReplicaSpecs: map[kubeflow.MPIReplicaType]*kubeflow.ReplicaSpec{ - kubeflow.MPIReplicaTypeLauncher: { + job: kfmpi.MPIJob{ + Spec: kfmpi.MPIJobSpec{ + MPIReplicaSpecs: map[kfmpi.MPIReplicaType]*kfmpi.ReplicaSpec{ + kfmpi.MPIReplicaTypeLauncher: { Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ PriorityClassName: "launcher-priority", }, }, }, - kubeflow.MPIReplicaTypeWorker: { + kfmpi.MPIReplicaTypeWorker: { Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ PriorityClassName: "worker-priority", @@ -115,15 +115,15 @@ func TestCalcPriorityClassName(t *testing.T) { wantPriorityClassName: "launcher-priority", }, "launcher present, but without priority; fallback to worker": { - job: kubeflow.MPIJob{ - Spec: kubeflow.MPIJobSpec{ - MPIReplicaSpecs: map[kubeflow.MPIReplicaType]*kubeflow.ReplicaSpec{ - kubeflow.MPIReplicaTypeLauncher: { + job: kfmpi.MPIJob{ + Spec: kfmpi.MPIJobSpec{ + MPIReplicaSpecs: map[kfmpi.MPIReplicaType]*kfmpi.ReplicaSpec{ + kfmpi.MPIReplicaTypeLauncher: { Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{}, }, }, - kubeflow.MPIReplicaTypeWorker: { + kfmpi.MPIReplicaTypeWorker: { Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ PriorityClassName: "worker-priority", @@ -136,11 +136,11 @@ func TestCalcPriorityClassName(t *testing.T) { wantPriorityClassName: "worker-priority", }, "specified on worker only": { - job: kubeflow.MPIJob{ - Spec: kubeflow.MPIJobSpec{ - MPIReplicaSpecs: map[kubeflow.MPIReplicaType]*kubeflow.ReplicaSpec{ - kubeflow.MPIReplicaTypeLauncher: {}, - kubeflow.MPIReplicaTypeWorker: { + job: kfmpi.MPIJob{ + Spec: kfmpi.MPIJobSpec{ + MPIReplicaSpecs: map[kfmpi.MPIReplicaType]*kfmpi.ReplicaSpec{ + kfmpi.MPIReplicaTypeLauncher: {}, + kfmpi.MPIReplicaTypeWorker: { Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ PriorityClassName: "worker-priority", @@ -153,11 +153,11 @@ func TestCalcPriorityClassName(t *testing.T) { wantPriorityClassName: "worker-priority", }, "worker present, but without priority; fallback to empty": { - job: kubeflow.MPIJob{ - Spec: kubeflow.MPIJobSpec{ - MPIReplicaSpecs: map[kubeflow.MPIReplicaType]*kubeflow.ReplicaSpec{ - kubeflow.MPIReplicaTypeLauncher: {}, - kubeflow.MPIReplicaTypeWorker: { + job: kfmpi.MPIJob{ + Spec: kfmpi.MPIJobSpec{ + MPIReplicaSpecs: map[kfmpi.MPIReplicaType]*kfmpi.ReplicaSpec{ + kfmpi.MPIReplicaTypeLauncher: {}, + kfmpi.MPIReplicaTypeWorker: { Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{}, }, @@ -183,7 +183,7 @@ func TestCalcPriorityClassName(t *testing.T) { var ( jobCmpOpts = []cmp.Option{ cmpopts.EquateEmpty(), - cmpopts.IgnoreFields(kubeflow.MPIJob{}, "TypeMeta", "ObjectMeta"), + cmpopts.IgnoreFields(kfmpi.MPIJob{}, "TypeMeta", "ObjectMeta"), } workloadCmpOpts = []cmp.Option{ cmpopts.EquateEmpty(), @@ -201,9 +201,9 @@ func TestReconciler(t *testing.T) { PriorityValue(200) cases := map[string]struct { reconcilerOptions []jobframework.Option - job *kubeflow.MPIJob + job *kfmpi.MPIJob priorityClasses []client.Object - wantJob *kubeflow.MPIJob + wantJob *kfmpi.MPIJob wantWorkloads []kueue.Workload wantErr error }{ @@ -211,8 +211,8 @@ func TestReconciler(t *testing.T) { reconcilerOptions: []jobframework.Option{ jobframework.WithManageJobsWithoutQueueName(true), }, - job: testingmpijob.MakeMPIJob("mpijob", "ns").Parallelism(2).Obj(), - wantJob: testingmpijob.MakeMPIJob("mpijob", "ns").Parallelism(2).Obj(), + job: testingmpijob.MakeMPIJob("mpijob", "ns").GenericLauncherAndWorker().Parallelism(2).Obj(), + wantJob: testingmpijob.MakeMPIJob("mpijob", "ns").GenericLauncherAndWorker().Parallelism(2).Obj(), wantWorkloads: []kueue.Workload{ *utiltesting.MakeWorkload("mpijob", "ns"). PodSets( @@ -226,11 +226,11 @@ func TestReconciler(t *testing.T) { reconcilerOptions: []jobframework.Option{ jobframework.WithManageJobsWithoutQueueName(true), }, - job: testingmpijob.MakeMPIJob("mpijob", "ns").Parallelism(2).WorkloadPriorityClass("test-wpc").Obj(), + job: testingmpijob.MakeMPIJob("mpijob", "ns").GenericLauncherAndWorker().Parallelism(2).WorkloadPriorityClass("test-wpc").Obj(), priorityClasses: []client.Object{ baseWPCWrapper.Obj(), }, - wantJob: testingmpijob.MakeMPIJob("mpijob", "ns").Parallelism(2).WorkloadPriorityClass("test-wpc").Obj(), + wantJob: testingmpijob.MakeMPIJob("mpijob", "ns").GenericLauncherAndWorker().Parallelism(2).WorkloadPriorityClass("test-wpc").Obj(), wantWorkloads: []kueue.Workload{ *utiltesting.MakeWorkload("mpijob", "ns"). PodSets( @@ -245,11 +245,11 @@ func TestReconciler(t *testing.T) { reconcilerOptions: []jobframework.Option{ jobframework.WithManageJobsWithoutQueueName(true), }, - job: testingmpijob.MakeMPIJob("mpijob", "ns").Parallelism(2).PriorityClass("test-pc").Obj(), + job: testingmpijob.MakeMPIJob("mpijob", "ns").GenericLauncherAndWorker().Parallelism(2).PriorityClass("test-pc").Obj(), priorityClasses: []client.Object{ basePCWrapper.Obj(), }, - wantJob: testingmpijob.MakeMPIJob("mpijob", "ns").Parallelism(2).PriorityClass("test-pc").Obj(), + wantJob: testingmpijob.MakeMPIJob("mpijob", "ns").GenericLauncherAndWorker().Parallelism(2).PriorityClass("test-pc").Obj(), wantWorkloads: []kueue.Workload{ *utiltesting.MakeWorkload("mpijob", "ns"). PodSets( @@ -264,12 +264,12 @@ func TestReconciler(t *testing.T) { reconcilerOptions: []jobframework.Option{ jobframework.WithManageJobsWithoutQueueName(true), }, - job: testingmpijob.MakeMPIJob("mpijob", "ns").Parallelism(2). + job: testingmpijob.MakeMPIJob("mpijob", "ns").GenericLauncherAndWorker().Parallelism(2). WorkloadPriorityClass("test-wpc").PriorityClass("test-pc").Obj(), priorityClasses: []client.Object{ basePCWrapper.Obj(), baseWPCWrapper.Obj(), }, - wantJob: testingmpijob.MakeMPIJob("mpijob", "ns").Parallelism(2). + wantJob: testingmpijob.MakeMPIJob("mpijob", "ns").GenericLauncherAndWorker().Parallelism(2). WorkloadPriorityClass("test-wpc").PriorityClass("test-pc").Obj(), wantWorkloads: []kueue.Workload{ *utiltesting.MakeWorkload("mpijob", "ns"). @@ -286,7 +286,7 @@ func TestReconciler(t *testing.T) { for name, tc := range cases { t.Run(name, func(t *testing.T) { ctx, _ := utiltesting.ContextWithLog(t) - clientBuilder := utiltesting.NewClientBuilder(kubeflow.AddToScheme) + clientBuilder := utiltesting.NewClientBuilder(kfmpi.AddToScheme) if err := SetupIndexes(ctx, utiltesting.AsIndexer(clientBuilder)); err != nil { t.Fatalf("Could not setup indexes: %v", err) } @@ -303,7 +303,7 @@ func TestReconciler(t *testing.T) { t.Errorf("Reconcile returned error (-want,+got):\n%s", diff) } - var gotMpiJob kubeflow.MPIJob + var gotMpiJob kfmpi.MPIJob if err := kClient.Get(ctx, jobKey, &gotMpiJob); err != nil { t.Fatalf("Could not get Job after reconcile: %v", err) } diff --git a/pkg/controller/jobs/mpijob/mpijob_multikueue_adapter.go b/pkg/controller/jobs/mpijob/mpijob_multikueue_adapter.go new file mode 100644 index 0000000000..a4e973fa8d --- /dev/null +++ b/pkg/controller/jobs/mpijob/mpijob_multikueue_adapter.go @@ -0,0 +1,115 @@ +/* +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 mpijob + +import ( + "context" + "errors" + "fmt" + + kfmpi "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "k8s.io/klog/v2" + "sigs.k8s.io/controller-runtime/pkg/client" + + kueuealpha "sigs.k8s.io/kueue/apis/kueue/v1alpha1" + "sigs.k8s.io/kueue/pkg/controller/constants" + "sigs.k8s.io/kueue/pkg/controller/jobframework" + "sigs.k8s.io/kueue/pkg/util/api" + clientutil "sigs.k8s.io/kueue/pkg/util/client" +) + +type multikueueAdapter struct{} + +var _ jobframework.MultiKueueAdapter = (*multikueueAdapter)(nil) + +func (b *multikueueAdapter) SyncJob(ctx context.Context, localClient client.Client, remoteClient client.Client, key types.NamespacedName, workloadName, origin string) error { + localJob := kfmpi.MPIJob{} + err := localClient.Get(ctx, key, &localJob) + if err != nil { + return err + } + + remoteJob := kfmpi.MPIJob{} + err = remoteClient.Get(ctx, key, &remoteJob) + if client.IgnoreNotFound(err) != nil { + return err + } + + // if the remote exists, just copy the status + if err == nil { + return clientutil.PatchStatus(ctx, localClient, &localJob, func() (bool, error) { + localJob.Status = remoteJob.Status + return true, nil + }) + } + + remoteJob = kfmpi.MPIJob{ + ObjectMeta: api.CloneObjectMetaForCreation(&localJob.ObjectMeta), + Spec: *localJob.Spec.DeepCopy(), + } + + // add the prebuilt workload + if remoteJob.Labels == nil { + remoteJob.Labels = make(map[string]string, 2) + } + remoteJob.Labels[constants.PrebuiltWorkloadLabel] = workloadName + remoteJob.Labels[kueuealpha.MultiKueueOriginLabel] = origin + + return remoteClient.Create(ctx, &remoteJob) +} + +func (b *multikueueAdapter) DeleteRemoteObject(ctx context.Context, remoteClient client.Client, key types.NamespacedName) error { + job := kfmpi.MPIJob{} + job.SetName(key.Name) + job.SetNamespace(key.Namespace) + return client.IgnoreNotFound(remoteClient.Delete(ctx, &job)) +} + +func (b *multikueueAdapter) KeepAdmissionCheckPending() bool { + return false +} + +func (b *multikueueAdapter) IsJobManagedByKueue(context.Context, client.Client, types.NamespacedName) (bool, string, error) { + return true, "", nil +} + +func (b *multikueueAdapter) GVK() schema.GroupVersionKind { + return gvk +} + +var _ jobframework.MultiKueueWatcher = (*multikueueAdapter)(nil) + +func (*multikueueAdapter) GetEmptyList() client.ObjectList { + return &kfmpi.MPIJobList{} +} + +func (*multikueueAdapter) WorkloadKeyFor(o runtime.Object) (types.NamespacedName, error) { + job, isJob := o.(*kfmpi.MPIJob) + if !isJob { + return types.NamespacedName{}, errors.New("not a mpijob") + } + + prebuiltWl, hasPrebuiltWorkload := job.Labels[constants.PrebuiltWorkloadLabel] + if !hasPrebuiltWorkload { + return types.NamespacedName{}, fmt.Errorf("no prebuilt workload found for mpijob: %s", klog.KObj(job)) + } + + return types.NamespacedName{Name: prebuiltWl, Namespace: job.Namespace}, nil +} diff --git a/pkg/controller/jobs/mpijob/mpijob_multikueue_adapter_test.go b/pkg/controller/jobs/mpijob/mpijob_multikueue_adapter_test.go new file mode 100644 index 0000000000..a658591707 --- /dev/null +++ b/pkg/controller/jobs/mpijob/mpijob_multikueue_adapter_test.go @@ -0,0 +1,160 @@ +/* +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 mpijob + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + kfmpi "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/interceptor" + + kueuealpha "sigs.k8s.io/kueue/apis/kueue/v1alpha1" + "sigs.k8s.io/kueue/pkg/controller/constants" + "sigs.k8s.io/kueue/pkg/util/slices" + utiltesting "sigs.k8s.io/kueue/pkg/util/testing" + utiltestingmpijob "sigs.k8s.io/kueue/pkg/util/testingjobs/mpijob" +) + +const ( + TestNamespace = "ns" +) + +func TestMultikueueAdapter(t *testing.T) { + objCheckOpts := []cmp.Option{ + cmpopts.IgnoreFields(metav1.ObjectMeta{}, "ResourceVersion"), + cmpopts.EquateEmpty(), + } + + mpiJobBuilder := utiltestingmpijob.MakeMPIJob("mpijob1", TestNamespace) + + cases := map[string]struct { + managersJobSets []kfmpi.MPIJob + workerJobSets []kfmpi.MPIJob + + operation func(ctx context.Context, adapter *multikueueAdapter, managerClient, workerClient client.Client) error + + wantError error + wantManagersJobSets []kfmpi.MPIJob + wantWorkerJobSets []kfmpi.MPIJob + }{ + + "sync creates missing remote mpijob": { + managersJobSets: []kfmpi.MPIJob{ + *mpiJobBuilder.DeepCopy(), + }, + operation: func(ctx context.Context, adapter *multikueueAdapter, managerClient, workerClient client.Client) error { + return adapter.SyncJob(ctx, managerClient, workerClient, types.NamespacedName{Name: "mpijob1", Namespace: TestNamespace}, "wl1", "origin1") + }, + + wantManagersJobSets: []kfmpi.MPIJob{ + *mpiJobBuilder.DeepCopy(), + }, + wantWorkerJobSets: []kfmpi.MPIJob{ + *mpiJobBuilder.Clone(). + Label(constants.PrebuiltWorkloadLabel, "wl1"). + Label(kueuealpha.MultiKueueOriginLabel, "origin1"). + Obj(), + }, + }, + "sync status from remote mpijob": { + managersJobSets: []kfmpi.MPIJob{ + *mpiJobBuilder.DeepCopy(), + }, + workerJobSets: []kfmpi.MPIJob{ + *mpiJobBuilder.Clone(). + Label(constants.PrebuiltWorkloadLabel, "wl1"). + Label(kueuealpha.MultiKueueOriginLabel, "origin1"). + StatusConditions(kfmpi.JobCondition{Type: kfmpi.JobSucceeded, Status: corev1.ConditionTrue}). + Obj(), + }, + operation: func(ctx context.Context, adapter *multikueueAdapter, managerClient, workerClient client.Client) error { + return adapter.SyncJob(ctx, managerClient, workerClient, types.NamespacedName{Name: "mpijob1", Namespace: TestNamespace}, "wl1", "origin1") + }, + + wantManagersJobSets: []kfmpi.MPIJob{ + *mpiJobBuilder.Clone(). + StatusConditions(kfmpi.JobCondition{Type: kfmpi.JobSucceeded, Status: corev1.ConditionTrue}). + Obj(), + }, + wantWorkerJobSets: []kfmpi.MPIJob{ + *mpiJobBuilder.Clone(). + Label(constants.PrebuiltWorkloadLabel, "wl1"). + Label(kueuealpha.MultiKueueOriginLabel, "origin1"). + StatusConditions(kfmpi.JobCondition{Type: kfmpi.JobSucceeded, Status: corev1.ConditionTrue}). + Obj(), + }, + }, + "remote mpijob is deleted": { + workerJobSets: []kfmpi.MPIJob{ + *mpiJobBuilder.Clone(). + Label(constants.PrebuiltWorkloadLabel, "wl1"). + Label(kueuealpha.MultiKueueOriginLabel, "origin1"). + Obj(), + }, + operation: func(ctx context.Context, adapter *multikueueAdapter, managerClient, workerClient client.Client) error { + return adapter.DeleteRemoteObject(ctx, workerClient, types.NamespacedName{Name: "mpijob1", Namespace: TestNamespace}) + }, + }, + } + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + managerBuilder := utiltesting.NewClientBuilder(kfmpi.AddToScheme).WithInterceptorFuncs(interceptor.Funcs{SubResourcePatch: utiltesting.TreatSSAAsStrategicMerge}) + managerBuilder = managerBuilder.WithLists(&kfmpi.MPIJobList{Items: tc.managersJobSets}) + managerBuilder = managerBuilder.WithStatusSubresource(slices.Map(tc.managersJobSets, func(w *kfmpi.MPIJob) client.Object { return w })...) + managerClient := managerBuilder.Build() + + workerBuilder := utiltesting.NewClientBuilder(kfmpi.AddToScheme).WithInterceptorFuncs(interceptor.Funcs{SubResourcePatch: utiltesting.TreatSSAAsStrategicMerge}) + workerBuilder = workerBuilder.WithLists(&kfmpi.MPIJobList{Items: tc.workerJobSets}) + workerClient := workerBuilder.Build() + + ctx, _ := utiltesting.ContextWithLog(t) + + adapter := &multikueueAdapter{} + + gotErr := tc.operation(ctx, adapter, managerClient, workerClient) + + if diff := cmp.Diff(tc.wantError, gotErr, cmpopts.EquateErrors()); diff != "" { + t.Errorf("unexpected error (-want/+got):\n%s", diff) + } + + gotManagersJobSets := &kfmpi.MPIJobList{} + if err := managerClient.List(ctx, gotManagersJobSets); err != nil { + t.Errorf("unexpected list manager's mpijobs error %s", err) + } else { + if diff := cmp.Diff(tc.wantManagersJobSets, gotManagersJobSets.Items, objCheckOpts...); diff != "" { + t.Errorf("unexpected manager's mpijobs (-want/+got):\n%s", diff) + } + } + + gotWorkerJobSets := &kfmpi.MPIJobList{} + if err := workerClient.List(ctx, gotWorkerJobSets); err != nil { + t.Errorf("unexpected list worker's mpijobs error %s", err) + } else { + if diff := cmp.Diff(tc.wantWorkerJobSets, gotWorkerJobSets.Items, objCheckOpts...); diff != "" { + t.Errorf("unexpected worker's mpijobs (-want/+got):\n%s", diff) + } + } + }) + } +} diff --git a/pkg/controller/jobs/mpijob/mpijob_webhook.go b/pkg/controller/jobs/mpijob/mpijob_webhook.go index f3167b3efd..253e75264e 100644 --- a/pkg/controller/jobs/mpijob/mpijob_webhook.go +++ b/pkg/controller/jobs/mpijob/mpijob_webhook.go @@ -19,7 +19,7 @@ package mpijob import ( "context" - kubeflow "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" + kfmpi "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/klog/v2" @@ -41,7 +41,7 @@ func SetupMPIJobWebhook(mgr ctrl.Manager, opts ...jobframework.Option) error { manageJobsWithoutQueueName: options.ManageJobsWithoutQueueName, } return ctrl.NewWebhookManagedBy(mgr). - For(&kubeflow.MPIJob{}). + For(&kfmpi.MPIJob{}). WithDefaulter(wh). WithValidator(wh). Complete() diff --git a/pkg/controller/jobs/mpijob/mpijob_webhook_test.go b/pkg/controller/jobs/mpijob/mpijob_webhook_test.go index e6e9a06ec8..57e0c2b76c 100644 --- a/pkg/controller/jobs/mpijob/mpijob_webhook_test.go +++ b/pkg/controller/jobs/mpijob/mpijob_webhook_test.go @@ -21,16 +21,16 @@ import ( "testing" "github.com/google/go-cmp/cmp" - kubeflow "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" + kfmpi "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" testingutil "sigs.k8s.io/kueue/pkg/util/testingjobs/mpijob" ) func TestDefault(t *testing.T) { testcases := map[string]struct { - job *kubeflow.MPIJob + job *kfmpi.MPIJob manageJobsWithoutQueueName bool - want *kubeflow.MPIJob + want *kfmpi.MPIJob }{ "update the suspend field with 'manageJobsWithoutQueueName=false'": { job: testingutil.MakeMPIJob("job", "default").Queue("queue").Suspend(false).Obj(), diff --git a/pkg/util/testingjobs/mpijob/wrappers_mpijob.go b/pkg/util/testingjobs/mpijob/wrappers_mpijob.go index 42be69ce49..22939f1761 100644 --- a/pkg/util/testingjobs/mpijob/wrappers_mpijob.go +++ b/pkg/util/testingjobs/mpijob/wrappers_mpijob.go @@ -17,7 +17,7 @@ limitations under the License. package testing import ( - kubeflow "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" + kfmpi "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -28,64 +28,105 @@ import ( ) // MPIJobWrapper wraps a Job. -type MPIJobWrapper struct{ kubeflow.MPIJob } +type MPIJobWrapper struct{ kfmpi.MPIJob } // MakeMPIJob creates a wrapper for a suspended job with a single container and parallelism=1. func MakeMPIJob(name, ns string) *MPIJobWrapper { - return &MPIJobWrapper{kubeflow.MPIJob{ + return &MPIJobWrapper{kfmpi.MPIJob{ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: ns, Annotations: make(map[string]string, 1), }, - Spec: kubeflow.MPIJobSpec{ - RunPolicy: kubeflow.RunPolicy{ + Spec: kfmpi.MPIJobSpec{ + RunPolicy: kfmpi.RunPolicy{ Suspend: ptr.To(true), }, - MPIReplicaSpecs: map[kubeflow.MPIReplicaType]*kubeflow.ReplicaSpec{ - kubeflow.MPIReplicaTypeLauncher: { - Replicas: ptr.To[int32](1), - Template: corev1.PodTemplateSpec{ - Spec: corev1.PodSpec{ - RestartPolicy: corev1.RestartPolicyNever, - Containers: []corev1.Container{ - { - Name: "c", - Image: "pause", - Command: []string{}, - Resources: corev1.ResourceRequirements{Requests: corev1.ResourceList{}}, - }, - }, - NodeSelector: map[string]string{}, - }, + MPIReplicaSpecs: make(map[kfmpi.MPIReplicaType]*kfmpi.ReplicaSpec), + }, + }, + } +} + +type MPIJobReplicaSpecRequirement struct { + ReplicaType kfmpi.MPIReplicaType + ReplicaCount int32 + Annotations map[string]string + RestartPolicy corev1.RestartPolicy +} + +func (j *MPIJobWrapper) MPIJobReplicaSpecs(replicaSpecs ...MPIJobReplicaSpecRequirement) *MPIJobWrapper { + j = j.GenericLauncherAndWorker() + for _, rs := range replicaSpecs { + j.Spec.MPIReplicaSpecs[rs.ReplicaType].Replicas = ptr.To[int32](rs.ReplicaCount) + j.Spec.MPIReplicaSpecs[rs.ReplicaType].Template.Spec.RestartPolicy = rs.RestartPolicy + + if rs.Annotations != nil { + j.Spec.MPIReplicaSpecs[rs.ReplicaType].Template.ObjectMeta.Annotations = rs.Annotations + } + } + + return j +} + +func (j *MPIJobWrapper) GenericLauncherAndWorker() *MPIJobWrapper { + j.Spec.MPIReplicaSpecs[kfmpi.MPIReplicaTypeLauncher] = &kfmpi.ReplicaSpec{ + Replicas: ptr.To[int32](1), + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + RestartPolicy: corev1.RestartPolicyNever, + Containers: []corev1.Container{ + { + Name: "mpijob", + Image: "pause", + Command: []string{}, + Resources: corev1.ResourceRequirements{Requests: corev1.ResourceList{}}, }, }, - kubeflow.MPIReplicaTypeWorker: { - Replicas: ptr.To[int32](1), - Template: corev1.PodTemplateSpec{ - Spec: corev1.PodSpec{ - RestartPolicy: corev1.RestartPolicyNever, - Containers: []corev1.Container{ - { - Name: "c", - Image: "pause", - Command: []string{}, - Resources: corev1.ResourceRequirements{Requests: corev1.ResourceList{}}, - }, - }, - NodeSelector: map[string]string{}, - }, + NodeSelector: map[string]string{}, + }, + }, + } + + j.Spec.MPIReplicaSpecs[kfmpi.MPIReplicaTypeWorker] = &kfmpi.ReplicaSpec{ + Replicas: ptr.To[int32](1), + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + RestartPolicy: corev1.RestartPolicyNever, + Containers: []corev1.Container{ + { + Name: "mpijob", + Image: "pause", + Command: []string{}, + Resources: corev1.ResourceRequirements{Requests: corev1.ResourceList{}}, }, }, + NodeSelector: map[string]string{}, }, }, - }} + } + + return j +} + +// Clone returns deep copy of the MPIJobWrapper. +func (j *MPIJobWrapper) Clone() *MPIJobWrapper { + return &MPIJobWrapper{MPIJob: *j.DeepCopy()} +} + +// Label sets the label key and value +func (j *MPIJobWrapper) Label(key, value string) *MPIJobWrapper { + if j.Labels == nil { + j.Labels = make(map[string]string, 1) + } + j.Labels[key] = value + return j } // PriorityClass updates job priorityclass. func (j *MPIJobWrapper) PriorityClass(pc string) *MPIJobWrapper { if j.Spec.RunPolicy.SchedulingPolicy == nil { - j.Spec.RunPolicy.SchedulingPolicy = &kubeflow.SchedulingPolicy{} + j.Spec.RunPolicy.SchedulingPolicy = &kfmpi.SchedulingPolicy{} } j.Spec.RunPolicy.SchedulingPolicy.PriorityClass = pc return j @@ -101,7 +142,7 @@ func (j *MPIJobWrapper) WorkloadPriorityClass(wpc string) *MPIJobWrapper { } // Obj returns the inner Job. -func (j *MPIJobWrapper) Obj() *kubeflow.MPIJob { +func (j *MPIJobWrapper) Obj() *kfmpi.MPIJob { return &j.MPIJob } @@ -115,14 +156,14 @@ func (j *MPIJobWrapper) Queue(queue string) *MPIJobWrapper { } // Request adds a resource request to the default container. -func (j *MPIJobWrapper) Request(replicaType kubeflow.MPIReplicaType, r corev1.ResourceName, v string) *MPIJobWrapper { +func (j *MPIJobWrapper) Request(replicaType kfmpi.MPIReplicaType, r corev1.ResourceName, v string) *MPIJobWrapper { j.Spec.MPIReplicaSpecs[replicaType].Template.Spec.Containers[0].Resources.Requests[r] = resource.MustParse(v) return j } // Parallelism updates job parallelism. func (j *MPIJobWrapper) Parallelism(p int32) *MPIJobWrapper { - j.Spec.MPIReplicaSpecs[kubeflow.MPIReplicaTypeWorker].Replicas = ptr.To(p) + j.Spec.MPIReplicaSpecs[kfmpi.MPIReplicaTypeWorker].Replicas = ptr.To(p) return j } @@ -139,7 +180,7 @@ func (j *MPIJobWrapper) UID(uid string) *MPIJobWrapper { } // PodAnnotation sets annotation at the pod template level -func (j *MPIJobWrapper) PodAnnotation(replicaType kubeflow.MPIReplicaType, k, v string) *MPIJobWrapper { +func (j *MPIJobWrapper) PodAnnotation(replicaType kfmpi.MPIReplicaType, k, v string) *MPIJobWrapper { if j.Spec.MPIReplicaSpecs[replicaType].Template.Annotations == nil { j.Spec.MPIReplicaSpecs[replicaType].Template.Annotations = make(map[string]string) } @@ -148,7 +189,7 @@ func (j *MPIJobWrapper) PodAnnotation(replicaType kubeflow.MPIReplicaType, k, v } // PodLabel sets label at the pod template level -func (j *MPIJobWrapper) PodLabel(replicaType kubeflow.MPIReplicaType, k, v string) *MPIJobWrapper { +func (j *MPIJobWrapper) PodLabel(replicaType kfmpi.MPIReplicaType, k, v string) *MPIJobWrapper { if j.Spec.MPIReplicaSpecs[replicaType].Template.Labels == nil { j.Spec.MPIReplicaSpecs[replicaType].Template.Labels = make(map[string]string) } @@ -161,3 +202,15 @@ func (j *MPIJobWrapper) Generation(num int64) *MPIJobWrapper { j.ObjectMeta.Generation = num return j } + +// StatusConditions adds a condition +func (j *MPIJobWrapper) StatusConditions(c kfmpi.JobCondition) *MPIJobWrapper { + j.Status.Conditions = append(j.Status.Conditions, c) + return j +} + +func (j *MPIJobWrapper) Image(replicaType kfmpi.MPIReplicaType, image string, args []string) *MPIJobWrapper { + j.Spec.MPIReplicaSpecs[replicaType].Template.Spec.Containers[0].Image = image + j.Spec.MPIReplicaSpecs[replicaType].Template.Spec.Containers[0].Args = args + return j +} diff --git a/site/content/en/docs/tasks/run/kubeflow/mpijobs.md b/site/content/en/docs/tasks/run/kubeflow/mpijobs.md index 7abbcbc7b5..4ff7640410 100644 --- a/site/content/en/docs/tasks/run/kubeflow/mpijobs.md +++ b/site/content/en/docs/tasks/run/kubeflow/mpijobs.md @@ -23,6 +23,11 @@ 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 %}} +{{% alert title="Note" color="primary" %}} +While using both MPI Operator and Training Operator, it is required to disable Training Operator's MPIJob option. +Training Operator deployment needs to be modified to enable all kubeflow jobs except MPIJob, as mentioned [here](https://github.com/kubeflow/training-operator/issues/1777). +{{% /alert %}} + ## MPI Operator definition ### a. Queue selection diff --git a/site/static/examples/multikueue/create-multikueue-kubeconfig.sh b/site/static/examples/multikueue/create-multikueue-kubeconfig.sh index 971d7b9d36..4ad71e36df 100644 --- a/site/static/examples/multikueue/create-multikueue-kubeconfig.sh +++ b/site/static/examples/multikueue/create-multikueue-kubeconfig.sh @@ -149,6 +149,22 @@ rules: - xgboostjobs/status verbs: - get +- apiGroups: + - kubeflow.org + resources: + - mpijobs + verbs: + - create + - delete + - get + - list + - watch +- apiGroups: + - kubeflow.org + resources: + - mpijobs/status + verbs: + - get --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding diff --git a/test/e2e/config/multikueue/manager/kustomization.yaml b/test/e2e/config/multikueue/manager/kustomization.yaml new file mode 100644 index 0000000000..bf62f9ec13 --- /dev/null +++ b/test/e2e/config/multikueue/manager/kustomization.yaml @@ -0,0 +1,12 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ../../../../../dep-crds/training-operator/manifests/base/crds +images: + - name: kubeflow/training-operator +secretGenerator: + - name: training-operator-webhook-cert + options: + disableNameSuffixHash: true +patchesStrategicMerge: + - patch_crds.yaml diff --git a/test/e2e/config/multikueue/manager/patch_crds.yaml b/test/e2e/config/multikueue/manager/patch_crds.yaml new file mode 100644 index 0000000000..85a2f63b61 --- /dev/null +++ b/test/e2e/config/multikueue/manager/patch_crds.yaml @@ -0,0 +1,5 @@ +$patch: delete +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: mpijobs.kubeflow.org \ No newline at end of file diff --git a/test/e2e/config/multikueue/worker/kustomization.yaml b/test/e2e/config/multikueue/worker/kustomization.yaml new file mode 100644 index 0000000000..3fb5f58fe6 --- /dev/null +++ b/test/e2e/config/multikueue/worker/kustomization.yaml @@ -0,0 +1,8 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: kubeflow +resources: +- ../../../../../dep-crds/training-operator/manifests/overlays/standalone +patchesStrategicMerge: +- patch_crds.yaml +- patch_deployment.yaml diff --git a/test/e2e/config/multikueue/worker/patch_crds.yaml b/test/e2e/config/multikueue/worker/patch_crds.yaml new file mode 100644 index 0000000000..85a2f63b61 --- /dev/null +++ b/test/e2e/config/multikueue/worker/patch_crds.yaml @@ -0,0 +1,5 @@ +$patch: delete +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: mpijobs.kubeflow.org \ No newline at end of file diff --git a/test/e2e/config/multikueue/worker/patch_deployment.yaml b/test/e2e/config/multikueue/worker/patch_deployment.yaml new file mode 100644 index 0000000000..41094b690a --- /dev/null +++ b/test/e2e/config/multikueue/worker/patch_deployment.yaml @@ -0,0 +1,15 @@ +$patch: merge +apiVersion: apps/v1 +kind: Deployment +metadata: + name: training-operator +spec: + template: + spec: + containers: + - name: training-operator + args: + - --enable-scheme=tfjob + - --enable-scheme=pytorchjob + - --enable-scheme=xgboostjob + - --enable-scheme=paddlejob \ No newline at end of file diff --git a/test/e2e/multikueue/e2e_test.go b/test/e2e/multikueue/e2e_test.go index 8504a54171..bf1ccf3f59 100644 --- a/test/e2e/multikueue/e2e_test.go +++ b/test/e2e/multikueue/e2e_test.go @@ -33,6 +33,7 @@ import ( versionutil "k8s.io/apimachinery/pkg/util/version" "k8s.io/utils/ptr" + kfmpi "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" "sigs.k8s.io/controller-runtime/pkg/client" jobset "sigs.k8s.io/jobset/api/jobset/v1alpha2" @@ -40,17 +41,13 @@ import ( kueue "sigs.k8s.io/kueue/apis/kueue/v1beta1" workloadjob "sigs.k8s.io/kueue/pkg/controller/jobs/job" workloadjobset "sigs.k8s.io/kueue/pkg/controller/jobs/jobset" - workloadpaddlejob "sigs.k8s.io/kueue/pkg/controller/jobs/kubeflow/jobs/paddlejob" workloadpytorchjob "sigs.k8s.io/kueue/pkg/controller/jobs/kubeflow/jobs/pytorchjob" - workloadtfjob "sigs.k8s.io/kueue/pkg/controller/jobs/kubeflow/jobs/tfjob" - workloadxgboostjob "sigs.k8s.io/kueue/pkg/controller/jobs/kubeflow/jobs/xgboostjob" + workloadmpijob "sigs.k8s.io/kueue/pkg/controller/jobs/mpijob" utiltesting "sigs.k8s.io/kueue/pkg/util/testing" testingjob "sigs.k8s.io/kueue/pkg/util/testingjobs/job" testingjobset "sigs.k8s.io/kueue/pkg/util/testingjobs/jobset" - testingpaddlejob "sigs.k8s.io/kueue/pkg/util/testingjobs/paddlejob" + testingmpijob "sigs.k8s.io/kueue/pkg/util/testingjobs/mpijob" testingpytorchjob "sigs.k8s.io/kueue/pkg/util/testingjobs/pytorchjob" - testingtfjob "sigs.k8s.io/kueue/pkg/util/testingjobs/tfjob" - testingxgboostjob "sigs.k8s.io/kueue/pkg/util/testingjobs/xgboostjob" "sigs.k8s.io/kueue/pkg/workload" "sigs.k8s.io/kueue/test/util" ) @@ -375,135 +372,6 @@ var _ = ginkgo.Describe("MultiKueue", func() { util.IgnoreConditionTimestampsAndObservedGeneration))) }) }) - ginkgo.It("Should run a kubeflow TFJob on worker if admitted", func() { - // Since it requires 1.5 CPU, this job can only be admitted in worker 1. - tfJob := testingtfjob.MakeTFJob("tfjob1", managerNs.Name). - Queue(managerLq.Name). - TFReplicaSpecs( - testingtfjob.TFReplicaSpecRequirement{ - ReplicaType: kftraining.TFJobReplicaTypeChief, - ReplicaCount: 1, - RestartPolicy: "OnFailure", - }, - testingtfjob.TFReplicaSpecRequirement{ - ReplicaType: kftraining.TFJobReplicaTypePS, - ReplicaCount: 1, - RestartPolicy: "Never", - }, - testingtfjob.TFReplicaSpecRequirement{ - ReplicaType: kftraining.TFJobReplicaTypeWorker, - ReplicaCount: 1, - RestartPolicy: "OnFailure", - }, - ). - Request(kftraining.TFJobReplicaTypeChief, corev1.ResourceCPU, "0.5"). - Request(kftraining.TFJobReplicaTypeChief, corev1.ResourceMemory, "200M"). - Request(kftraining.TFJobReplicaTypePS, corev1.ResourceCPU, "0.5"). - Request(kftraining.TFJobReplicaTypePS, corev1.ResourceMemory, "200M"). - Request(kftraining.TFJobReplicaTypeWorker, corev1.ResourceCPU, "0.5"). - Request(kftraining.TFJobReplicaTypeWorker, corev1.ResourceMemory, "100M"). - Image(kftraining.TFJobReplicaTypeChief, "gcr.io/k8s-staging-perf-tests/sleep:v0.1.0", []string{"1ms"}). - Image(kftraining.TFJobReplicaTypePS, "gcr.io/k8s-staging-perf-tests/sleep:v0.1.0", []string{"1ms"}). - Image(kftraining.TFJobReplicaTypeWorker, "gcr.io/k8s-staging-perf-tests/sleep:v0.1.0", []string{"1ms"}). - Obj() - - ginkgo.By("Creating the TfJob", func() { - gomega.Expect(k8sManagerClient.Create(ctx, tfJob)).Should(gomega.Succeed()) - }) - wlLookupKey := types.NamespacedName{Name: workloadtfjob.GetWorkloadNameForTFJob(tfJob.Name, tfJob.UID), Namespace: managerNs.Name} - - // the execution should be given to the worker1 - waitForJobAdmitted(wlLookupKey, multiKueueAc.Name, "worker1") - - ginkgo.By("Waiting for the TfJob to finish", func() { - gomega.Eventually(func(g gomega.Gomega) { - createdTfJob := &kftraining.TFJob{} - g.Expect(k8sManagerClient.Get(ctx, client.ObjectKeyFromObject(tfJob), createdTfJob)).To(gomega.Succeed()) - g.Expect(createdTfJob.Status.ReplicaStatuses[kftraining.TFJobReplicaTypeChief]).To(gomega.BeComparableTo( - &kftraining.ReplicaStatus{ - Active: 0, - Succeeded: 1, - }, - util.IgnoreConditionTimestampsAndObservedGeneration)) - - finishReasonMessage := fmt.Sprintf("TFJob %s/%s successfully completed.", tfJob.Namespace, tfJob.Name) - checkFinishStatusCondition(g, wlLookupKey, finishReasonMessage) - }, util.LongTimeout, util.Interval).Should(gomega.Succeed()) - }) - - ginkgo.By("Checking no objects are left in the worker clusters and the TfJob is completed", func() { - gomega.Eventually(func(g gomega.Gomega) { - workerWl := &kueue.Workload{} - g.Expect(k8sWorker1Client.Get(ctx, wlLookupKey, workerWl)).To(utiltesting.BeNotFoundError()) - g.Expect(k8sWorker2Client.Get(ctx, wlLookupKey, workerWl)).To(utiltesting.BeNotFoundError()) - workerTfJob := &kftraining.TFJob{} - g.Expect(k8sWorker1Client.Get(ctx, client.ObjectKeyFromObject(tfJob), workerTfJob)).To(utiltesting.BeNotFoundError()) - g.Expect(k8sWorker2Client.Get(ctx, client.ObjectKeyFromObject(tfJob), workerTfJob)).To(utiltesting.BeNotFoundError()) - }, util.Timeout, util.Interval).Should(gomega.Succeed()) - }) - }) - - ginkgo.It("Should run a kubeflow PaddleJob on worker if admitted", func() { - // Since it requires 1600M memory, this job can only be admitted in worker 2. - paddleJob := testingpaddlejob.MakePaddleJob("paddlejob1", managerNs.Name). - Queue(managerLq.Name). - PaddleReplicaSpecs( - testingpaddlejob.PaddleReplicaSpecRequirement{ - ReplicaType: kftraining.PaddleJobReplicaTypeMaster, - ReplicaCount: 1, - RestartPolicy: "OnFailure", - }, - testingpaddlejob.PaddleReplicaSpecRequirement{ - ReplicaType: kftraining.PaddleJobReplicaTypeWorker, - ReplicaCount: 1, - RestartPolicy: "OnFailure", - }, - ). - Request(kftraining.PaddleJobReplicaTypeMaster, corev1.ResourceCPU, "0.2"). - Request(kftraining.PaddleJobReplicaTypeMaster, corev1.ResourceMemory, "800M"). - Request(kftraining.PaddleJobReplicaTypeWorker, corev1.ResourceCPU, "0.2"). - Request(kftraining.PaddleJobReplicaTypeWorker, corev1.ResourceMemory, "800M"). - Image("gcr.io/k8s-staging-perf-tests/sleep:v0.1.0"). - Args([]string{"1ms"}). - Obj() - - ginkgo.By("Creating the PaddleJob", func() { - gomega.Expect(k8sManagerClient.Create(ctx, paddleJob)).Should(gomega.Succeed()) - }) - - wlLookupKey := types.NamespacedName{Name: workloadpaddlejob.GetWorkloadNameForPaddleJob(paddleJob.Name, paddleJob.UID), Namespace: managerNs.Name} - - // the execution should be given to the worker2 - waitForJobAdmitted(wlLookupKey, multiKueueAc.Name, "worker2") - - ginkgo.By("Waiting for the PaddleJob to finish", func() { - gomega.Eventually(func(g gomega.Gomega) { - createdPaddleJob := &kftraining.PaddleJob{} - g.Expect(k8sManagerClient.Get(ctx, client.ObjectKeyFromObject(paddleJob), createdPaddleJob)).To(gomega.Succeed()) - g.Expect(createdPaddleJob.Status.ReplicaStatuses[kftraining.PaddleJobReplicaTypeMaster]).To(gomega.BeComparableTo( - &kftraining.ReplicaStatus{ - Active: 0, - Succeeded: 1, - Selector: fmt.Sprintf("training.kubeflow.org/job-name=%s,training.kubeflow.org/operator-name=paddlejob-controller,training.kubeflow.org/replica-type=master", createdPaddleJob.Name), - }, - util.IgnoreConditionTimestampsAndObservedGeneration)) - - finishReasonMessage := fmt.Sprintf("PaddleJob %s is successfully completed.", paddleJob.Name) - checkFinishStatusCondition(g, wlLookupKey, finishReasonMessage) - }, util.Timeout, util.Interval).Should(gomega.Succeed()) - }) - - ginkgo.By("Checking no objects are left in the worker clusters and the PaddleJob is completed", func() { - gomega.Eventually(func(g gomega.Gomega) { - workerWl := &kueue.Workload{} - g.Expect(k8sWorker1Client.Get(ctx, wlLookupKey, workerWl)).To(utiltesting.BeNotFoundError()) - g.Expect(k8sWorker2Client.Get(ctx, wlLookupKey, workerWl)).To(utiltesting.BeNotFoundError()) - workerPaddleJob := &kftraining.PaddleJob{} - g.Expect(k8sWorker1Client.Get(ctx, client.ObjectKeyFromObject(paddleJob), workerPaddleJob)).To(utiltesting.BeNotFoundError()) - g.Expect(k8sWorker2Client.Get(ctx, client.ObjectKeyFromObject(paddleJob), workerPaddleJob)).To(utiltesting.BeNotFoundError()) - }, util.Timeout, util.Interval).Should(gomega.Succeed()) - }) - }) ginkgo.It("Should run a kubeflow PyTorchJob on worker if admitted", func() { // Since it requires 1600M of memory, this job can only be admitted in worker 2. @@ -567,65 +435,63 @@ var _ = ginkgo.Describe("MultiKueue", func() { }) }) - ginkgo.It("Should run a kubeflow XGBoostJob on worker if admitted", func() { - // Skipped due to known bug - https://github.com/kubeflow/training-operator/issues/1711 - ginkgo.Skip("Skipped due to state transitioning bug in training-operator") + ginkgo.It("Should run a MPIJob on worker if admitted", func() { // Since it requires 1.5 CPU, this job can only be admitted in worker 1. - xgboostJob := testingxgboostjob.MakeXGBoostJob("xgboostjob1", managerNs.Name). + mpijob := testingmpijob.MakeMPIJob("mpijob1", managerNs.Name). Queue(managerLq.Name). - XGBReplicaSpecs( - testingxgboostjob.XGBReplicaSpecRequirement{ - ReplicaType: kftraining.XGBoostJobReplicaTypeMaster, + MPIJobReplicaSpecs( + testingmpijob.MPIJobReplicaSpecRequirement{ + ReplicaType: kfmpi.MPIReplicaTypeLauncher, ReplicaCount: 1, RestartPolicy: "OnFailure", }, - testingxgboostjob.XGBReplicaSpecRequirement{ - ReplicaType: kftraining.XGBoostJobReplicaTypeWorker, + testingmpijob.MPIJobReplicaSpecRequirement{ + ReplicaType: kfmpi.MPIReplicaTypeWorker, ReplicaCount: 1, RestartPolicy: "OnFailure", }, ). - Request(kftraining.XGBoostJobReplicaTypeMaster, corev1.ResourceCPU, "1"). - Request(kftraining.XGBoostJobReplicaTypeMaster, corev1.ResourceMemory, "200M"). - Request(kftraining.XGBoostJobReplicaTypeWorker, corev1.ResourceCPU, "0.5"). - Request(kftraining.XGBoostJobReplicaTypeWorker, corev1.ResourceMemory, "100M"). - Image("gcr.io/k8s-staging-perf-tests/sleep:v0.1.0"). - Args([]string{"1ms"}). + Request(kfmpi.MPIReplicaTypeLauncher, corev1.ResourceCPU, "1"). + Request(kfmpi.MPIReplicaTypeLauncher, corev1.ResourceMemory, "200M"). + Request(kfmpi.MPIReplicaTypeWorker, corev1.ResourceCPU, "0.5"). + Request(kfmpi.MPIReplicaTypeWorker, corev1.ResourceMemory, "100M"). + Image(kfmpi.MPIReplicaTypeLauncher, "gcr.io/k8s-staging-perf-tests/sleep:v0.1.0", []string{"1ms"}). + Image(kfmpi.MPIReplicaTypeWorker, "gcr.io/k8s-staging-perf-tests/sleep:v0.1.0", []string{"1ms"}). Obj() - ginkgo.By("Creating the XGBoostJob", func() { - gomega.Expect(k8sManagerClient.Create(ctx, xgboostJob)).Should(gomega.Succeed()) + ginkgo.By("Creating the MPIJob", func() { + gomega.Expect(k8sManagerClient.Create(ctx, mpijob)).Should(gomega.Succeed()) }) - wlLookupKey := types.NamespacedName{Name: workloadxgboostjob.GetWorkloadNameForXGBoostJob(xgboostJob.Name, xgboostJob.UID), Namespace: managerNs.Name} + wlLookupKey := types.NamespacedName{Name: workloadmpijob.GetWorkloadNameForMPIJob(mpijob.Name, mpijob.UID), Namespace: managerNs.Name} // the execution should be given to the worker1 waitForJobAdmitted(wlLookupKey, multiKueueAc.Name, "worker1") - ginkgo.By("Waiting for the XGBoostJob to finish", func() { + ginkgo.By("Waiting for the MPIJob to finish", func() { gomega.Eventually(func(g gomega.Gomega) { - createdXGBoostJob := &kftraining.XGBoostJob{} - g.Expect(k8sManagerClient.Get(ctx, client.ObjectKeyFromObject(xgboostJob), createdXGBoostJob)).To(gomega.Succeed()) - g.Expect(createdXGBoostJob.Status.ReplicaStatuses[kftraining.XGBoostJobReplicaTypeMaster]).To(gomega.BeComparableTo( - &kftraining.ReplicaStatus{ + createdMPIJob := &kfmpi.MPIJob{} + g.Expect(k8sManagerClient.Get(ctx, client.ObjectKeyFromObject(mpijob), createdMPIJob)).To(gomega.Succeed()) + g.Expect(createdMPIJob.Status.ReplicaStatuses[kfmpi.MPIReplicaTypeLauncher]).To(gomega.BeComparableTo( + &kfmpi.ReplicaStatus{ Active: 0, Succeeded: 1, }, util.IgnoreConditionTimestampsAndObservedGeneration)) - finishReasonMessage := fmt.Sprintf("XGBoostJob %s is successfully completed.", xgboostJob.Name) + finishReasonMessage := fmt.Sprintf("MPIJob %s successfully completed.", client.ObjectKeyFromObject(mpijob).String()) checkFinishStatusCondition(g, wlLookupKey, finishReasonMessage) }, util.Timeout, util.Interval).Should(gomega.Succeed()) }) - ginkgo.By("Checking no objects are left in the worker clusters and the XGBoostJob is completed", func() { + ginkgo.By("Checking no objects are left in the worker clusters and the MPIJob is completed", func() { gomega.Eventually(func(g gomega.Gomega) { workerWl := &kueue.Workload{} g.Expect(k8sWorker1Client.Get(ctx, wlLookupKey, workerWl)).To(utiltesting.BeNotFoundError()) g.Expect(k8sWorker2Client.Get(ctx, wlLookupKey, workerWl)).To(utiltesting.BeNotFoundError()) - workerXGBoostJob := &kftraining.XGBoostJob{} - g.Expect(k8sWorker1Client.Get(ctx, client.ObjectKeyFromObject(xgboostJob), workerXGBoostJob)).To(utiltesting.BeNotFoundError()) - g.Expect(k8sWorker2Client.Get(ctx, client.ObjectKeyFromObject(xgboostJob), workerXGBoostJob)).To(utiltesting.BeNotFoundError()) + workerMPIJob := &kfmpi.MPIJob{} + g.Expect(k8sWorker1Client.Get(ctx, client.ObjectKeyFromObject(mpijob), workerMPIJob)).To(utiltesting.BeNotFoundError()) + g.Expect(k8sWorker2Client.Get(ctx, client.ObjectKeyFromObject(mpijob), workerMPIJob)).To(utiltesting.BeNotFoundError()) }, util.Timeout, util.Interval).Should(gomega.Succeed()) }) }) diff --git a/test/e2e/multikueue/suite_test.go b/test/e2e/multikueue/suite_test.go index c5a3f897f3..e40ed7696e 100644 --- a/test/e2e/multikueue/suite_test.go +++ b/test/e2e/multikueue/suite_test.go @@ -23,6 +23,7 @@ import ( "testing" "time" + kfmpi "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" kftraining "github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1" "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" @@ -95,6 +96,8 @@ func kubeconfigForMultiKueueSA(ctx context.Context, c client.Client, restConfig policyRule(kftraining.SchemeGroupVersion.Group, "pytorchjobs/status", "get"), policyRule(kftraining.SchemeGroupVersion.Group, "xgboostjobs", resourceVerbs...), policyRule(kftraining.SchemeGroupVersion.Group, "xgboostjobs/status", "get"), + policyRule(kfmpi.SchemeGroupVersion.Group, "mpijobs", resourceVerbs...), + policyRule(kfmpi.SchemeGroupVersion.Group, "mpijobs/status", "get"), }, } err := c.Create(ctx, cr) @@ -233,8 +236,11 @@ var _ = ginkgo.BeforeSuite(func() { util.WaitForJobSetAvailability(ctx, k8sWorker2Client) // there should not be a kubeflow operator in manager cluster - util.WaitForKubeFlowAvailability(ctx, k8sWorker1Client) - util.WaitForKubeFlowAvailability(ctx, k8sWorker2Client) + util.WaitForKubeFlowTrainingOperatorAvailability(ctx, k8sWorker1Client) + util.WaitForKubeFlowTrainingOperatorAvailability(ctx, k8sWorker2Client) + + util.WaitForKubeFlowMPIOperatorAvailability(ctx, k8sWorker1Client) + util.WaitForKubeFlowMPIOperatorAvailability(ctx, k8sWorker2Client) ginkgo.GinkgoLogr.Info("Kueue and JobSet operators are available in all the clusters", "waitingTime", time.Since(waitForAvailableStart)) diff --git a/test/integration/controller/jobs/mpijob/mpijob_controller_test.go b/test/integration/controller/jobs/mpijob/mpijob_controller_test.go index 4e503346e4..8ecc686044 100644 --- a/test/integration/controller/jobs/mpijob/mpijob_controller_test.go +++ b/test/integration/controller/jobs/mpijob/mpijob_controller_test.go @@ -19,7 +19,7 @@ package mpijob import ( "fmt" - kubeflow "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" + kfmpi "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" @@ -89,10 +89,12 @@ var _ = ginkgo.Describe("Job controller", ginkgo.Ordered, ginkgo.ContinueOnFailu PriorityValue(int32(priorityValue)).Obj() gomega.Expect(k8sClient.Create(ctx, priorityClass)).Should(gomega.Succeed()) - job := testingmpijob.MakeMPIJob(jobName, ns.Name).PriorityClass(priorityClassName).Obj() + job := testingmpijob.MakeMPIJob(jobName, ns.Name). + GenericLauncherAndWorker(). + PriorityClass(priorityClassName).Obj() err := k8sClient.Create(ctx, job) gomega.Expect(err).To(gomega.Succeed()) - createdJob := &kubeflow.MPIJob{} + createdJob := &kfmpi.MPIJob{} gomega.Eventually(func() bool { if err := k8sClient.Get(ctx, types.NamespacedName{Name: jobName, Namespace: ns.Name}, createdJob); err != nil { @@ -188,10 +190,10 @@ var _ = ginkgo.Describe("Job controller", ginkgo.Ordered, ginkgo.ContinueOnFailu ok, _ := testing.CheckLatestEvent(ctx, k8sClient, "Started", corev1.EventTypeNormal, fmt.Sprintf("Admitted by clusterQueue %v", clusterQueue.Name)) return ok }, util.Timeout, util.Interval).Should(gomega.BeTrue()) - gomega.Expect(createdJob.Spec.MPIReplicaSpecs[kubeflow.MPIReplicaTypeLauncher].Template.Spec.NodeSelector).Should(gomega.HaveLen(1)) - gomega.Expect(createdJob.Spec.MPIReplicaSpecs[kubeflow.MPIReplicaTypeLauncher].Template.Spec.NodeSelector[instanceKey]).Should(gomega.Equal(onDemandFlavor.Name)) - gomega.Expect(createdJob.Spec.MPIReplicaSpecs[kubeflow.MPIReplicaTypeWorker].Template.Spec.NodeSelector).Should(gomega.HaveLen(1)) - gomega.Expect(createdJob.Spec.MPIReplicaSpecs[kubeflow.MPIReplicaTypeWorker].Template.Spec.NodeSelector[instanceKey]).Should(gomega.Equal(spotFlavor.Name)) + gomega.Expect(createdJob.Spec.MPIReplicaSpecs[kfmpi.MPIReplicaTypeLauncher].Template.Spec.NodeSelector).Should(gomega.HaveLen(1)) + gomega.Expect(createdJob.Spec.MPIReplicaSpecs[kfmpi.MPIReplicaTypeLauncher].Template.Spec.NodeSelector[instanceKey]).Should(gomega.Equal(onDemandFlavor.Name)) + gomega.Expect(createdJob.Spec.MPIReplicaSpecs[kfmpi.MPIReplicaTypeWorker].Template.Spec.NodeSelector).Should(gomega.HaveLen(1)) + gomega.Expect(createdJob.Spec.MPIReplicaSpecs[kfmpi.MPIReplicaTypeWorker].Template.Spec.NodeSelector[instanceKey]).Should(gomega.Equal(spotFlavor.Name)) gomega.Eventually(func() bool { if err := k8sClient.Get(ctx, wlLookupKey, createdWorkload); err != nil { return false @@ -200,16 +202,16 @@ var _ = ginkgo.Describe("Job controller", ginkgo.Ordered, ginkgo.ContinueOnFailu }, util.Timeout, util.Interval).Should(gomega.BeTrue()) ginkgo.By("checking the job gets suspended when parallelism changes and the added node selectors are removed") - parallelism := ptr.Deref(job.Spec.MPIReplicaSpecs[kubeflow.MPIReplicaTypeWorker].Replicas, 1) + parallelism := ptr.Deref(job.Spec.MPIReplicaSpecs[kfmpi.MPIReplicaTypeWorker].Replicas, 1) newParallelism := parallelism + 1 - createdJob.Spec.MPIReplicaSpecs[kubeflow.MPIReplicaTypeWorker].Replicas = &newParallelism + createdJob.Spec.MPIReplicaSpecs[kfmpi.MPIReplicaTypeWorker].Replicas = &newParallelism gomega.Expect(k8sClient.Update(ctx, createdJob)).Should(gomega.Succeed()) gomega.Eventually(func() bool { if err := k8sClient.Get(ctx, lookupKey, createdJob); err != nil { return false } return createdJob.Spec.RunPolicy.Suspend != nil && *createdJob.Spec.RunPolicy.Suspend && - len(createdJob.Spec.MPIReplicaSpecs[kubeflow.MPIReplicaTypeWorker].Template.Spec.NodeSelector) == 0 + len(createdJob.Spec.MPIReplicaSpecs[kfmpi.MPIReplicaTypeWorker].Template.Spec.NodeSelector) == 0 }, util.Timeout, util.Interval).Should(gomega.BeTrue()) gomega.Eventually(func() bool { ok, _ := testing.CheckLatestEvent(ctx, k8sClient, "DeletedWorkload", corev1.EventTypeNormal, fmt.Sprintf("Deleted not matching Workload: %v", wlLookupKey.String())) @@ -252,10 +254,10 @@ var _ = ginkgo.Describe("Job controller", ginkgo.Ordered, ginkgo.ContinueOnFailu } return !*createdJob.Spec.RunPolicy.Suspend }, util.Timeout, util.Interval).Should(gomega.BeTrue()) - gomega.Expect(createdJob.Spec.MPIReplicaSpecs[kubeflow.MPIReplicaTypeLauncher].Template.Spec.NodeSelector).Should(gomega.HaveLen(1)) - gomega.Expect(createdJob.Spec.MPIReplicaSpecs[kubeflow.MPIReplicaTypeLauncher].Template.Spec.NodeSelector[instanceKey]).Should(gomega.Equal(onDemandFlavor.Name)) - gomega.Expect(createdJob.Spec.MPIReplicaSpecs[kubeflow.MPIReplicaTypeWorker].Template.Spec.NodeSelector).Should(gomega.HaveLen(1)) - gomega.Expect(createdJob.Spec.MPIReplicaSpecs[kubeflow.MPIReplicaTypeWorker].Template.Spec.NodeSelector[instanceKey]).Should(gomega.Equal(spotFlavor.Name)) + gomega.Expect(createdJob.Spec.MPIReplicaSpecs[kfmpi.MPIReplicaTypeLauncher].Template.Spec.NodeSelector).Should(gomega.HaveLen(1)) + gomega.Expect(createdJob.Spec.MPIReplicaSpecs[kfmpi.MPIReplicaTypeLauncher].Template.Spec.NodeSelector[instanceKey]).Should(gomega.Equal(onDemandFlavor.Name)) + gomega.Expect(createdJob.Spec.MPIReplicaSpecs[kfmpi.MPIReplicaTypeWorker].Template.Spec.NodeSelector).Should(gomega.HaveLen(1)) + gomega.Expect(createdJob.Spec.MPIReplicaSpecs[kfmpi.MPIReplicaTypeWorker].Template.Spec.NodeSelector[instanceKey]).Should(gomega.Equal(spotFlavor.Name)) gomega.Eventually(func() bool { if err := k8sClient.Get(ctx, wlLookupKey, createdWorkload); err != nil { return false @@ -265,8 +267,8 @@ var _ = ginkgo.Describe("Job controller", ginkgo.Ordered, ginkgo.ContinueOnFailu ginkgo.By("checking the workload is finished when job is completed") createdJob.Status.Conditions = append(createdJob.Status.Conditions, - kubeflow.JobCondition{ - Type: kubeflow.JobSucceeded, + kfmpi.JobCondition{ + Type: kfmpi.JobSucceeded, Status: corev1.ConditionTrue, LastTransitionTime: metav1.Now(), }) @@ -316,11 +318,12 @@ var _ = ginkgo.Describe("Job controller", ginkgo.Ordered, ginkgo.ContinueOnFailu ginkgo.It("labels and annotations should be propagated from admission check to job", func() { job := testingmpijob.MakeMPIJob(jobName, ns.Name). + GenericLauncherAndWorker(). Queue(localQueue.Name). - PodAnnotation(kubeflow.MPIReplicaTypeWorker, "old-ann-key", "old-ann-value"). - PodLabel(kubeflow.MPIReplicaTypeWorker, "old-label-key", "old-label-value"). + PodAnnotation(kfmpi.MPIReplicaTypeWorker, "old-ann-key", "old-ann-value"). + PodLabel(kfmpi.MPIReplicaTypeWorker, "old-label-key", "old-label-value"). Obj() - createdJob := &kubeflow.MPIJob{} + createdJob := &kfmpi.MPIJob{} createdWorkload := &kueue.Workload{} ginkgo.By("creating the job with pod labels & annotations", func() { @@ -407,7 +410,7 @@ var _ = ginkgo.Describe("Job controller", ginkgo.Ordered, ginkgo.ContinueOnFailu }) ginkgo.By("verify the PodSetUpdates are propagated to the running job, for worker", func() { - worker := createdJob.Spec.MPIReplicaSpecs[kubeflow.MPIReplicaTypeWorker].Template + worker := createdJob.Spec.MPIReplicaSpecs[kfmpi.MPIReplicaTypeWorker].Template gomega.Expect(worker.Annotations).Should(gomega.HaveKeyWithValue("ann1", "ann-value1")) gomega.Expect(worker.Annotations).Should(gomega.HaveKeyWithValue("old-ann-key", "old-ann-value")) gomega.Expect(worker.Labels).Should(gomega.HaveKeyWithValue("label1", "label-value1")) @@ -427,7 +430,7 @@ var _ = ginkgo.Describe("Job controller", ginkgo.Ordered, ginkgo.ContinueOnFailu }) ginkgo.By("verify the node selectors are propagated to the running job, for launcher", func() { - launcher := createdJob.Spec.MPIReplicaSpecs[kubeflow.MPIReplicaTypeLauncher].Template + launcher := createdJob.Spec.MPIReplicaSpecs[kfmpi.MPIReplicaTypeLauncher].Template gomega.Expect(launcher.Spec.NodeSelector).Should(gomega.HaveKeyWithValue(instanceKey, "test-flavor")) }) @@ -449,7 +452,7 @@ var _ = ginkgo.Describe("Job controller", ginkgo.Ordered, ginkgo.ContinueOnFailu }) ginkgo.By("verify the PodSetUpdates are restored for worker", func() { - worker := createdJob.Spec.MPIReplicaSpecs[kubeflow.MPIReplicaTypeWorker].Template + worker := createdJob.Spec.MPIReplicaSpecs[kfmpi.MPIReplicaTypeWorker].Template gomega.Expect(worker.Annotations).ShouldNot(gomega.HaveKey("ann1")) gomega.Expect(worker.Annotations).Should(gomega.HaveKeyWithValue("old-ann-key", "old-ann-value")) gomega.Expect(worker.Labels).ShouldNot(gomega.HaveKey("label1")) @@ -459,7 +462,7 @@ var _ = ginkgo.Describe("Job controller", ginkgo.Ordered, ginkgo.ContinueOnFailu }) ginkgo.By("verify the PodSetUpdates are restored for launcher", func() { - launcher := createdJob.Spec.MPIReplicaSpecs[kubeflow.MPIReplicaTypeLauncher].Template + launcher := createdJob.Spec.MPIReplicaSpecs[kfmpi.MPIReplicaTypeLauncher].Template gomega.Expect(launcher.Annotations).ShouldNot(gomega.HaveKey("ann1")) gomega.Expect(launcher.Labels).ShouldNot(gomega.HaveKey("label1")) gomega.Expect(launcher.Spec.NodeSelector).ShouldNot(gomega.HaveKey(instanceKey)) @@ -503,10 +506,10 @@ var _ = ginkgo.Describe("Job controller for workloads when only jobs with queue ginkgo.It("Should reconcile jobs only when queue is set", func() { ginkgo.By("checking the workload is not created when queue name is not set") - job := testingmpijob.MakeMPIJob(jobName, ns.Name).Obj() + job := testingmpijob.MakeMPIJob(jobName, ns.Name).GenericLauncherAndWorker().Obj() gomega.Expect(k8sClient.Create(ctx, job)).Should(gomega.Succeed()) lookupKey := types.NamespacedName{Name: jobName, Namespace: ns.Name} - createdJob := &kubeflow.MPIJob{} + createdJob := &kfmpi.MPIJob{} gomega.Expect(k8sClient.Get(ctx, lookupKey, createdJob)).Should(gomega.Succeed()) createdWorkload := &kueue.Workload{} @@ -534,7 +537,7 @@ var _ = ginkgo.Describe("Job controller for workloads when only jobs with queue ginkgo.By("Creating the child job") childJob := testingjob.MakeJob(childJobName, ns.Name). - OwnerReference(parentJobName, kubeflow.SchemeGroupVersionKind). + OwnerReference(parentJobName, kfmpi.SchemeGroupVersionKind). Suspend(false). Obj() gomega.Expect(ctrl.SetControllerReference(parentJob, childJob, k8sClient.Scheme())).To(gomega.Succeed()) @@ -557,7 +560,7 @@ var _ = ginkgo.Describe("Job controller for workloads when only jobs with queue ginkgo.By("Creating the child job which has ownerReference with known existing workload owner") childJob := testingjob.MakeJob(childJobName, ns.Name). - OwnerReference(parentJobName, kubeflow.SchemeGroupVersionKind). + OwnerReference(parentJobName, kfmpi.SchemeGroupVersionKind). Suspend(false). Obj() gomega.Expect(ctrl.SetControllerReference(parentJob, childJob, k8sClient.Scheme())).To(gomega.Succeed()) @@ -573,9 +576,9 @@ var _ = ginkgo.Describe("Job controller for workloads when only jobs with queue var _ = ginkgo.Describe("Job controller when waitForPodsReady enabled", ginkgo.Ordered, ginkgo.ContinueOnFailure, func() { type podsReadyTestSpec struct { - beforeJobStatus *kubeflow.JobStatus + beforeJobStatus *kfmpi.JobStatus beforeCondition *metav1.Condition - jobStatus kubeflow.JobStatus + jobStatus kfmpi.JobStatus suspended bool wantCondition *metav1.Condition } @@ -616,12 +619,14 @@ var _ = ginkgo.Describe("Job controller when waitForPodsReady enabled", ginkgo.O ginkgo.DescribeTable("Single job at different stages of progress towards completion", func(podsReadyTestSpec podsReadyTestSpec) { ginkgo.By("Create a job") - job := testingmpijob.MakeMPIJob(jobName, ns.Name).Parallelism(2).Obj() + job := testingmpijob.MakeMPIJob(jobName, ns.Name). + GenericLauncherAndWorker(). + Parallelism(2).Obj() jobQueueName := "test-queue" job.Annotations = map[string]string{constants.QueueAnnotation: jobQueueName} gomega.Expect(k8sClient.Create(ctx, job)).Should(gomega.Succeed()) lookupKey := types.NamespacedName{Name: jobName, Namespace: ns.Name} - createdJob := &kubeflow.MPIJob{} + createdJob := &kfmpi.MPIJob{} gomega.Expect(k8sClient.Get(ctx, lookupKey, createdJob)).Should(gomega.Succeed()) ginkgo.By("Fetch the workload created for the job") @@ -708,10 +713,10 @@ var _ = ginkgo.Describe("Job controller when waitForPodsReady enabled", ginkgo.O }, }), ginkgo.Entry("Running MPIJob", podsReadyTestSpec{ - jobStatus: kubeflow.JobStatus{ - Conditions: []kubeflow.JobCondition{ + jobStatus: kfmpi.JobStatus{ + Conditions: []kfmpi.JobCondition{ { - Type: kubeflow.JobRunning, + Type: kfmpi.JobRunning, Status: corev1.ConditionTrue, Reason: "Running", }, @@ -731,10 +736,10 @@ var _ = ginkgo.Describe("Job controller when waitForPodsReady enabled", ginkgo.O Reason: "PodsReady", Message: "Not all pods are ready or succeeded", }, - jobStatus: kubeflow.JobStatus{ - Conditions: []kubeflow.JobCondition{ + jobStatus: kfmpi.JobStatus{ + Conditions: []kfmpi.JobCondition{ { - Type: kubeflow.JobRunning, + Type: kfmpi.JobRunning, Status: corev1.ConditionTrue, Reason: "Running", }, @@ -748,10 +753,10 @@ var _ = ginkgo.Describe("Job controller when waitForPodsReady enabled", ginkgo.O }, }), ginkgo.Entry("Job suspended; PodsReady=True before", podsReadyTestSpec{ - beforeJobStatus: &kubeflow.JobStatus{ - Conditions: []kubeflow.JobCondition{ + beforeJobStatus: &kfmpi.JobStatus{ + Conditions: []kfmpi.JobCondition{ { - Type: kubeflow.JobRunning, + Type: kfmpi.JobRunning, Status: corev1.ConditionTrue, Reason: "Running", }, @@ -763,10 +768,10 @@ var _ = ginkgo.Describe("Job controller when waitForPodsReady enabled", ginkgo.O Reason: "PodsReady", Message: "All pods were ready or succeeded since the workload admission", }, - jobStatus: kubeflow.JobStatus{ - Conditions: []kubeflow.JobCondition{ + jobStatus: kfmpi.JobStatus{ + Conditions: []kfmpi.JobCondition{ { - Type: kubeflow.JobRunning, + Type: kfmpi.JobRunning, Status: corev1.ConditionFalse, Reason: "Suspended", }, @@ -839,18 +844,19 @@ var _ = ginkgo.Describe("Job controller interacting with scheduler", ginkgo.Orde ginkgo.By("checking a dev job starts") job := testingmpijob.MakeMPIJob("dev-job", ns.Name).Queue(localQueue.Name). - Request(kubeflow.MPIReplicaTypeLauncher, corev1.ResourceCPU, "3"). - Request(kubeflow.MPIReplicaTypeWorker, corev1.ResourceCPU, "4"). + GenericLauncherAndWorker(). + Request(kfmpi.MPIReplicaTypeLauncher, corev1.ResourceCPU, "3"). + Request(kfmpi.MPIReplicaTypeWorker, corev1.ResourceCPU, "4"). Obj() gomega.Expect(k8sClient.Create(ctx, job)).Should(gomega.Succeed()) - createdJob := &kubeflow.MPIJob{} + createdJob := &kfmpi.MPIJob{} gomega.Eventually(func() *bool { gomega.Expect(k8sClient.Get(ctx, types.NamespacedName{Name: job.Name, Namespace: job.Namespace}, createdJob)). Should(gomega.Succeed()) return createdJob.Spec.RunPolicy.Suspend }, util.Timeout, util.Interval).Should(gomega.Equal(ptr.To(false))) - gomega.Expect(createdJob.Spec.MPIReplicaSpecs[kubeflow.MPIReplicaTypeLauncher].Template.Spec.NodeSelector[instanceKey]).Should(gomega.Equal(spotUntaintedFlavor.Name)) - gomega.Expect(createdJob.Spec.MPIReplicaSpecs[kubeflow.MPIReplicaTypeWorker].Template.Spec.NodeSelector[instanceKey]).Should(gomega.Equal(onDemandFlavor.Name)) + gomega.Expect(createdJob.Spec.MPIReplicaSpecs[kfmpi.MPIReplicaTypeLauncher].Template.Spec.NodeSelector[instanceKey]).Should(gomega.Equal(spotUntaintedFlavor.Name)) + gomega.Expect(createdJob.Spec.MPIReplicaSpecs[kfmpi.MPIReplicaTypeWorker].Template.Spec.NodeSelector[instanceKey]).Should(gomega.Equal(onDemandFlavor.Name)) util.ExpectPendingWorkloadsMetric(clusterQueue, 0, 0) util.ExpectReservingActiveWorkloadsMetric(clusterQueue, 1) }) @@ -859,14 +865,15 @@ var _ = ginkgo.Describe("Job controller interacting with scheduler", ginkgo.Orde ginkgo.It("Should restore the original node selectors", func() { localQueue := testing.MakeLocalQueue("local-queue", ns.Name).ClusterQueue(clusterQueue.Name).Obj() job := testingmpijob.MakeMPIJob(jobName, ns.Name).Queue(localQueue.Name). - Request(kubeflow.MPIReplicaTypeLauncher, corev1.ResourceCPU, "3"). - Request(kubeflow.MPIReplicaTypeWorker, corev1.ResourceCPU, "4"). + GenericLauncherAndWorker(). + Request(kfmpi.MPIReplicaTypeLauncher, corev1.ResourceCPU, "3"). + Request(kfmpi.MPIReplicaTypeWorker, corev1.ResourceCPU, "4"). Obj() lookupKey := types.NamespacedName{Name: job.Name, Namespace: job.Namespace} - createdJob := &kubeflow.MPIJob{} + createdJob := &kfmpi.MPIJob{} - nodeSelectors := func(j *kubeflow.MPIJob) map[kubeflow.MPIReplicaType]map[string]string { - ret := map[kubeflow.MPIReplicaType]map[string]string{} + nodeSelectors := func(j *kfmpi.MPIJob) map[kfmpi.MPIReplicaType]map[string]string { + ret := map[kfmpi.MPIReplicaType]map[string]string{} for k := range j.Spec.MPIReplicaSpecs { ret[k] = j.Spec.MPIReplicaSpecs[k].Template.Spec.NodeSelector } @@ -899,7 +906,7 @@ var _ = ginkgo.Describe("Job controller interacting with scheduler", ginkgo.Orde }) ginkgo.By("the node selectors should be updated", func() { - gomega.Eventually(func() map[kubeflow.MPIReplicaType]map[string]string { + gomega.Eventually(func() map[kfmpi.MPIReplicaType]map[string]string { gomega.Expect(k8sClient.Get(ctx, lookupKey, createdJob)).Should(gomega.Succeed()) return nodeSelectors(createdJob) }, util.Timeout, util.Interval).ShouldNot(gomega.Equal(originalNodeSelectors)) @@ -918,7 +925,7 @@ var _ = ginkgo.Describe("Job controller interacting with scheduler", ginkgo.Orde }) ginkgo.By("the node selectors should be restored", func() { - gomega.Eventually(func() map[kubeflow.MPIReplicaType]map[string]string { + gomega.Eventually(func() map[kfmpi.MPIReplicaType]map[string]string { gomega.Expect(k8sClient.Get(ctx, lookupKey, createdJob)).Should(gomega.Succeed()) return nodeSelectors(createdJob) }, util.Timeout, util.Interval).Should(gomega.Equal(originalNodeSelectors)) diff --git a/test/integration/controller/jobs/mxjob/suite_test.go b/test/integration/controller/jobs/mxjob/suite_test.go index f29689c1b5..396a275333 100644 --- a/test/integration/controller/jobs/mxjob/suite_test.go +++ b/test/integration/controller/jobs/mxjob/suite_test.go @@ -45,7 +45,7 @@ var ( ctx context.Context fwk *framework.Framework crdPath = filepath.Join("..", "..", "..", "..", "..", "config", "components", "crd", "bases") - mxnetCrdPath = filepath.Join("..", "..", "..", "..", "..", "dep-crds", "training-operator") + mxnetCrdPath = filepath.Join("..", "..", "..", "..", "..", "dep-crds", "training-operator-crds") ) func TestAPIs(t *testing.T) { diff --git a/test/integration/controller/jobs/paddlejob/suite_test.go b/test/integration/controller/jobs/paddlejob/suite_test.go index 754bbb9334..40865b3508 100644 --- a/test/integration/controller/jobs/paddlejob/suite_test.go +++ b/test/integration/controller/jobs/paddlejob/suite_test.go @@ -45,7 +45,7 @@ var ( ctx context.Context fwk *framework.Framework crdPath = filepath.Join("..", "..", "..", "..", "..", "config", "components", "crd", "bases") - paddleCrdPath = filepath.Join("..", "..", "..", "..", "..", "dep-crds", "training-operator") + paddleCrdPath = filepath.Join("..", "..", "..", "..", "..", "dep-crds", "training-operator-crds") ) func TestAPIs(t *testing.T) { diff --git a/test/integration/controller/jobs/pytorchjob/suite_test.go b/test/integration/controller/jobs/pytorchjob/suite_test.go index 7cf5924791..bd199bfa8b 100644 --- a/test/integration/controller/jobs/pytorchjob/suite_test.go +++ b/test/integration/controller/jobs/pytorchjob/suite_test.go @@ -45,7 +45,7 @@ var ( ctx context.Context fwk *framework.Framework crdPath = filepath.Join("..", "..", "..", "..", "..", "config", "components", "crd", "bases") - pytorchCrdPath = filepath.Join("..", "..", "..", "..", "..", "dep-crds", "training-operator") + pytorchCrdPath = filepath.Join("..", "..", "..", "..", "..", "dep-crds", "training-operator-crds") ) func TestAPIs(t *testing.T) { diff --git a/test/integration/controller/jobs/tfjob/suite_test.go b/test/integration/controller/jobs/tfjob/suite_test.go index 1689c80ea0..9293bd6497 100644 --- a/test/integration/controller/jobs/tfjob/suite_test.go +++ b/test/integration/controller/jobs/tfjob/suite_test.go @@ -45,7 +45,7 @@ var ( ctx context.Context fwk *framework.Framework crdPath = filepath.Join("..", "..", "..", "..", "..", "config", "components", "crd", "bases") - tensorflowCrdPath = filepath.Join("..", "..", "..", "..", "..", "dep-crds", "training-operator") + tensorflowCrdPath = filepath.Join("..", "..", "..", "..", "..", "dep-crds", "training-operator-crds") ) func TestAPIs(t *testing.T) { diff --git a/test/integration/controller/jobs/xgboostjob/suite_test.go b/test/integration/controller/jobs/xgboostjob/suite_test.go index ca5fd57e8b..726020bb33 100644 --- a/test/integration/controller/jobs/xgboostjob/suite_test.go +++ b/test/integration/controller/jobs/xgboostjob/suite_test.go @@ -45,7 +45,7 @@ var ( ctx context.Context fwk *framework.Framework crdPath = filepath.Join("..", "..", "..", "..", "..", "config", "components", "crd", "bases") - xgbCrdPath = filepath.Join("..", "..", "..", "..", "..", "dep-crds", "training-operator") + xgbCrdPath = filepath.Join("..", "..", "..", "..", "..", "dep-crds", "training-operator-crds") ) func TestAPIs(t *testing.T) { diff --git a/test/integration/framework/framework.go b/test/integration/framework/framework.go index fe50fc107b..5cf3960155 100644 --- a/test/integration/framework/framework.go +++ b/test/integration/framework/framework.go @@ -26,7 +26,7 @@ import ( "strings" "time" - kubeflow "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" + kfmpi "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" kftraining "github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1" "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" @@ -97,7 +97,7 @@ func (f *Framework) SetupClient(cfg *rest.Config) (context.Context, client.Clien err = kueuealpha.AddToScheme(scheme.Scheme) gomega.ExpectWithOffset(1, err).NotTo(gomega.HaveOccurred()) - err = kubeflow.AddToScheme(scheme.Scheme) + err = kfmpi.AddToScheme(scheme.Scheme) gomega.ExpectWithOffset(1, err).NotTo(gomega.HaveOccurred()) err = rayv1.AddToScheme(scheme.Scheme) diff --git a/test/integration/multikueue/multikueue_test.go b/test/integration/multikueue/multikueue_test.go index b347a16b24..f44a6c609a 100644 --- a/test/integration/multikueue/multikueue_test.go +++ b/test/integration/multikueue/multikueue_test.go @@ -23,6 +23,7 @@ import ( "time" "github.com/google/go-cmp/cmp/cmpopts" + kfmpi "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" kftraining "github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1" "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" @@ -41,14 +42,18 @@ import ( "sigs.k8s.io/kueue/pkg/controller/admissionchecks/multikueue" workloadjob "sigs.k8s.io/kueue/pkg/controller/jobs/job" workloadjobset "sigs.k8s.io/kueue/pkg/controller/jobs/jobset" + workloadpaddlejob "sigs.k8s.io/kueue/pkg/controller/jobs/kubeflow/jobs/paddlejob" workloadpytorchjob "sigs.k8s.io/kueue/pkg/controller/jobs/kubeflow/jobs/pytorchjob" workloadtfjob "sigs.k8s.io/kueue/pkg/controller/jobs/kubeflow/jobs/tfjob" workloadxgboostjob "sigs.k8s.io/kueue/pkg/controller/jobs/kubeflow/jobs/xgboostjob" + workloadmpijob "sigs.k8s.io/kueue/pkg/controller/jobs/mpijob" "sigs.k8s.io/kueue/pkg/features" utiltesting "sigs.k8s.io/kueue/pkg/util/testing" testingjob "sigs.k8s.io/kueue/pkg/util/testingjobs/job" testingjobset "sigs.k8s.io/kueue/pkg/util/testingjobs/jobset" + testingmpijob "sigs.k8s.io/kueue/pkg/util/testingjobs/mpijob" + testingpaddlejob "sigs.k8s.io/kueue/pkg/util/testingjobs/paddlejob" testingpytorchjob "sigs.k8s.io/kueue/pkg/util/testingjobs/pytorchjob" testingtfjob "sigs.k8s.io/kueue/pkg/util/testingjobs/tfjob" @@ -947,7 +952,7 @@ var _ = ginkgo.Describe("Multikueue", ginkgo.Ordered, ginkgo.ContinueOnFailure, }) ginkgo.It("Should run a XGBoostJob on worker if admitted", func() { - xgBoostJob := testingxgboostjob.MakeXGBoostJob("pytorchjob1", managerNs.Name). + xgBoostJob := testingxgboostjob.MakeXGBoostJob("xgboostjob1", managerNs.Name). Queue(managerLq.Name). XGBReplicaSpecs( testingxgboostjob.XGBReplicaSpecRequirement{ @@ -1026,6 +1031,84 @@ var _ = ginkgo.Describe("Multikueue", ginkgo.Ordered, ginkgo.ContinueOnFailure, }) }) + ginkgo.It("Should run a MPIJob on worker if admitted", func() { + mpijob := testingmpijob.MakeMPIJob("mpijob1", managerNs.Name). + Queue(managerLq.Name). + MPIJobReplicaSpecs( + testingmpijob.MPIJobReplicaSpecRequirement{ + ReplicaType: kfmpi.MPIReplicaTypeLauncher, + ReplicaCount: 1, + RestartPolicy: corev1.RestartPolicyOnFailure, + }, + testingmpijob.MPIJobReplicaSpecRequirement{ + ReplicaType: kfmpi.MPIReplicaTypeWorker, + ReplicaCount: 1, + RestartPolicy: corev1.RestartPolicyNever, + }, + ). + Obj() + gomega.Expect(managerTestCluster.client.Create(managerTestCluster.ctx, mpijob)).Should(gomega.Succeed()) + + wlLookupKey := types.NamespacedName{Name: workloadmpijob.GetWorkloadNameForMPIJob(mpijob.Name, mpijob.UID), Namespace: managerNs.Name} + admission := utiltesting.MakeAdmission(managerCq.Name).PodSets( + kueue.PodSetAssignment{ + Name: "launcher", + }, kueue.PodSetAssignment{ + Name: "worker", + }, + ) + + admitWorkloadAndCheckWorkerCopies(multikueueAC.Name, wlLookupKey, admission) + + ginkgo.By("changing the status of the MPIJob in the worker, updates the manager's MPIJob status", func() { + gomega.Eventually(func(g gomega.Gomega) { + createdMPIJob := kfmpi.MPIJob{} + g.Expect(worker2TestCluster.client.Get(worker2TestCluster.ctx, client.ObjectKeyFromObject(mpijob), &createdMPIJob)).To(gomega.Succeed()) + createdMPIJob.Status.ReplicaStatuses = map[kfmpi.MPIReplicaType]*kfmpi.ReplicaStatus{ + kfmpi.MPIReplicaTypeLauncher: { + Active: 1, + }, + kfmpi.MPIReplicaTypeWorker: { + Active: 1, + Succeeded: 1, + }, + } + g.Expect(worker2TestCluster.client.Status().Update(worker2TestCluster.ctx, &createdMPIJob)).To(gomega.Succeed()) + }, util.Timeout, util.Interval).Should(gomega.Succeed()) + gomega.Eventually(func(g gomega.Gomega) { + createdMPIJob := kfmpi.MPIJob{} + g.Expect(managerTestCluster.client.Get(managerTestCluster.ctx, client.ObjectKeyFromObject(mpijob), &createdMPIJob)).To(gomega.Succeed()) + g.Expect(createdMPIJob.Status.ReplicaStatuses).To(gomega.Equal( + map[kfmpi.MPIReplicaType]*kfmpi.ReplicaStatus{ + kfmpi.MPIReplicaTypeLauncher: { + Active: 1, + }, + kfmpi.MPIReplicaTypeWorker: { + Active: 1, + Succeeded: 1, + }, + })) + }, util.Timeout, util.Interval).Should(gomega.Succeed()) + }) + + ginkgo.By("finishing the worker MPIJob, the manager's wl is marked as finished and the worker2 wl removed", func() { + finishJobReason := "MPIJob finished successfully" + gomega.Eventually(func(g gomega.Gomega) { + createdMPIJob := kfmpi.MPIJob{} + g.Expect(worker2TestCluster.client.Get(worker2TestCluster.ctx, client.ObjectKeyFromObject(mpijob), &createdMPIJob)).To(gomega.Succeed()) + createdMPIJob.Status.Conditions = append(createdMPIJob.Status.Conditions, kfmpi.JobCondition{ + Type: kfmpi.JobSucceeded, + Status: corev1.ConditionTrue, + Reason: "ByTest", + Message: finishJobReason, + }) + g.Expect(worker2TestCluster.client.Status().Update(worker2TestCluster.ctx, &createdMPIJob)).To(gomega.Succeed()) + }, util.Timeout, util.Interval).Should(gomega.Succeed()) + + waitForWorkloadToFinishAndRemoteWorkloadToBeDeleted(wlLookupKey, finishJobReason) + }) + }) + ginkgo.It("Should remove the worker's workload and job after reconnect when the managers job and workload are deleted", func() { job := testingjob.MakeJob("job", managerNs.Name). Queue(managerLq.Name). diff --git a/test/integration/multikueue/suite_test.go b/test/integration/multikueue/suite_test.go index 0d58df277b..121b452949 100644 --- a/test/integration/multikueue/suite_test.go +++ b/test/integration/multikueue/suite_test.go @@ -45,6 +45,7 @@ import ( workloadpytorchjob "sigs.k8s.io/kueue/pkg/controller/jobs/kubeflow/jobs/pytorchjob" workloadtfjob "sigs.k8s.io/kueue/pkg/controller/jobs/kubeflow/jobs/tfjob" workloadxgboostjob "sigs.k8s.io/kueue/pkg/controller/jobs/kubeflow/jobs/xgboostjob" + workloadmpijob "sigs.k8s.io/kueue/pkg/controller/jobs/mpijob" "sigs.k8s.io/kueue/pkg/queue" "sigs.k8s.io/kueue/pkg/util/kubeversion" utiltesting "sigs.k8s.io/kueue/pkg/util/testing" @@ -89,9 +90,12 @@ func TestMultiKueue(t *testing.T) { func createCluster(setupFnc framework.ManagerSetup, apiFeatureGates ...string) cluster { c := cluster{} c.fwk = &framework.Framework{ - CRDPath: filepath.Join("..", "..", "..", "config", "components", "crd", "bases"), - WebhookPath: filepath.Join("..", "..", "..", "config", "components", "webhook"), - DepCRDPaths: []string{filepath.Join("..", "..", "..", "dep-crds", "jobset-operator"), filepath.Join("..", "..", "..", "dep-crds", "training-operator")}, + CRDPath: filepath.Join("..", "..", "..", "config", "components", "crd", "bases"), + WebhookPath: filepath.Join("..", "..", "..", "config", "components", "webhook"), + DepCRDPaths: []string{filepath.Join("..", "..", "..", "dep-crds", "jobset-operator"), + filepath.Join("..", "..", "..", "dep-crds", "training-operator-crds"), + filepath.Join("..", "..", "..", "dep-crds", "mpi-operator"), + }, APIServerFeatureGates: apiFeatureGates, } c.cfg = c.fwk.Init() @@ -186,6 +190,18 @@ func managerSetup(ctx context.Context, mgr manager.Manager) { err = workloadxgboostjob.SetupXGBoostJobWebhook(mgr) gomega.Expect(err).NotTo(gomega.HaveOccurred()) + + err = workloadmpijob.SetupIndexes(ctx, mgr.GetFieldIndexer()) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + + mpiJobReconciler := workloadmpijob.NewReconciler( + mgr.GetClient(), + mgr.GetEventRecorderFor(constants.JobControllerName)) + err = mpiJobReconciler.SetupWithManager(mgr) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + + err = workloadmpijob.SetupMPIJobWebhook(mgr) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) } func managerAndMultiKueueSetup(ctx context.Context, mgr manager.Manager, gcInterval time.Duration) { diff --git a/test/util/e2e.go b/test/util/e2e.go index f4dc7a81dc..02dc9686df 100644 --- a/test/util/e2e.go +++ b/test/util/e2e.go @@ -6,6 +6,7 @@ import ( "os" "github.com/google/go-cmp/cmp/cmpopts" + kfmpi "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" kftraining "github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1" "github.com/onsi/gomega" appsv1 "k8s.io/api/apps/v1" @@ -47,6 +48,9 @@ func CreateClientUsingCluster(kContext string) (client.WithWatch, *rest.Config) err = kftraining.AddToScheme(scheme.Scheme) gomega.ExpectWithOffset(1, err).NotTo(gomega.HaveOccurred()) + err = kfmpi.AddToScheme(scheme.Scheme) + gomega.ExpectWithOffset(1, err).NotTo(gomega.HaveOccurred()) + client, err := client.NewWithWatch(cfg, client.Options{Scheme: scheme.Scheme}) gomega.ExpectWithOffset(1, err).NotTo(gomega.HaveOccurred()) return client, cfg @@ -108,7 +112,12 @@ func WaitForJobSetAvailability(ctx context.Context, k8sClient client.Client) { waitForOperatorAvailability(ctx, k8sClient, jcmKey) } -func WaitForKubeFlowAvailability(ctx context.Context, k8sClient client.Client) { +func WaitForKubeFlowTrainingOperatorAvailability(ctx context.Context, k8sClient client.Client) { kftoKey := types.NamespacedName{Namespace: "kubeflow", Name: "training-operator"} waitForOperatorAvailability(ctx, k8sClient, kftoKey) } + +func WaitForKubeFlowMPIOperatorAvailability(ctx context.Context, k8sClient client.Client) { + kftoKey := types.NamespacedName{Namespace: "mpi-operator", Name: "mpi-operator"} + waitForOperatorAvailability(ctx, k8sClient, kftoKey) +} From df36922109e5aacc3b72a2adcf867609dd9fb4a6 Mon Sep 17 00:00:00 2001 From: Mykhailo Bobrovskyi Date: Thu, 12 Sep 2024 06:41:12 +0300 Subject: [PATCH 025/155] Fix Warning: 'commonLabels' is deprecated. (#3027) * Fix Warning: 'commonLabels' is deprecated. * Add target for paths. --- .../multikueue/manager/kustomization.yaml | 9 +++++++-- .../multikueue/worker/kustomization.yaml | 20 ++++++++++++++----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/test/e2e/config/multikueue/manager/kustomization.yaml b/test/e2e/config/multikueue/manager/kustomization.yaml index bf62f9ec13..0e5b1219ee 100644 --- a/test/e2e/config/multikueue/manager/kustomization.yaml +++ b/test/e2e/config/multikueue/manager/kustomization.yaml @@ -8,5 +8,10 @@ secretGenerator: - name: training-operator-webhook-cert options: disableNameSuffixHash: true -patchesStrategicMerge: - - patch_crds.yaml +patches: + - path: patch_crds.yaml + target: + version: v1 + group: apiextensions.k8s.io + kind: CustomResourceDefinition + name: mpijobs.kubeflow.org diff --git a/test/e2e/config/multikueue/worker/kustomization.yaml b/test/e2e/config/multikueue/worker/kustomization.yaml index 3fb5f58fe6..5abe584aeb 100644 --- a/test/e2e/config/multikueue/worker/kustomization.yaml +++ b/test/e2e/config/multikueue/worker/kustomization.yaml @@ -1,8 +1,18 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization -namespace: kubeflow resources: -- ../../../../../dep-crds/training-operator/manifests/overlays/standalone -patchesStrategicMerge: -- patch_crds.yaml -- patch_deployment.yaml + - ../../../../../dep-crds/training-operator/manifests/overlays/standalone +patches: + - path: patch_crds.yaml + target: + version: v1 + group: apiextensions.k8s.io + kind: CustomResourceDefinition + name: mpijobs.kubeflow.org + - path: patch_deployment.yaml + target: + version: v1 + group: apps + kind: Deployment + name: training-operator + From e05902a8a1296ce8af25ed2330e087f0cb896e05 Mon Sep 17 00:00:00 2001 From: Mykhailo Bobrovskyi Date: Thu, 12 Sep 2024 10:05:12 +0300 Subject: [PATCH 026/155] Clean roles and secrets after e2e multikueue test. (#3030) --- test/e2e/multikueue/suite_test.go | 43 +++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/test/e2e/multikueue/suite_test.go b/test/e2e/multikueue/suite_test.go index e40ed7696e..a6a2d4ac9b 100644 --- a/test/e2e/multikueue/suite_test.go +++ b/test/e2e/multikueue/suite_test.go @@ -175,8 +175,29 @@ func kubeconfigForMultiKueueSA(ctx context.Context, c client.Client, restConfig return clientcmd.Write(cfg) } +func cleanKubeconfigForMultiKueueSA(ctx context.Context, c client.Client, ns string, prefix string) error { + roleName := prefix + "-role" + + err := c.Delete(ctx, &rbacv1.ClusterRole{ObjectMeta: metav1.ObjectMeta{Name: roleName}}) + if client.IgnoreNotFound(err) != nil { + return err + } + + err = c.Delete(ctx, &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Namespace: ns, Name: prefix + "-sa"}}) + if client.IgnoreNotFound(err) != nil { + return err + } + + err = c.Delete(ctx, &rbacv1.ClusterRoleBinding{ObjectMeta: metav1.ObjectMeta{Name: prefix + "-crb"}}) + if client.IgnoreNotFound(err) != nil { + return err + } + + return nil +} + func makeMultiKueueSecret(ctx context.Context, c client.Client, namespace string, name string, kubeconfig []byte) error { - w1Secret := &corev1.Secret{ + secret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Namespace: namespace, Name: name, @@ -185,7 +206,17 @@ func makeMultiKueueSecret(ctx context.Context, c client.Client, namespace string "kubeconfig": kubeconfig, }, } - return c.Create(ctx, w1Secret) + return c.Create(ctx, secret) +} + +func cleanMultiKueueSecret(ctx context.Context, c client.Client, namespace string, name string) error { + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + Name: name, + }, + } + return client.IgnoreNotFound(c.Delete(ctx, secret)) } func TestAPIs(t *testing.T) { @@ -249,3 +280,11 @@ var _ = ginkgo.BeforeSuite(func() { managerK8SVersion, err = kubeversion.FetchServerVersion(discoveryClient) gomega.Expect(err).NotTo(gomega.HaveOccurred()) }) + +var _ = ginkgo.AfterSuite(func() { + gomega.Expect(cleanKubeconfigForMultiKueueSA(ctx, k8sWorker1Client, "kueue-system", "mksa")).To(gomega.Succeed()) + gomega.Expect(cleanKubeconfigForMultiKueueSA(ctx, k8sWorker2Client, "kueue-system", "mksa")).To(gomega.Succeed()) + + gomega.Expect(cleanMultiKueueSecret(ctx, k8sManagerClient, "kueue-system", "multikueue1")).To(gomega.Succeed()) + gomega.Expect(cleanMultiKueueSecret(ctx, k8sManagerClient, "kueue-system", "multikueue2")).To(gomega.Succeed()) +}) From b9e173091c53456ae6858d9a10de81e6ba07ec62 Mon Sep 17 00:00:00 2001 From: Mykhailo Bobrovskyi Date: Thu, 12 Sep 2024 10:31:12 +0300 Subject: [PATCH 027/155] [kjobctl] Fix installation guide. (#3031) --- Makefile | 2 +- cmd/experimental/kjobctl/docs/installation.md | 38 ------------------- 2 files changed, 1 insertion(+), 39 deletions(-) diff --git a/Makefile b/Makefile index 2e67d96e37..534e6584f0 100644 --- a/Makefile +++ b/Makefile @@ -278,7 +278,7 @@ 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 -i cmd/experimental/kjobctl/docs/installation.md + $(SED) -r 's/v[0-9]+\.[0-9]+\.[0-9]+/$(RELEASE_VERSION)/g' -i README.md -i site/hugo.toml $(YQ) e '.appVersion = "$(RELEASE_VERSION)"' -i charts/kueue/Chart.yaml @$(call clean-manifests) diff --git a/cmd/experimental/kjobctl/docs/installation.md b/cmd/experimental/kjobctl/docs/installation.md index 5c9d87f38d..9c8d90d039 100644 --- a/cmd/experimental/kjobctl/docs/installation.md +++ b/cmd/experimental/kjobctl/docs/installation.md @@ -2,44 +2,6 @@ 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.1/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 From 5ffe0e346bffc59e4de5169be9d01508343c00a1 Mon Sep 17 00:00:00 2001 From: Mykhailo Bobrovskyi Date: Thu, 12 Sep 2024 11:21:13 +0300 Subject: [PATCH 028/155] Fix Should run a MPIJob on worker if admitted flaky test. (#3029) --- test/e2e/multikueue/e2e_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/multikueue/e2e_test.go b/test/e2e/multikueue/e2e_test.go index bf1ccf3f59..0146971efa 100644 --- a/test/e2e/multikueue/e2e_test.go +++ b/test/e2e/multikueue/e2e_test.go @@ -481,7 +481,7 @@ var _ = ginkgo.Describe("MultiKueue", func() { finishReasonMessage := fmt.Sprintf("MPIJob %s successfully completed.", client.ObjectKeyFromObject(mpijob).String()) checkFinishStatusCondition(g, wlLookupKey, finishReasonMessage) - }, util.Timeout, util.Interval).Should(gomega.Succeed()) + }, util.LongTimeout, util.Interval).Should(gomega.Succeed()) }) ginkgo.By("Checking no objects are left in the worker clusters and the MPIJob is completed", func() { From 1aa52db8eb60477558e502d835d0ad8ebb612649 Mon Sep 17 00:00:00 2001 From: Mykhailo Bobrovskyi Date: Thu, 12 Sep 2024 11:49:12 +0300 Subject: [PATCH 029/155] Remove unnecessary IgnoreConditionTimestampsAndObservedGeneration for ReplicaStatus object. (#3033) --- test/e2e/multikueue/e2e_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e2e/multikueue/e2e_test.go b/test/e2e/multikueue/e2e_test.go index 0146971efa..46b6a949b3 100644 --- a/test/e2e/multikueue/e2e_test.go +++ b/test/e2e/multikueue/e2e_test.go @@ -416,7 +416,7 @@ var _ = ginkgo.Describe("MultiKueue", func() { Succeeded: 1, Selector: fmt.Sprintf("training.kubeflow.org/job-name=%s,training.kubeflow.org/operator-name=pytorchjob-controller,training.kubeflow.org/replica-type=master", createdPyTorchJob.Name), }, - util.IgnoreConditionTimestampsAndObservedGeneration)) + )) finishReasonMessage := fmt.Sprintf("PyTorchJob %s is successfully completed.", pyTorchJob.Name) checkFinishStatusCondition(g, wlLookupKey, finishReasonMessage) @@ -477,7 +477,7 @@ var _ = ginkgo.Describe("MultiKueue", func() { Active: 0, Succeeded: 1, }, - util.IgnoreConditionTimestampsAndObservedGeneration)) + )) finishReasonMessage := fmt.Sprintf("MPIJob %s successfully completed.", client.ObjectKeyFromObject(mpijob).String()) checkFinishStatusCondition(g, wlLookupKey, finishReasonMessage) From e27bd2d66d244193b71b9ce8e1ac02a6b4fee447 Mon Sep 17 00:00:00 2001 From: Mykhailo Bobrovskyi Date: Thu, 12 Sep 2024 14:13:12 +0300 Subject: [PATCH 030/155] [kjobctl] Add delete slurm command. (#2863) * [kjobctl] Added delete slurm command. * Fix created in different mode error. --- .../docs/commands/kjobctl_delete/_index.md | 1 + .../kjobctl_delete/kjobctl_delete_slurm.md | 281 ++++++++++++++++++ .../kjobctl/pkg/cmd/delete/delete.go | 1 + .../kjobctl/pkg/cmd/delete/delete_job.go | 5 + .../kjobctl/pkg/cmd/delete/delete_job_test.go | 55 ++-- .../kjobctl/pkg/cmd/delete/delete_slurm.go | 220 ++++++++++++++ .../pkg/cmd/delete/delete_slurm_test.go | 267 +++++++++++++++++ 7 files changed, 810 insertions(+), 20 deletions(-) create mode 100644 cmd/experimental/kjobctl/docs/commands/kjobctl_delete/kjobctl_delete_slurm.md create mode 100644 cmd/experimental/kjobctl/pkg/cmd/delete/delete_slurm.go create mode 100644 cmd/experimental/kjobctl/pkg/cmd/delete/delete_slurm_test.go diff --git a/cmd/experimental/kjobctl/docs/commands/kjobctl_delete/_index.md b/cmd/experimental/kjobctl/docs/commands/kjobctl_delete/_index.md index e6ac776bcd..627d81abcf 100644 --- a/cmd/experimental/kjobctl/docs/commands/kjobctl_delete/_index.md +++ b/cmd/experimental/kjobctl/docs/commands/kjobctl_delete/_index.md @@ -233,4 +233,5 @@ Delete resources * [kjobctl delete job](kjobctl_delete_job.md) - Delete Job * [kjobctl delete raycluster](kjobctl_delete_raycluster.md) - Delete RayCluster * [kjobctl delete rayjob](kjobctl_delete_rayjob.md) - Delete RayJob +* [kjobctl delete slurm](kjobctl_delete_slurm.md) - Delete Slurm diff --git a/cmd/experimental/kjobctl/docs/commands/kjobctl_delete/kjobctl_delete_slurm.md b/cmd/experimental/kjobctl/docs/commands/kjobctl_delete/kjobctl_delete_slurm.md new file mode 100644 index 0000000000..3c18e64ac5 --- /dev/null +++ b/cmd/experimental/kjobctl/docs/commands/kjobctl_delete/kjobctl_delete_slurm.md @@ -0,0 +1,281 @@ + + +# kjobctl delete slurm + + +## Synopsis + + +Delete Slurm + +``` +kjobctl delete slurm NAME [--cascade STRATEGY] [--dry-run STRATEGY] +``` + + +## Examples + +``` + # Delete Slurm + kjobctl delete slurm my-application-profile-slurm-k2wzd +``` + + +## Options + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
--allow-missing-template-keys     Default: true
+

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.

+
--cascade string     Default: "background"
+

Must be "background", "orphan", or "foreground". Defaults to background.

+
--dry-run string     Default: "none"
+

Must be "none", "server", or "client". 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.

+
-h, --help
+

help for slurm

+
-o, --output string
+

Output format. One of: (json, yaml, name, go-template, go-template-file, template, templatefile, jsonpath, jsonpath-as-json, jsonpath-file).

+
--show-managed-fields
+

If true, keep the managedFields when printing objects in JSON or YAML format.

+
--template string
+

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].

+
+ + + +## Options inherited from parent commands + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
--as string
+

Username to impersonate for the operation. User could be a regular user or a service account in a namespace.

+
--as-group strings
+

Group to impersonate for the operation, this flag can be repeated to specify multiple groups.

+
--as-uid string
+

UID to impersonate for the operation.

+
--cache-dir string     Default: "$HOME/.kube/cache"
+

Default cache directory

+
--certificate-authority string
+

Path to a cert file for the certificate authority

+
--client-certificate string
+

Path to a client certificate file for TLS

+
--client-key string
+

Path to a client key file for TLS

+
--cluster string
+

The name of the kubeconfig cluster to use

+
--context string
+

The name of the kubeconfig context to use

+
--disable-compression
+

If true, opt-out of response compression for all requests to the server

+
--insecure-skip-tls-verify
+

If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure

+
--kubeconfig string
+

Path to the kubeconfig file to use for CLI requests.

+
-n, --namespace string
+

If present, the namespace scope for this CLI request

+
--request-timeout string     Default: "0"
+

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't timeout requests.

+
-s, --server string
+

The address and port of the Kubernetes API server

+
--tls-server-name string
+

Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used

+
--token string
+

Bearer token for authentication to the API server

+
--user string
+

The name of the kubeconfig user to use

+
+ + + +## See Also + +* [kjobctl_delete](_index.md) - Delete resources + diff --git a/cmd/experimental/kjobctl/pkg/cmd/delete/delete.go b/cmd/experimental/kjobctl/pkg/cmd/delete/delete.go index 3dd4b36b8e..724cf08f05 100644 --- a/cmd/experimental/kjobctl/pkg/cmd/delete/delete.go +++ b/cmd/experimental/kjobctl/pkg/cmd/delete/delete.go @@ -37,6 +37,7 @@ func NewDeleteCmd(clientGetter util.ClientGetter, streams genericiooptions.IOStr cmd.AddCommand(NewJobCmd(clientGetter, streams)) cmd.AddCommand(NewRayJobCmd(clientGetter, streams)) cmd.AddCommand(NewRayClusterCmd(clientGetter, streams)) + cmd.AddCommand(NewSlurmCmd(clientGetter, streams)) return cmd } diff --git a/cmd/experimental/kjobctl/pkg/cmd/delete/delete_job.go b/cmd/experimental/kjobctl/pkg/cmd/delete/delete_job.go index 9bed6b2ea4..004199d440 100644 --- a/cmd/experimental/kjobctl/pkg/cmd/delete/delete_job.go +++ b/cmd/experimental/kjobctl/pkg/cmd/delete/delete_job.go @@ -150,6 +150,11 @@ func (o *JobOptions) Run(ctx context.Context) error { fmt.Fprintf(o.ErrOut, "jobs.batch \"%s\" not created via kjob\n", job.Name) continue } + if job.Labels[constants.ModeLabel] != string(v1alpha1.JobMode) { + fmt.Fprintf(o.ErrOut, "jobs.batch \"%s\" created in \"%s\" mode. Switch to the correct mode to delete it\n", + job.Name, job.Labels[constants.ModeLabel]) + continue + } if o.DryRunStrategy != util.DryRunClient { deleteOptions := metav1.DeleteOptions{ diff --git a/cmd/experimental/kjobctl/pkg/cmd/delete/delete_job_test.go b/cmd/experimental/kjobctl/pkg/cmd/delete/delete_job_test.go index cc65ab5dc0..531dabb0f2 100644 --- a/cmd/experimental/kjobctl/pkg/cmd/delete/delete_job_test.go +++ b/cmd/experimental/kjobctl/pkg/cmd/delete/delete_job_test.go @@ -29,6 +29,7 @@ import ( k8sfake "k8s.io/client-go/kubernetes/fake" kubetesting "k8s.io/client-go/testing" + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1" cmdtesting "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/cmd/testing" "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/testing/wrappers" ) @@ -46,12 +47,12 @@ func TestJobCmd(t *testing.T) { "shouldn't delete job because it is not found": { args: []string{"j"}, objs: []runtime.Object{ - wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Obj(), - wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Obj(), + wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.JobMode).Obj(), + wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.JobMode).Obj(), }, wantJobs: []batchv1.Job{ - *wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Obj(), - *wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Obj(), + *wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.JobMode).Obj(), + *wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.JobMode).Obj(), }, wantOutErr: "jobs.batch \"j\" not found\n", }, @@ -65,33 +66,47 @@ func TestJobCmd(t *testing.T) { }, wantOutErr: "jobs.batch \"j1\" not created via kjob\n", }, + "shouldn't delete job because it is not used for Job mode": { + args: []string{"j1", "j2"}, + objs: []runtime.Object{ + wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Obj(), + wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.SlurmMode).Obj(), + }, + wantJobs: []batchv1.Job{ + *wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Obj(), + *wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.SlurmMode).Obj(), + }, + wantOutErr: `jobs.batch "j1" created in "" mode. Switch to the correct mode to delete it +jobs.batch "j2" created in "Slurm" mode. Switch to the correct mode to delete it +`, + }, "should delete job": { args: []string{"j1"}, objs: []runtime.Object{ - wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Obj(), - wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Obj(), + wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.JobMode).Obj(), + wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.JobMode).Obj(), }, wantJobs: []batchv1.Job{ - *wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Obj(), + *wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.JobMode).Obj(), }, wantOut: "job.batch/j1 deleted\n", }, "should delete jobs": { args: []string{"j1", "j2"}, objs: []runtime.Object{ - wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Obj(), - wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Obj(), + wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.JobMode).Obj(), + wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.JobMode).Obj(), }, wantOut: "job.batch/j1 deleted\njob.batch/j2 deleted\n", }, "should delete only one job": { args: []string{"j1", "j"}, objs: []runtime.Object{ - wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Obj(), - wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Obj(), + wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.JobMode).Obj(), + wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.JobMode).Obj(), }, wantJobs: []batchv1.Job{ - *wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Obj(), + *wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.JobMode).Obj(), }, wantOut: "job.batch/j1 deleted\n", wantOutErr: "jobs.batch \"j\" not found\n", @@ -99,24 +114,24 @@ func TestJobCmd(t *testing.T) { "shouldn't delete job with client dry run": { args: []string{"j1", "--dry-run", "client"}, objs: []runtime.Object{ - wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Obj(), - wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Obj(), + wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.JobMode).Obj(), + wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.JobMode).Obj(), }, wantJobs: []batchv1.Job{ - *wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Obj(), - *wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Obj(), + *wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.JobMode).Obj(), + *wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.JobMode).Obj(), }, wantOut: "job.batch/j1 deleted (client dry run)\n", }, "shouldn't delete job with server dry run": { args: []string{"j1", "--dry-run", "server"}, objs: []runtime.Object{ - wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Obj(), - wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Obj(), + wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.JobMode).Obj(), + wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.JobMode).Obj(), }, wantJobs: []batchv1.Job{ - *wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Obj(), - *wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Obj(), + *wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.JobMode).Obj(), + *wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.JobMode).Obj(), }, wantOut: "job.batch/j1 deleted (server dry run)\n", }, diff --git a/cmd/experimental/kjobctl/pkg/cmd/delete/delete_slurm.go b/cmd/experimental/kjobctl/pkg/cmd/delete/delete_slurm.go new file mode 100644 index 0000000000..ae9d914e1e --- /dev/null +++ b/cmd/experimental/kjobctl/pkg/cmd/delete/delete_slurm.go @@ -0,0 +1,220 @@ +/* +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 delete + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/genericiooptions" + "k8s.io/cli-runtime/pkg/printers" + k8s "k8s.io/client-go/kubernetes" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1" + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/cmd/completion" + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/cmd/util" + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/constants" +) + +const ( + slurmExample = ` # Delete Slurm + kjobctl delete slurm my-application-profile-slurm-k2wzd` +) + +type SlurmOptions struct { + PrintFlags *genericclioptions.PrintFlags + + JobNames []string + Namespace string + + CascadeStrategy metav1.DeletionPropagation + DryRunStrategy util.DryRunStrategy + + Clientset k8s.Interface + + PrintObj printers.ResourcePrinterFunc + + genericiooptions.IOStreams +} + +func NewSlurmOptions(streams genericiooptions.IOStreams) *SlurmOptions { + return &SlurmOptions{ + PrintFlags: genericclioptions.NewPrintFlags("deleted").WithTypeSetter(scheme.Scheme), + IOStreams: streams, + } +} + +func NewSlurmCmd(clientGetter util.ClientGetter, streams genericiooptions.IOStreams) *cobra.Command { + o := NewSlurmOptions(streams) + + cmd := &cobra.Command{ + Use: "slurm NAME [--cascade STRATEGY] [--dry-run STRATEGY]", + DisableFlagsInUseLine: true, + Short: "Delete Slurm", + Example: slurmExample, + Args: cobra.MinimumNArgs(1), + ValidArgsFunction: completion.JobNameFunc(clientGetter, v1alpha1.SlurmMode), + RunE: func(cmd *cobra.Command, args []string) error { + cmd.SilenceUsage = true + + err := o.Complete(clientGetter, cmd, args) + if err != nil { + return err + } + + return o.Run(cmd.Context()) + }, + } + + addCascadingFlag(cmd) + util.AddDryRunFlag(cmd) + + o.PrintFlags.AddFlags(cmd) + + return cmd +} + +func (o *SlurmOptions) Complete(clientGetter util.ClientGetter, cmd *cobra.Command, args []string) error { + o.JobNames = args + + var err error + + o.Namespace, _, err = clientGetter.ToRawKubeConfigLoader().Namespace() + if err != nil { + return err + } + + o.DryRunStrategy, err = util.GetDryRunStrategy(cmd) + if err != nil { + return err + } + + err = util.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) + if err != nil { + return err + } + + o.CascadeStrategy, err = getCascadingStrategy(cmd) + if err != nil { + return err + } + + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return err + } + + o.PrintObj = printer.PrintObj + + o.Clientset, err = clientGetter.K8sClientset() + if err != nil { + return err + } + + return nil +} + +func (o *SlurmOptions) Run(ctx context.Context) error { + for _, jobName := range o.JobNames { + if err := o.deleteJob(ctx, jobName); err != nil { + return err + } + if err := o.deleteConfigMap(ctx, jobName); err != nil { + return err + } + } + + return nil +} + +func (o *SlurmOptions) deleteJob(ctx context.Context, jobName string) error { + job, err := o.Clientset.BatchV1().Jobs(o.Namespace).Get(ctx, jobName, metav1.GetOptions{}) + if client.IgnoreNotFound(err) != nil { + return err + } + if err != nil { + fmt.Fprintln(o.ErrOut, err) + return nil + } + if _, ok := job.Labels[constants.ProfileLabel]; !ok { + fmt.Fprintf(o.ErrOut, "jobs.batch \"%s\" not created via kjob\n", job.Name) + return nil + } + if job.Labels[constants.ModeLabel] != string(v1alpha1.SlurmMode) { + fmt.Fprintf(o.ErrOut, "jobs.batch \"%s\" created in \"%s\" mode. Switch to the correct mode to delete it\n", + job.Name, job.Labels[constants.ModeLabel]) + return nil + } + + if o.DryRunStrategy != util.DryRunClient { + deleteOptions := metav1.DeleteOptions{ + PropagationPolicy: ptr.To(o.CascadeStrategy), + } + + if o.DryRunStrategy == util.DryRunServer { + deleteOptions.DryRun = []string{metav1.DryRunAll} + } + + if err := o.Clientset.BatchV1().Jobs(o.Namespace).Delete(ctx, jobName, deleteOptions); err != nil { + return err + } + } + + return o.PrintObj(job, o.Out) +} + +func (o *SlurmOptions) deleteConfigMap(ctx context.Context, configMapName string) error { + configMap, err := o.Clientset.CoreV1().ConfigMaps(o.Namespace).Get(ctx, configMapName, metav1.GetOptions{}) + if client.IgnoreNotFound(err) != nil { + return err + } + if err != nil { + fmt.Fprintln(o.ErrOut, err) + return nil + } + if _, ok := configMap.Labels[constants.ProfileLabel]; !ok { + fmt.Fprintf(o.ErrOut, "configmaps \"%s\" not created via kjob\n", configMap.Name) + return nil + } + if configMap.Labels[constants.ModeLabel] != string(v1alpha1.SlurmMode) { + fmt.Fprintf(o.ErrOut, "configmaps \"%s\" created in \"%s\" mode. Switch to the correct mode to delete it\n", + configMap.Name, configMap.Labels[constants.ModeLabel]) + return nil + } + + if o.DryRunStrategy != util.DryRunClient { + deleteOptions := metav1.DeleteOptions{ + PropagationPolicy: ptr.To(o.CascadeStrategy), + } + + if o.DryRunStrategy == util.DryRunServer { + deleteOptions.DryRun = []string{metav1.DryRunAll} + } + + if err := o.Clientset.CoreV1().ConfigMaps(o.Namespace).Delete(ctx, configMapName, deleteOptions); err != nil { + return err + } + } + + return o.PrintObj(configMap, o.Out) +} diff --git a/cmd/experimental/kjobctl/pkg/cmd/delete/delete_slurm_test.go b/cmd/experimental/kjobctl/pkg/cmd/delete/delete_slurm_test.go new file mode 100644 index 0000000000..058a42a8a3 --- /dev/null +++ b/cmd/experimental/kjobctl/pkg/cmd/delete/delete_slurm_test.go @@ -0,0 +1,267 @@ +/* +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 delete + +import ( + "context" + "slices" + "testing" + + "github.com/google/go-cmp/cmp" + batchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/cli-runtime/pkg/genericiooptions" + k8sfake "k8s.io/client-go/kubernetes/fake" + kubetesting "k8s.io/client-go/testing" + + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1" + cmdtesting "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/cmd/testing" + "sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/testing/wrappers" +) + +func TestSlurmCmd(t *testing.T) { + testCases := map[string]struct { + ns string + args []string + objs []runtime.Object + wantJobs []batchv1.Job + wantConfigMaps []corev1.ConfigMap + wantOut string + wantOutErr string + wantErr string + }{ + "shouldn't delete slurm job because it is not found": { + args: []string{"j"}, + objs: []runtime.Object{ + wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.SlurmMode).Obj(), + wrappers.MakeConfigMap("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.SlurmMode).Obj(), + wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.SlurmMode).Obj(), + wrappers.MakeConfigMap("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.SlurmMode).Obj(), + }, + wantJobs: []batchv1.Job{ + *wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.SlurmMode).Obj(), + *wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.SlurmMode).Obj(), + }, + wantConfigMaps: []corev1.ConfigMap{ + *wrappers.MakeConfigMap("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.SlurmMode).Obj(), + *wrappers.MakeConfigMap("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.SlurmMode).Obj(), + }, + wantOutErr: "jobs.batch \"j\" not found\nconfigmaps \"j\" not found\n", + }, + "shouldn't delete job because it is not created via kjob": { + args: []string{"j1"}, + objs: []runtime.Object{ + wrappers.MakeJob("j1", metav1.NamespaceDefault).Obj(), + wrappers.MakeConfigMap("j1", metav1.NamespaceDefault).Obj(), + }, + wantJobs: []batchv1.Job{ + *wrappers.MakeJob("j1", metav1.NamespaceDefault).Obj(), + }, + wantConfigMaps: []corev1.ConfigMap{ + *wrappers.MakeConfigMap("j1", metav1.NamespaceDefault).Obj(), + }, + wantOutErr: "jobs.batch \"j1\" not created via kjob\nconfigmaps \"j1\" not created via kjob\n", + }, + "shouldn't delete slurm job because it is not used for Job mode": { + args: []string{"j1", "j2"}, + objs: []runtime.Object{ + wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Obj(), + wrappers.MakeConfigMap("j1", metav1.NamespaceDefault).Profile("p1").Obj(), + wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.JobMode).Obj(), + wrappers.MakeConfigMap("j2", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.JobMode).Obj(), + }, + wantJobs: []batchv1.Job{ + *wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Obj(), + *wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.JobMode).Obj(), + }, + wantConfigMaps: []corev1.ConfigMap{ + *wrappers.MakeConfigMap("j1", metav1.NamespaceDefault).Profile("p1").Obj(), + *wrappers.MakeConfigMap("j2", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.JobMode).Obj(), + }, + wantOutErr: `jobs.batch "j1" created in "" mode. Switch to the correct mode to delete it +configmaps "j1" created in "" mode. Switch to the correct mode to delete it +jobs.batch "j2" created in "Job" mode. Switch to the correct mode to delete it +configmaps "j2" created in "Job" mode. Switch to the correct mode to delete it +`, + }, + "should delete slurm job": { + args: []string{"j1"}, + objs: []runtime.Object{ + wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.SlurmMode).Obj(), + wrappers.MakeConfigMap("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.SlurmMode).Obj(), + wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.SlurmMode).Obj(), + wrappers.MakeConfigMap("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.SlurmMode).Obj(), + }, + wantJobs: []batchv1.Job{ + *wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.SlurmMode).Obj(), + }, + wantConfigMaps: []corev1.ConfigMap{ + *wrappers.MakeConfigMap("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.SlurmMode).Obj(), + }, + wantOut: "job.batch/j1 deleted\nconfigmap/j1 deleted\n", + }, + "should delete slurm jobs": { + args: []string{"j1", "j2"}, + objs: []runtime.Object{ + wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.SlurmMode).Obj(), + wrappers.MakeConfigMap("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.SlurmMode).Obj(), + wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.SlurmMode).Obj(), + wrappers.MakeConfigMap("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.SlurmMode).Obj(), + }, + wantOut: "job.batch/j1 deleted\nconfigmap/j1 deleted\njob.batch/j2 deleted\nconfigmap/j2 deleted\n", + }, + "should delete only one slurm job": { + args: []string{"j1", "j"}, + objs: []runtime.Object{ + wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.SlurmMode).Obj(), + wrappers.MakeConfigMap("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.SlurmMode).Obj(), + wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.SlurmMode).Obj(), + wrappers.MakeConfigMap("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.SlurmMode).Obj(), + }, + wantJobs: []batchv1.Job{ + *wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.SlurmMode).Obj(), + }, + wantConfigMaps: []corev1.ConfigMap{ + *wrappers.MakeConfigMap("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.SlurmMode).Obj(), + }, + wantOut: "job.batch/j1 deleted\nconfigmap/j1 deleted\n", + wantOutErr: "jobs.batch \"j\" not found\nconfigmaps \"j\" not found\n", + }, + "shouldn't delete slurm job with client dry run": { + args: []string{"j1", "--dry-run", "client"}, + objs: []runtime.Object{ + wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.SlurmMode).Obj(), + wrappers.MakeConfigMap("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.SlurmMode).Obj(), + wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.SlurmMode).Obj(), + wrappers.MakeConfigMap("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.SlurmMode).Obj(), + }, + wantJobs: []batchv1.Job{ + *wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.SlurmMode).Obj(), + *wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.SlurmMode).Obj(), + }, + wantConfigMaps: []corev1.ConfigMap{ + *wrappers.MakeConfigMap("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.SlurmMode).Obj(), + *wrappers.MakeConfigMap("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.SlurmMode).Obj(), + }, + wantOut: "job.batch/j1 deleted (client dry run)\nconfigmap/j1 deleted (client dry run)\n", + }, + "shouldn't delete slurm job with server dry run": { + args: []string{"j1", "--dry-run", "server"}, + objs: []runtime.Object{ + wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.SlurmMode).Obj(), + wrappers.MakeConfigMap("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.SlurmMode).Obj(), + wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.SlurmMode).Obj(), + wrappers.MakeConfigMap("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.SlurmMode).Obj(), + }, + wantJobs: []batchv1.Job{ + *wrappers.MakeJob("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.SlurmMode).Obj(), + *wrappers.MakeJob("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.SlurmMode).Obj(), + }, + wantConfigMaps: []corev1.ConfigMap{ + *wrappers.MakeConfigMap("j1", metav1.NamespaceDefault).Profile("p1").Mode(v1alpha1.SlurmMode).Obj(), + *wrappers.MakeConfigMap("j2", metav1.NamespaceDefault).Profile("p2").Mode(v1alpha1.SlurmMode).Obj(), + }, + wantOut: "job.batch/j1 deleted (server dry run)\nconfigmap/j1 deleted (server dry run)\n", + }, + "no args": { + args: []string{}, + wantErr: "requires at least 1 arg(s), only received 0", + }, + } + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + ns := metav1.NamespaceDefault + if tc.ns != "" { + ns = tc.ns + } + + streams, _, out, outErr := genericiooptions.NewTestIOStreams() + + clientset := k8sfake.NewSimpleClientset(tc.objs...) + clientset.PrependReactor("delete", "jobs", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { + if slices.Contains(action.(kubetesting.DeleteAction).GetDeleteOptions().DryRun, metav1.DryRunAll) { + handled = true + } + return handled, ret, err + }) + clientset.PrependReactor("delete", "configmaps", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { + if slices.Contains(action.(kubetesting.DeleteAction).GetDeleteOptions().DryRun, metav1.DryRunAll) { + handled = true + } + return handled, ret, err + }) + + tcg := cmdtesting.NewTestClientGetter(). + WithK8sClientset(clientset). + WithNamespace(ns) + + cmd := NewSlurmCmd(tcg, streams) + cmd.SetOut(out) + cmd.SetErr(outErr) + cmd.SetArgs(tc.args) + + gotErr := cmd.Execute() + + 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) + } + + if gotErr != nil { + return + } + + gotOut := out.String() + if diff := cmp.Diff(tc.wantOut, gotOut); diff != "" { + t.Errorf("Unexpected output (-want/+got)\n%s", diff) + } + + gotOutErr := outErr.String() + if diff := cmp.Diff(tc.wantOutErr, gotOutErr); diff != "" { + t.Errorf("Unexpected error output (-want/+got)\n%s", diff) + } + + ctx := context.Background() + + gotJobList, err := clientset.BatchV1().Jobs(tc.ns).List(ctx, metav1.ListOptions{}) + if err != nil { + t.Error(err) + return + } + + if diff := cmp.Diff(tc.wantJobs, gotJobList.Items); diff != "" { + t.Errorf("Unexpected jobs (-want/+got)\n%s", diff) + } + + gotConfigMapList, err := clientset.CoreV1().ConfigMaps(tc.ns).List(ctx, metav1.ListOptions{}) + if err != nil { + t.Error(err) + return + } + + if diff := cmp.Diff(tc.wantConfigMaps, gotConfigMapList.Items); diff != "" { + t.Errorf("Unexpected jobs (-want/+got)\n%s", diff) + } + }) + } +} From c03277c969f4682cdaf119a2133664d9e76b95db Mon Sep 17 00:00:00 2001 From: Mykhailo Bobrovskyi Date: Thu, 12 Sep 2024 17:25:20 +0300 Subject: [PATCH 031/155] Bump Kubernetes dependencies to v0.31.x (#2402) * Bump kubernetes dependencies to v0.31.x. * Use Kubernetes v1.31.0 on tests. * Bump kubernetes dependencies to v0.31.1. --- Makefile | 2 +- Makefile-test.mk | 6 +- .../v1alpha1/openapi/zz_generated.openapi.go | 53 +- .../crd/kueue.x-k8s.io_admissionchecks.yaml | 21 +- .../crd/kueue.x-k8s.io_clusterqueues.yaml | 35 +- .../templates/crd/kueue.x-k8s.io_cohorts.yaml | 26 +- .../crd/kueue.x-k8s.io_localqueues.yaml | 23 +- .../kueue.x-k8s.io_multikueueclusters.yaml | 22 +- .../crd/kueue.x-k8s.io_multikueueconfigs.yaml | 2 +- ...e.x-k8s.io_provisioningrequestconfigs.yaml | 5 +- .../crd/kueue.x-k8s.io_resourceflavors.yaml | 7 +- ...ueue.x-k8s.io_workloadpriorityclasses.yaml | 2 +- .../crd/kueue.x-k8s.io_workloads.yaml | 327 +- charts/kueue/templates/rbac/role.yaml | 308 +- .../kueue/v1alpha1/kubeconfig.go | 4 +- .../kueue/v1alpha1/multikueuecluster.go | 10 +- .../kueue/v1alpha1/multikueueclusterspec.go | 4 +- .../kueue/v1alpha1/multikueueclusterstatus.go | 15 +- .../kueue/v1alpha1/multikueueconfig.go | 10 +- .../kueue/v1alpha1/multikueueconfigspec.go | 4 +- .../kueue/v1beta1/admission.go | 4 +- .../kueue/v1beta1/admissioncheck.go | 10 +- .../admissioncheckparametersreference.go | 4 +- .../kueue/v1beta1/admissioncheckspec.go | 4 +- .../kueue/v1beta1/admissionchecksstrategy.go | 4 +- .../kueue/v1beta1/admissioncheckstate.go | 4 +- .../kueue/v1beta1/admissioncheckstatus.go | 15 +- .../v1beta1/admissioncheckstrategyrule.go | 4 +- .../kueue/v1beta1/borrowwithincohort.go | 4 +- .../kueue/v1beta1/clusterqueue.go | 10 +- .../v1beta1/clusterqueuependingworkload.go | 4 +- .../clusterqueuependingworkloadsstatus.go | 4 +- .../kueue/v1beta1/clusterqueuepreemption.go | 4 +- .../kueue/v1beta1/clusterqueuespec.go | 12 +- .../kueue/v1beta1/clusterqueuestatus.go | 15 +- .../kueue/v1beta1/fairsharing.go | 4 +- .../kueue/v1beta1/fairsharingstatus.go | 4 +- .../kueue/v1beta1/flavorfungibility.go | 4 +- .../kueue/v1beta1/flavorquotas.go | 4 +- .../kueue/v1beta1/flavorusage.go | 4 +- .../kueue/v1beta1/localqueue.go | 10 +- .../kueue/v1beta1/localqueueflavorusage.go | 4 +- .../kueue/v1beta1/localqueueresourceusage.go | 4 +- .../kueue/v1beta1/localqueuespec.go | 4 +- .../kueue/v1beta1/localqueuestatus.go | 15 +- .../kueue/v1beta1/podset.go | 4 +- .../kueue/v1beta1/podsetassignment.go | 4 +- .../kueue/v1beta1/podsetupdate.go | 4 +- .../v1beta1/provisioningrequestconfig.go | 10 +- .../v1beta1/provisioningrequestconfigspec.go | 4 +- .../kueue/v1beta1/reclaimablepod.go | 4 +- .../kueue/v1beta1/requeuestate.go | 4 +- .../kueue/v1beta1/resourceflavor.go | 10 +- .../kueue/v1beta1/resourceflavorspec.go | 4 +- .../kueue/v1beta1/resourcegroup.go | 4 +- .../kueue/v1beta1/resourcequota.go | 4 +- .../kueue/v1beta1/resourceusage.go | 4 +- .../kueue/v1beta1/workload.go | 10 +- .../kueue/v1beta1/workloadpriorityclass.go | 10 +- .../kueue/v1beta1/workloadspec.go | 4 +- .../kueue/v1beta1/workloadstatus.go | 15 +- client-go/applyconfiguration/utils.go | 7 + .../visibility/v1alpha1/clusterqueue.go | 10 +- .../visibility/v1alpha1/localqueue.go | 10 +- .../visibility/v1alpha1/pendingworkload.go | 10 +- .../v1alpha1/pendingworkloadssummary.go | 10 +- .../versioned/fake/clientset_generated.go | 39 +- .../v1alpha1/fake/fake_multikueuecluster.go | 46 +- .../v1alpha1/fake/fake_multikueueconfig.go | 34 +- .../typed/kueue/v1alpha1/multikueuecluster.go | 192 +- .../typed/kueue/v1alpha1/multikueueconfig.go | 146 +- .../typed/kueue/v1beta1/admissioncheck.go | 192 +- .../typed/kueue/v1beta1/clusterqueue.go | 192 +- .../kueue/v1beta1/fake/fake_admissioncheck.go | 46 +- .../kueue/v1beta1/fake/fake_clusterqueue.go | 46 +- .../kueue/v1beta1/fake/fake_localqueue.go | 46 +- .../fake/fake_provisioningrequestconfig.go | 34 +- .../kueue/v1beta1/fake/fake_resourceflavor.go | 34 +- .../typed/kueue/v1beta1/fake/fake_workload.go | 46 +- .../fake/fake_workloadpriorityclass.go | 34 +- .../typed/kueue/v1beta1/localqueue.go | 205 +- .../v1beta1/provisioningrequestconfig.go | 146 +- .../typed/kueue/v1beta1/resourceflavor.go | 146 +- .../versioned/typed/kueue/v1beta1/workload.go | 205 +- .../kueue/v1beta1/workloadpriorityclass.go | 146 +- .../typed/visibility/v1alpha1/clusterqueue.go | 148 +- .../v1alpha1/fake/fake_clusterqueue.go | 39 +- .../v1alpha1/fake/fake_localqueue.go | 39 +- .../typed/visibility/v1alpha1/localqueue.go | 161 +- .../informers/externalversions/factory.go | 1 + .../kueue/v1alpha1/multikueuecluster.go | 26 +- .../kueue/v1alpha1/multikueueconfig.go | 26 +- .../listers/kueue/v1beta1/admissioncheck.go | 26 +- .../listers/kueue/v1beta1/clusterqueue.go | 26 +- client-go/listers/kueue/v1beta1/localqueue.go | 39 +- .../v1beta1/provisioningrequestconfig.go | 26 +- .../listers/kueue/v1beta1/resourceflavor.go | 26 +- client-go/listers/kueue/v1beta1/workload.go | 39 +- .../kueue/v1beta1/workloadpriorityclass.go | 26 +- .../visibility/v1alpha1/clusterqueue.go | 26 +- .../listers/visibility/v1alpha1/localqueue.go | 39 +- cmd/experimental/kjobctl/Makefile | 2 +- .../versioned/fake/clientset_generated.go | 6 +- .../typed/apis/v1alpha1/applicationprofile.go | 129 +- .../v1alpha1/fake/fake_applicationprofile.go | 29 +- .../apis/v1alpha1/fake/fake_jobtemplate.go | 29 +- .../v1alpha1/fake/fake_rayclustertemplate.go | 29 +- .../apis/v1alpha1/fake/fake_rayjobtemplate.go | 29 +- .../apis/v1alpha1/fake/fake_volumebundle.go | 29 +- .../typed/apis/v1alpha1/jobtemplate.go | 129 +- .../typed/apis/v1alpha1/rayclustertemplate.go | 129 +- .../typed/apis/v1alpha1/rayjobtemplate.go | 129 +- .../typed/apis/v1alpha1/volumebundle.go | 129 +- .../kjobctl.x-k8s.io_applicationprofiles.yaml | 3 +- .../bases/kjobctl.x-k8s.io_jobtemplates.yaml | 317 +- .../kjobctl.x-k8s.io_rayclustertemplates.yaml | 650 +- .../kjobctl.x-k8s.io_rayjobtemplates.yaml | 945 +- .../bases/kjobctl.x-k8s.io_volumebundles.yaml | 104 +- cmd/experimental/kjobctl/go.mod | 34 +- cmd/experimental/kjobctl/go.sum | 75 +- cmd/experimental/kjobctl/hack/tools/go.mod | 32 +- cmd/experimental/kjobctl/hack/tools/go.sum | 61 +- .../pkg/cmd/printcrds/embed/manifest.gz | Bin 428592 -> 432404 bytes .../app/create/create_resourceflavor_test.go | 1 + .../bases/kueue.x-k8s.io_admissionchecks.yaml | 21 +- .../bases/kueue.x-k8s.io_clusterqueues.yaml | 35 +- .../crd/bases/kueue.x-k8s.io_cohorts.yaml | 26 +- .../crd/bases/kueue.x-k8s.io_localqueues.yaml | 23 +- .../kueue.x-k8s.io_multikueueclusters.yaml | 22 +- .../kueue.x-k8s.io_multikueueconfigs.yaml | 2 +- ...e.x-k8s.io_provisioningrequestconfigs.yaml | 5 +- .../bases/kueue.x-k8s.io_resourceflavors.yaml | 7 +- ...ueue.x-k8s.io_workloadpriorityclasses.yaml | 2 +- .../crd/bases/kueue.x-k8s.io_workloads.yaml | 327 +- config/components/rbac/role.yaml | 308 +- go.mod | 84 +- go.sum | 210 +- hack/internal/tools/go.mod | 41 +- hack/internal/tools/go.sum | 83 +- hack/update-codegen.sh | 37 +- pkg/cache/cache_test.go | 2 +- pkg/cache/clusterqueue_test.go | 2 +- pkg/cache/snapshot_test.go | 2 +- pkg/config/config_test.go | 2 + .../multikueue/admissioncheck.go | 21 +- .../multikueue/multikueuecluster.go | 18 +- .../admissionchecks/multikueue/workload.go | 5 +- .../multikueue/workload_test.go | 2 +- .../provisioning/controller.go | 24 +- .../core/admissioncheck_controller.go | 10 +- .../core/clusterqueue_controller.go | 59 +- .../core/clusterqueue_controller_test.go | 3 +- pkg/controller/core/localqueue_controller.go | 20 +- .../core/resourceflavor_controller.go | 10 +- pkg/controller/core/workload_controller.go | 24 +- pkg/controller/jobframework/setup.go | 2 +- pkg/controller/jobs/job/job_controller.go | 10 +- .../jobs/job/job_multikueue_adapter_test.go | 2 +- pkg/controller/jobs/job/job_webhook_test.go | 4 +- .../jobs/jobset/jobset_webhook_test.go | 2 +- pkg/controller/jobs/pod/event_handlers.go | 20 +- pkg/controller/jobs/pod/pod_controller.go | 1 + pkg/features/kube_features.go | 4 +- pkg/features/kube_features_test.go | 2 +- .../flavorassigner/flavorassigner_test.go | 2 +- pkg/scheduler/preemption/preemption_test.go | 2 +- pkg/scheduler/scheduler_test.go | 10 +- pkg/visibility/server.go | 12 +- pkg/webhooks/clusterqueue_webhook_test.go | 2 +- test/integration/framework/framework.go | 5 + .../integration/multikueue/multikueue_test.go | 55 +- test/integration/multikueue/suite_test.go | 3 - .../scheduler/minimalkueue/main.go | 2 + .../scheduler/runner/controller/controller.go | 4 +- test/performance/scheduler/runner/main.go | 1 + .../antlr/antlr4/runtime/Go/antlr/v4/LICENSE | 26 - .../antlr4/runtime/Go/antlr/v4/antlrdoc.go | 68 - .../antlr4/runtime/Go/antlr/v4/atn_config.go | 303 - .../runtime/Go/antlr/v4/atn_config_set.go | 441 - .../runtime/Go/antlr/v4/input_stream.go | 113 - .../antlr4/runtime/Go/antlr/v4/jcollect.go | 198 - .../runtime/Go/antlr/v4/prediction_context.go | 806 -- .../runtime/Go/antlr/v4/prediction_mode.go | 529 - .../runtime/Go/antlr/v4/rule_context.go | 114 - .../antlr4/runtime/Go/antlr/v4/utils_set.go | 235 - .../github.com/antlr4-go/antlr/v4/.gitignore | 18 + vendor/github.com/antlr4-go/antlr/v4/LICENSE | 28 + .../github.com/antlr4-go/antlr/v4/README.md | 54 + .../github.com/antlr4-go/antlr/v4/antlrdoc.go | 102 + .../runtime/Go => antlr4-go}/antlr/v4/atn.go | 9 +- .../antlr4-go/antlr/v4/atn_config.go | 335 + .../antlr4-go/antlr/v4/atn_config_set.go | 301 + .../antlr/v4/atn_deserialization_options.go | 7 +- .../antlr/v4/atn_deserializer.go | 9 +- .../antlr/v4/atn_simulator.go | 17 +- .../Go => antlr4-go}/antlr/v4/atn_state.go | 224 +- .../Go => antlr4-go}/antlr/v4/atn_type.go | 0 .../Go => antlr4-go}/antlr/v4/char_stream.go | 2 +- .../antlr/v4/common_token_factory.go | 0 .../antlr/v4/common_token_stream.go | 39 +- .../Go => antlr4-go}/antlr/v4/comparators.go | 33 +- .../antlr4-go/antlr/v4/configuration.go | 214 + .../runtime/Go => antlr4-go}/antlr/v4/dfa.go | 47 +- .../antlr/v4/dfa_serializer.go | 2 +- .../Go => antlr4-go}/antlr/v4/dfa_state.go | 29 +- .../antlr/v4/diagnostic_error_listener.go | 11 +- .../antlr/v4/error_listener.go | 40 +- .../antlr/v4/error_strategy.go | 450 +- .../Go => antlr4-go}/antlr/v4/errors.go | 73 +- .../Go => antlr4-go}/antlr/v4/file_stream.go | 46 +- .../antlr4-go/antlr/v4/input_stream.go | 157 + .../Go => antlr4-go}/antlr/v4/int_stream.go | 0 .../Go => antlr4-go}/antlr/v4/interval_set.go | 60 +- .../github.com/antlr4-go/antlr/v4/jcollect.go | 685 ++ .../Go => antlr4-go}/antlr/v4/lexer.go | 68 +- .../Go => antlr4-go}/antlr/v4/lexer_action.go | 100 +- .../antlr/v4/lexer_action_executor.go | 61 +- .../antlr/v4/lexer_atn_simulator.go | 185 +- .../Go => antlr4-go}/antlr/v4/ll1_analyzer.go | 62 +- .../antlr4-go/antlr/v4/nostatistics.go | 47 + .../Go => antlr4-go}/antlr/v4/parser.go | 160 +- .../antlr/v4/parser_atn_simulator.go | 787 +- .../antlr/v4/parser_rule_context.go | 85 +- .../antlr4-go/antlr/v4/prediction_context.go | 727 ++ .../antlr/v4/prediction_context_cache.go | 48 + .../antlr4-go/antlr/v4/prediction_mode.go | 536 + .../Go => antlr4-go}/antlr/v4/recognizer.go | 65 +- .../antlr4-go/antlr/v4/rule_context.go | 40 + .../antlr/v4/semantic_context.go | 33 +- .../antlr4-go/antlr/v4/statistics.go | 281 + .../antlr4-go/antlr/v4/stats_data.go | 23 + .../Go => antlr4-go}/antlr/v4/token.go | 36 +- .../Go => antlr4-go}/antlr/v4/token_source.go | 0 .../Go => antlr4-go}/antlr/v4/token_stream.go | 3 +- .../antlr/v4/tokenstream_rewriter.go | 221 +- .../antlr/v4/trace_listener.go | 0 .../Go => antlr4-go}/antlr/v4/transition.go | 229 +- .../runtime/Go => antlr4-go}/antlr/v4/tree.go | 109 +- .../Go => antlr4-go}/antlr/v4/trees.go | 22 +- .../Go => antlr4-go}/antlr/v4/utils.go | 84 +- .../github.com/fvbommel/sortorder/.gitignore | 19 - .../github.com/fvbommel/sortorder/README.md | 9 - vendor/github.com/fvbommel/sortorder/doc.go | 5 - .../github.com/fvbommel/sortorder/natsort.go | 76 - .../github.com/fxamacker/cbor/v2/.gitignore | 12 + .../fxamacker/cbor/v2/.golangci.yml | 104 + .../fxamacker/cbor/v2/CODE_OF_CONDUCT.md | 133 + .../fxamacker/cbor/v2/CONTRIBUTING.md | 41 + .../sortorder => fxamacker/cbor/v2}/LICENSE | 10 +- vendor/github.com/fxamacker/cbor/v2/README.md | 691 ++ .../github.com/fxamacker/cbor/v2/SECURITY.md | 7 + .../fxamacker/cbor/v2/bytestring.go | 63 + vendor/github.com/fxamacker/cbor/v2/cache.go | 363 + vendor/github.com/fxamacker/cbor/v2/common.go | 182 + vendor/github.com/fxamacker/cbor/v2/decode.go | 3187 ++++++ .../github.com/fxamacker/cbor/v2/diagnose.go | 724 ++ vendor/github.com/fxamacker/cbor/v2/doc.go | 129 + vendor/github.com/fxamacker/cbor/v2/encode.go | 1989 ++++ .../fxamacker/cbor/v2/encode_map.go | 94 + .../fxamacker/cbor/v2/encode_map_go117.go | 60 + .../fxamacker/cbor/v2/simplevalue.go | 69 + vendor/github.com/fxamacker/cbor/v2/stream.go | 277 + .../fxamacker/cbor/v2/structfields.go | 260 + vendor/github.com/fxamacker/cbor/v2/tag.go | 299 + vendor/github.com/fxamacker/cbor/v2/valid.go | 394 + .../github.com/google/cel-go/cel/BUILD.bazel | 8 + vendor/github.com/google/cel-go/cel/decls.go | 40 - vendor/github.com/google/cel-go/cel/env.go | 128 +- .../github.com/google/cel-go/cel/folding.go | 559 + .../github.com/google/cel-go/cel/inlining.go | 228 + vendor/github.com/google/cel-go/cel/io.go | 36 +- .../github.com/google/cel-go/cel/library.go | 61 +- vendor/github.com/google/cel-go/cel/macro.go | 456 +- .../github.com/google/cel-go/cel/optimizer.go | 509 + .../github.com/google/cel-go/cel/options.go | 2 + .../github.com/google/cel-go/cel/program.go | 60 +- .../github.com/google/cel-go/cel/validator.go | 51 +- .../google/cel-go/checker/BUILD.bazel | 1 - .../google/cel-go/checker/checker.go | 356 +- .../github.com/google/cel-go/checker/cost.go | 195 +- .../google/cel-go/checker/decls/decls.go | 2 +- .../github.com/google/cel-go/checker/env.go | 8 + .../google/cel-go/checker/errors.go | 18 +- .../google/cel-go/checker/printer.go | 34 +- .../github.com/google/cel-go/checker/types.go | 13 +- .../google/cel-go/common/ast/BUILD.bazel | 16 +- .../google/cel-go/common/ast/ast.go | 480 +- .../google/cel-go/common/ast/conversion.go | 632 ++ .../google/cel-go/common/ast/expr.go | 967 +- .../google/cel-go/common/ast/factory.go | 303 + .../google/cel-go/common/ast/navigable.go | 652 ++ .../cel-go/common/containers/BUILD.bazel | 4 +- .../cel-go/common/containers/container.go | 22 +- .../google/cel-go/common/debug/BUILD.bazel | 4 +- .../google/cel-go/common/debug/debug.go | 156 +- .../github.com/google/cel-go/common/errors.go | 2 +- .../google/cel-go/common/types/err.go | 25 +- .../google/cel-go/common/types/int.go | 12 + .../google/cel-go/common/types/list.go | 8 +- .../google/cel-go/common/types/optional.go | 2 +- .../google/cel-go/common/types/overflow.go | 40 + .../google/cel-go/common/types/provider.go | 51 +- .../google/cel-go/common/types/string.go | 7 +- .../google/cel-go/common/types/types.go | 19 +- .../google/cel-go/common/types/uint.go | 12 + .../github.com/google/cel-go/ext/BUILD.bazel | 7 +- vendor/github.com/google/cel-go/ext/README.md | 14 + .../github.com/google/cel-go/ext/bindings.go | 24 +- .../google/cel-go/ext/formatting.go | 904 ++ vendor/github.com/google/cel-go/ext/guards.go | 11 +- vendor/github.com/google/cel-go/ext/math.go | 67 +- vendor/github.com/google/cel-go/ext/native.go | 66 +- vendor/github.com/google/cel-go/ext/protos.go | 45 +- vendor/github.com/google/cel-go/ext/sets.go | 64 + .../github.com/google/cel-go/ext/strings.go | 456 +- .../google/cel-go/interpreter/BUILD.bazel | 1 - .../google/cel-go/interpreter/attributes.go | 3 + .../google/cel-go/interpreter/formatting.go | 383 - .../cel-go/interpreter/interpretable.go | 50 +- .../google/cel-go/interpreter/interpreter.go | 26 +- .../google/cel-go/interpreter/planner.go | 279 +- .../google/cel-go/interpreter/prune.go | 496 +- .../google/cel-go/parser/BUILD.bazel | 9 +- .../google/cel-go/parser/gen/BUILD.bazel | 2 +- .../cel-go/parser/gen/cel_base_listener.go | 4 +- .../cel-go/parser/gen/cel_base_visitor.go | 5 +- .../google/cel-go/parser/gen/cel_lexer.go | 603 +- .../google/cel-go/parser/gen/cel_listener.go | 5 +- .../google/cel-go/parser/gen/cel_parser.go | 2478 +++-- .../google/cel-go/parser/gen/cel_visitor.go | 8 +- .../google/cel-go/parser/gen/generate.sh | 2 +- .../github.com/google/cel-go/parser/helper.go | 580 +- .../github.com/google/cel-go/parser/input.go | 4 +- .../github.com/google/cel-go/parser/macro.go | 192 +- .../github.com/google/cel-go/parser/parser.go | 189 +- .../google/cel-go/parser/unparser.go | 222 +- .../github.com/moby/spdystream/connection.go | 43 +- vendor/github.com/moby/spdystream/stream.go | 2 + vendor/github.com/moby/term/doc.go | 3 + vendor/github.com/moby/term/tc.go | 20 - vendor/github.com/moby/term/term.go | 101 +- vendor/github.com/moby/term/term_unix.go | 98 + vendor/github.com/moby/term/term_windows.go | 99 +- .../moby/term/{termios.go => termios_unix.go} | 13 +- .../github.com/moby/term/termios_windows.go | 37 + .../moby/term/windows/ansi_reader.go | 4 +- .../github.com/moby/term/windows/console.go | 7 +- vendor/github.com/moby/term/winsize.go | 21 - .../cert-controller/pkg/rotator/rotator.go | 11 +- vendor/github.com/x448/float16/.travis.yml | 13 + vendor/github.com/x448/float16/LICENSE | 22 + vendor/github.com/x448/float16/README.md | 133 + vendor/github.com/x448/float16/float16.go | 302 + .../go.etcd.io/etcd/api/v3/version/version.go | 2 +- vendor/go.etcd.io/etcd/client/v3/client.go | 21 +- vendor/go.etcd.io/etcd/client/v3/config.go | 9 + .../etcd/client/v3/retry_interceptor.go | 20 +- .../google.golang.org/grpc/otelgrpc/config.go | 74 +- .../google.golang.org/grpc/otelgrpc/doc.go | 13 +- .../grpc/otelgrpc/interceptor.go | 125 +- .../grpc/otelgrpc/interceptorinfo.go | 13 +- .../grpc/otelgrpc/internal/parse.go | 13 +- .../grpc/otelgrpc/metadata_supplier.go | 13 +- .../grpc/otelgrpc/semconv.go | 13 +- .../grpc/otelgrpc/stats_handler.go | 117 +- .../grpc/otelgrpc/version.go | 15 +- .../net/http/otelhttp/client.go | 15 +- .../net/http/otelhttp/common.go | 27 +- .../net/http/otelhttp/config.go | 15 +- .../instrumentation/net/http/otelhttp/doc.go | 13 +- .../net/http/otelhttp/handler.go | 113 +- .../net/http/otelhttp/internal/semconv/env.go | 82 + .../http/otelhttp/internal/semconv/util.go | 91 + .../http/otelhttp/internal/semconv/v1.20.0.go | 74 + .../http/otelhttp/internal/semconv/v1.24.0.go | 197 + .../http/otelhttp/internal/semconvutil/gen.go | 13 +- .../otelhttp/internal/semconvutil/httpconv.go | 309 +- .../otelhttp/internal/semconvutil/netconv.go | 191 +- .../net/http/otelhttp/labeler.go | 21 +- .../net/http/otelhttp/transport.go | 124 +- .../net/http/otelhttp/version.go | 15 +- .../instrumentation/net/http/otelhttp/wrap.go | 28 +- .../go.opentelemetry.io/otel/.codespellignore | 4 + vendor/go.opentelemetry.io/otel/.codespellrc | 2 +- vendor/go.opentelemetry.io/otel/.gitignore | 4 - vendor/go.opentelemetry.io/otel/.gitmodules | 3 - vendor/go.opentelemetry.io/otel/.golangci.yml | 6 + vendor/go.opentelemetry.io/otel/CHANGELOG.md | 310 +- vendor/go.opentelemetry.io/otel/CODEOWNERS | 4 +- .../go.opentelemetry.io/otel/CONTRIBUTING.md | 48 +- vendor/go.opentelemetry.io/otel/Makefile | 87 +- vendor/go.opentelemetry.io/otel/README.md | 41 +- vendor/go.opentelemetry.io/otel/RELEASING.md | 12 +- .../otel/attribute/README.md | 3 + .../go.opentelemetry.io/otel/attribute/doc.go | 13 +- .../otel/attribute/encoder.go | 13 +- .../otel/attribute/filter.go | 13 +- .../otel/attribute/iterator.go | 13 +- .../go.opentelemetry.io/otel/attribute/key.go | 13 +- .../go.opentelemetry.io/otel/attribute/kv.go | 13 +- .../go.opentelemetry.io/otel/attribute/set.go | 222 +- .../otel/attribute/value.go | 31 +- .../otel/baggage/README.md | 3 + .../otel/baggage/baggage.go | 522 +- .../otel/baggage/context.go | 13 +- .../go.opentelemetry.io/otel/baggage/doc.go | 13 +- .../go.opentelemetry.io/otel/codes/README.md | 3 + .../go.opentelemetry.io/otel/codes/codes.go | 13 +- vendor/go.opentelemetry.io/otel/codes/doc.go | 13 +- vendor/go.opentelemetry.io/otel/doc.go | 15 +- .../go.opentelemetry.io/otel/error_handler.go | 13 +- .../otel/exporters/otlp/otlptrace/README.md | 3 + .../otel/exporters/otlp/otlptrace/clients.go | 13 +- .../otel/exporters/otlp/otlptrace/doc.go | 13 +- .../otel/exporters/otlp/otlptrace/exporter.go | 15 +- .../internal/tracetransform/attribute.go | 13 +- .../tracetransform/instrumentation.go | 13 +- .../internal/tracetransform/resource.go | 13 +- .../otlptrace/internal/tracetransform/span.go | 26 +- .../otlp/otlptrace/otlptracegrpc/README.md | 3 + .../otlp/otlptrace/otlptracegrpc/client.go | 17 +- .../otlp/otlptrace/otlptracegrpc/doc.go | 21 +- .../otlp/otlptrace/otlptracegrpc/exporter.go | 13 +- .../internal/envconfig/envconfig.go | 13 +- .../otlptrace/otlptracegrpc/internal/gen.go | 13 +- .../internal/otlpconfig/envconfig.go | 13 +- .../internal/otlpconfig/options.go | 52 +- .../internal/otlpconfig/optiontypes.go | 13 +- .../otlptracegrpc/internal/otlpconfig/tls.go | 13 +- .../otlptracegrpc/internal/partialsuccess.go | 13 +- .../otlptracegrpc/internal/retry/retry.go | 13 +- .../otlp/otlptrace/otlptracegrpc/options.go | 53 +- .../otel/exporters/otlp/otlptrace/version.go | 15 +- .../go.opentelemetry.io/otel/get_main_pkgs.sh | 13 +- vendor/go.opentelemetry.io/otel/handler.go | 25 +- .../otel/internal/attribute/attribute.go | 37 +- .../otel/internal/baggage/baggage.go | 13 +- .../otel/internal/baggage/context.go | 13 +- .../go.opentelemetry.io/otel/internal/gen.go | 13 +- .../otel/internal/global/handler.go | 84 +- .../otel/internal/global/instruments.go | 65 +- .../otel/internal/global/internal_logging.go | 39 +- .../otel/internal/global/meter.go | 40 +- .../otel/internal/global/propagator.go | 13 +- .../otel/internal/global/state.go | 73 +- .../otel/internal/global/trace.go | 22 +- .../otel/internal/rawhelpers.go | 13 +- .../otel/internal_logging.go | 13 +- vendor/go.opentelemetry.io/otel/metric.go | 13 +- .../go.opentelemetry.io/otel/metric/README.md | 3 + .../otel/metric/asyncfloat64.go | 19 +- .../otel/metric/asyncint64.go | 13 +- .../go.opentelemetry.io/otel/metric/config.go | 13 +- vendor/go.opentelemetry.io/otel/metric/doc.go | 31 +- .../otel/metric/embedded/README.md | 3 + .../otel/metric/embedded/embedded.go | 33 +- .../otel/metric/instrument.go | 35 +- .../go.opentelemetry.io/otel/metric/meter.go | 77 +- .../otel/metric/noop/README.md | 3 + .../otel/metric/noop/noop.go | 281 + .../otel/metric/syncfloat64.go | 73 +- .../otel/metric/syncint64.go | 67 +- .../go.opentelemetry.io/otel/propagation.go | 13 +- .../otel/propagation/README.md | 3 + .../otel/propagation/baggage.go | 13 +- .../otel/propagation/doc.go | 13 +- .../otel/propagation/propagation.go | 13 +- .../otel/propagation/trace_context.go | 109 +- vendor/go.opentelemetry.io/otel/renovate.json | 24 + .../go.opentelemetry.io/otel/requirements.txt | 2 +- vendor/go.opentelemetry.io/otel/sdk/README.md | 3 + .../otel/sdk/instrumentation/README.md | 3 + .../otel/sdk/instrumentation/doc.go | 13 +- .../otel/sdk/instrumentation/library.go | 13 +- .../otel/sdk/instrumentation/scope.go | 13 +- .../otel/sdk/internal/env/env.go | 15 +- .../otel/sdk/internal/gen.go | 29 - .../otel/sdk/internal/internal.go | 28 - .../otel/sdk/internal/x/README.md | 46 + .../otel/sdk/internal/x/x.go | 66 + .../otel/sdk/resource/README.md | 3 + .../otel/sdk/resource/auto.go | 38 +- .../otel/sdk/resource/builtin.go | 36 +- .../otel/sdk/resource/config.go | 13 +- .../otel/sdk/resource/container.go | 17 +- .../otel/sdk/resource/doc.go | 13 +- .../otel/sdk/resource/env.go | 15 +- .../otel/sdk/resource/host_id.go | 15 +- .../otel/sdk/resource/host_id_bsd.go | 13 +- .../otel/sdk/resource/host_id_darwin.go | 13 +- .../otel/sdk/resource/host_id_exec.go | 13 +- .../otel/sdk/resource/host_id_linux.go | 13 +- .../otel/sdk/resource/host_id_readfile.go | 13 +- .../otel/sdk/resource/host_id_unsupported.go | 23 +- .../otel/sdk/resource/host_id_windows.go | 13 +- .../otel/sdk/resource/os.go | 15 +- .../otel/sdk/resource/os_release_darwin.go | 13 +- .../otel/sdk/resource/os_release_unix.go | 13 +- .../otel/sdk/resource/os_unix.go | 13 +- .../otel/sdk/resource/os_unsupported.go | 25 +- .../otel/sdk/resource/os_windows.go | 13 +- .../otel/sdk/resource/process.go | 15 +- .../otel/sdk/resource/resource.go | 103 +- .../otel/sdk/trace/README.md | 3 + .../otel/sdk/trace/batch_span_processor.go | 17 +- .../go.opentelemetry.io/otel/sdk/trace/doc.go | 13 +- .../otel/sdk/trace/event.go | 13 +- .../otel/sdk/trace/evictedqueue.go | 49 +- .../otel/sdk/trace/id_generator.go | 34 +- .../otel/sdk/trace/link.go | 13 +- .../otel/sdk/trace/provider.go | 17 +- .../otel/sdk/trace/sampler_env.go | 13 +- .../otel/sdk/trace/sampling.go | 13 +- .../otel/sdk/trace/simple_span_processor.go | 50 +- .../otel/sdk/trace/snapshot.go | 13 +- .../otel/sdk/trace/span.go | 97 +- .../otel/sdk/trace/span_exporter.go | 13 +- .../otel/sdk/trace/span_limits.go | 13 +- .../otel/sdk/trace/span_processor.go | 13 +- .../otel/sdk/trace/tracer.go | 19 +- .../otel/sdk/trace/version.go | 13 +- .../go.opentelemetry.io/otel/sdk/version.go | 15 +- .../otel/semconv/internal/http.go | 13 +- .../otel/semconv/v1.12.0/README.md | 3 + .../otel/semconv/v1.12.0/doc.go | 13 +- .../otel/semconv/v1.12.0/exception.go | 13 +- .../otel/semconv/v1.12.0/http.go | 13 +- .../otel/semconv/v1.12.0/resource.go | 13 +- .../otel/semconv/v1.12.0/schema.go | 13 +- .../otel/semconv/v1.12.0/trace.go | 17 +- .../otel/semconv/v1.17.0/README.md | 3 + .../otel/semconv/v1.17.0/doc.go | 13 +- .../otel/semconv/v1.17.0/event.go | 13 +- .../otel/semconv/v1.17.0/exception.go | 13 +- .../otel/semconv/v1.17.0/http.go | 13 +- .../otel/semconv/v1.17.0/resource.go | 13 +- .../otel/semconv/v1.17.0/schema.go | 13 +- .../otel/semconv/v1.17.0/trace.go | 13 +- .../otel/semconv/v1.20.0/README.md | 3 + .../otel/semconv/v1.20.0/attribute_group.go | 1198 +++ .../otel/semconv/v1.20.0/doc.go | 9 + .../semconv/{v1.21.0 => v1.20.0}/event.go | 15 +- .../otel/semconv/v1.20.0/exception.go | 9 + .../otel/semconv/v1.20.0/http.go | 10 + .../semconv/{v1.21.0 => v1.20.0}/resource.go | 314 +- .../otel/semconv/v1.20.0/schema.go | 9 + .../semconv/{v1.21.0 => v1.20.0}/trace.go | 176 +- .../otel/semconv/v1.21.0/attribute_group.go | 1877 ---- .../otel/semconv/v1.21.0/doc.go | 20 - .../otel/semconv/v1.21.0/exception.go | 20 - .../otel/semconv/v1.21.0/schema.go | 20 - .../otel/semconv/v1.24.0/README.md | 3 + .../otel/semconv/v1.24.0/attribute_group.go | 4387 ++++++++ .../otel/semconv/v1.24.0/doc.go | 9 + .../otel/semconv/v1.24.0/event.go | 200 + .../otel/semconv/v1.24.0/exception.go | 9 + .../otel/semconv/v1.24.0/metric.go | 1071 ++ .../otel/semconv/v1.24.0/resource.go | 2545 +++++ .../otel/semconv/v1.24.0/schema.go | 9 + .../otel/semconv/v1.24.0/trace.go | 1323 +++ .../otel/semconv/v1.26.0/README.md | 3 + .../otel/semconv/v1.26.0/attribute_group.go | 8996 +++++++++++++++++ .../otel/semconv/v1.26.0/doc.go | 9 + .../otel/semconv/v1.26.0/exception.go | 9 + .../otel/semconv/v1.26.0/metric.go | 1307 +++ .../otel/semconv/v1.26.0/schema.go | 9 + vendor/go.opentelemetry.io/otel/trace.go | 13 +- .../go.opentelemetry.io/otel/trace/README.md | 3 + .../go.opentelemetry.io/otel/trace/config.go | 13 +- .../go.opentelemetry.io/otel/trace/context.go | 17 +- vendor/go.opentelemetry.io/otel/trace/doc.go | 13 +- .../otel/trace/embedded/README.md | 3 + .../otel/trace/embedded/embedded.go | 13 +- .../otel/trace/nonrecording.go | 13 +- vendor/go.opentelemetry.io/otel/trace/noop.go | 20 +- .../otel/trace/noop/README.md | 3 + .../otel/trace/noop/noop.go | 20 +- .../go.opentelemetry.io/otel/trace/trace.go | 19 +- .../otel/trace/tracestate.go | 210 +- .../otel/verify_examples.sh | 13 +- .../otel/verify_readmes.sh | 21 + vendor/go.opentelemetry.io/otel/version.go | 15 +- vendor/go.opentelemetry.io/otel/versions.yaml | 42 +- .../proto/otlp/trace/v1/trace.pb.go | 397 +- vendor/golang.org/x/text/cases/cases.go | 162 + vendor/golang.org/x/text/cases/context.go | 376 + vendor/golang.org/x/text/cases/fold.go | 34 + vendor/golang.org/x/text/cases/icu.go | 61 + vendor/golang.org/x/text/cases/info.go | 82 + vendor/golang.org/x/text/cases/map.go | 816 ++ .../golang.org/x/text/cases/tables10.0.0.go | 2255 +++++ .../golang.org/x/text/cases/tables11.0.0.go | 2316 +++++ .../golang.org/x/text/cases/tables12.0.0.go | 2359 +++++ .../golang.org/x/text/cases/tables13.0.0.go | 2399 +++++ .../golang.org/x/text/cases/tables15.0.0.go | 2527 +++++ vendor/golang.org/x/text/cases/tables9.0.0.go | 2215 ++++ vendor/golang.org/x/text/cases/trieval.go | 217 + vendor/google.golang.org/grpc/README.md | 2 +- .../{ => balancer/pickfirst}/pickfirst.go | 32 +- .../grpc/balancer/roundrobin/roundrobin.go | 4 +- .../grpc/balancer_wrapper.go | 4 + .../grpc_binarylog_v1/binarylog.pb.go | 2 +- vendor/google.golang.org/grpc/clientconn.go | 66 +- .../google.golang.org/grpc/credentials/tls.go | 34 +- vendor/google.golang.org/grpc/dialoptions.go | 46 + .../grpc/health/grpc_health_v1/health.pb.go | 2 +- .../health/grpc_health_v1/health_grpc.pb.go | 10 +- .../grpc/internal/backoff/backoff.go | 4 +- .../grpc/internal/envconfig/envconfig.go | 6 + .../grpc/internal/grpcrand/grpcrand.go | 100 - .../grpc/internal/grpcrand/grpcrand_go1.21.go | 73 - .../grpc/internal/internal.go | 37 +- .../internal/resolver/dns/dns_resolver.go | 14 +- .../resolver/dns/internal/internal.go | 13 +- .../grpc/internal/transport/http2_server.go | 4 +- .../grpc/metadata/metadata.go | 15 - .../google.golang.org/grpc/picker_wrapper.go | 81 +- .../grpc/resolver_wrapper.go | 2 +- .../google.golang.org/grpc/service_config.go | 24 +- vendor/google.golang.org/grpc/stream.go | 4 +- vendor/google.golang.org/grpc/version.go | 2 +- .../evanphx/json-patch.v4}/.gitignore | 0 .../evanphx/json-patch.v4}/LICENSE | 0 .../evanphx/json-patch.v4}/README.md | 4 +- .../evanphx/json-patch.v4}/errors.go | 0 .../evanphx/json-patch.v4}/merge.go | 0 .../evanphx/json-patch.v4}/patch.go | 4 +- vendor/k8s.io/api/admission/v1/doc.go | 2 +- .../k8s.io/api/admission/v1/generated.proto | 18 +- vendor/k8s.io/api/admission/v1/types.go | 1 + .../v1/zz_generated.prerelease-lifecycle.go | 28 + .../api/admission/v1beta1/generated.proto | 18 +- .../api/admissionregistration/v1/doc.go | 1 + .../admissionregistration/v1/generated.proto | 39 +- .../api/admissionregistration/v1/types.go | 6 + .../v1/zz_generated.prerelease-lifecycle.go | 70 + .../v1alpha1/generated.proto | 18 +- .../v1beta1/generated.proto | 38 +- .../config/v1 => api/apidiscovery/v2}/doc.go | 12 +- .../api/apidiscovery/v2/generated.pb.go | 1742 ++++ .../api/apidiscovery/v2/generated.proto | 156 + .../apidiscovery/v2}/register.go | 37 +- vendor/k8s.io/api/apidiscovery/v2/types.go | 157 + .../apidiscovery/v2/zz_generated.deepcopy.go | 190 + .../v2/zz_generated.prerelease-lifecycle.go | 34 + .../api/apidiscovery/v2beta1/generated.proto | 10 +- .../v1alpha1/generated.proto | 6 +- vendor/k8s.io/api/apps/v1/doc.go | 1 + vendor/k8s.io/api/apps/v1/generated.proto | 67 +- vendor/k8s.io/api/apps/v1/types.go | 17 +- .../apps/v1/types_swagger_doc_generated.go | 4 +- .../v1/zz_generated.prerelease-lifecycle.go | 82 + .../k8s.io/api/apps/v1beta1/generated.proto | 42 +- vendor/k8s.io/api/apps/v1beta1/types.go | 4 +- .../v1beta1/types_swagger_doc_generated.go | 2 +- .../k8s.io/api/apps/v1beta2/generated.proto | 66 +- vendor/k8s.io/api/apps/v1beta2/types.go | 4 +- .../v1beta2/types_swagger_doc_generated.go | 2 +- vendor/k8s.io/api/authentication/v1/doc.go | 1 + .../api/authentication/v1/generated.proto | 8 +- vendor/k8s.io/api/authentication/v1/types.go | 3 + .../v1/zz_generated.prerelease-lifecycle.go | 40 + .../authentication/v1alpha1/generated.proto | 4 +- .../authentication/v1beta1/generated.proto | 6 +- vendor/k8s.io/api/authorization/v1/doc.go | 2 +- .../api/authorization/v1/generated.pb.go | 724 +- .../api/authorization/v1/generated.proto | 76 +- vendor/k8s.io/api/authorization/v1/types.go | 70 + .../v1/types_swagger_doc_generated.go | 38 +- .../authorization/v1/zz_generated.deepcopy.go | 61 +- .../v1/zz_generated.prerelease-lifecycle.go | 46 + .../api/authorization/v1beta1/generated.pb.go | 255 +- .../api/authorization/v1beta1/generated.proto | 17 +- .../k8s.io/api/authorization/v1beta1/types.go | 7 + .../v1beta1/types_swagger_doc_generated.go | 18 +- .../v1beta1/zz_generated.deepcopy.go | 15 +- vendor/k8s.io/api/autoscaling/v1/doc.go | 1 + .../k8s.io/api/autoscaling/v1/generated.proto | 50 +- vendor/k8s.io/api/autoscaling/v1/types.go | 3 + .../v1/zz_generated.prerelease-lifecycle.go | 40 + vendor/k8s.io/api/autoscaling/v2/doc.go | 1 + .../k8s.io/api/autoscaling/v2/generated.proto | 18 +- vendor/k8s.io/api/autoscaling/v2/types.go | 2 + .../v2/zz_generated.prerelease-lifecycle.go | 34 + .../api/autoscaling/v2beta1/generated.proto | 48 +- .../api/autoscaling/v2beta2/generated.proto | 18 +- vendor/k8s.io/api/batch/v1/doc.go | 2 +- vendor/k8s.io/api/batch/v1/generated.proto | 41 +- vendor/k8s.io/api/batch/v1/types.go | 25 +- .../batch/v1/types_swagger_doc_generated.go | 8 +- .../v1/zz_generated.prerelease-lifecycle.go | 46 + .../k8s.io/api/batch/v1beta1/generated.proto | 14 +- vendor/k8s.io/api/certificates/v1/doc.go | 2 +- .../api/certificates/v1/generated.proto | 8 +- vendor/k8s.io/api/certificates/v1/types.go | 2 + .../v1/zz_generated.prerelease-lifecycle.go | 34 + .../api/certificates/v1alpha1/generated.proto | 4 +- .../api/certificates/v1beta1/generated.proto | 8 +- vendor/k8s.io/api/coordination/v1/doc.go | 1 + .../api/coordination/v1/generated.pb.go | 162 +- .../api/coordination/v1/generated.proto | 26 +- vendor/k8s.io/api/coordination/v1/types.go | 30 +- .../v1/types_swagger_doc_generated.go | 6 +- .../coordination/v1/zz_generated.deepcopy.go | 10 + .../v1/zz_generated.prerelease-lifecycle.go | 34 + .../k8s.io/api/coordination/v1alpha1/doc.go | 24 + .../api/coordination/v1alpha1/generated.pb.go | 1036 ++ .../api/coordination/v1alpha1/generated.proto | 105 + .../coordination/v1alpha1}/register.go | 40 +- .../k8s.io/api/coordination/v1alpha1/types.go | 100 + .../v1alpha1/types_swagger_doc_generated.go | 64 + .../v1alpha1/zz_generated.deepcopy.go | 116 + .../zz_generated.prerelease-lifecycle.go | 58 + .../api/coordination/v1beta1/generated.pb.go | 165 +- .../api/coordination/v1beta1/generated.proto | 23 +- .../k8s.io/api/coordination/v1beta1/types.go | 13 + .../v1beta1/types_swagger_doc_generated.go | 4 +- .../v1beta1/zz_generated.deepcopy.go | 11 + vendor/k8s.io/api/core/v1/doc.go | 2 + vendor/k8s.io/api/core/v1/generated.pb.go | 5058 +++++---- vendor/k8s.io/api/core/v1/generated.proto | 452 +- vendor/k8s.io/api/core/v1/types.go | 353 +- .../core/v1/types_swagger_doc_generated.go | 168 +- .../api/core/v1/zz_generated.deepcopy.go | 185 +- .../v1/zz_generated.prerelease-lifecycle.go | 274 + vendor/k8s.io/api/discovery/v1/doc.go | 1 + .../k8s.io/api/discovery/v1/generated.proto | 6 +- vendor/k8s.io/api/discovery/v1/types.go | 2 + .../v1/zz_generated.prerelease-lifecycle.go | 34 + .../api/discovery/v1beta1/generated.proto | 6 +- vendor/k8s.io/api/events/v1/doc.go | 2 +- vendor/k8s.io/api/events/v1/generated.proto | 18 +- vendor/k8s.io/api/events/v1/types.go | 2 + .../v1/zz_generated.prerelease-lifecycle.go | 34 + .../k8s.io/api/events/v1beta1/generated.proto | 18 +- .../api/extensions/v1beta1/generated.proto | 62 +- vendor/k8s.io/api/extensions/v1beta1/types.go | 2 +- vendor/k8s.io/api/flowcontrol/v1/doc.go | 1 + .../k8s.io/api/flowcontrol/v1/generated.proto | 12 +- vendor/k8s.io/api/flowcontrol/v1/types.go | 4 + .../v1/zz_generated.prerelease-lifecycle.go | 46 + .../api/flowcontrol/v1beta1/generated.proto | 12 +- .../api/flowcontrol/v1beta2/generated.proto | 12 +- .../api/flowcontrol/v1beta3/generated.proto | 12 +- .../api/imagepolicy/v1alpha1/generated.proto | 2 +- vendor/k8s.io/api/networking/v1/doc.go | 1 + .../k8s.io/api/networking/v1/generated.proto | 23 +- vendor/k8s.io/api/networking/v1/types.go | 9 +- .../v1/zz_generated.prerelease-lifecycle.go | 58 + .../api/networking/v1alpha1/generated.proto | 13 +- .../k8s.io/api/networking/v1alpha1/types.go | 3 + .../v1alpha1/types_swagger_doc_generated.go | 2 +- .../api/networking/v1beta1/generated.pb.go | 3424 +++++-- .../api/networking/v1beta1/generated.proto | 121 +- .../k8s.io/api/networking/v1beta1/register.go | 4 + vendor/k8s.io/api/networking/v1beta1/types.go | 132 +- .../v1beta1/types_swagger_doc_generated.go | 80 + .../networking/v1beta1/well_known_labels.go | 33 + .../v1beta1/zz_generated.deepcopy.go | 203 + .../zz_generated.prerelease-lifecycle.go | 72 + vendor/k8s.io/api/node/v1/doc.go | 2 +- vendor/k8s.io/api/node/v1/generated.proto | 8 +- vendor/k8s.io/api/node/v1/types.go | 2 + .../v1/zz_generated.prerelease-lifecycle.go | 34 + .../k8s.io/api/node/v1alpha1/generated.proto | 8 +- .../k8s.io/api/node/v1beta1/generated.proto | 8 +- vendor/k8s.io/api/policy/v1/doc.go | 1 + vendor/k8s.io/api/policy/v1/generated.proto | 18 +- vendor/k8s.io/api/policy/v1/types.go | 3 + .../v1/zz_generated.prerelease-lifecycle.go | 40 + .../k8s.io/api/policy/v1beta1/generated.proto | 18 +- vendor/k8s.io/api/rbac/v1/doc.go | 2 +- vendor/k8s.io/api/rbac/v1/generated.proto | 18 +- vendor/k8s.io/api/rbac/v1/types.go | 10 +- .../v1/zz_generated.prerelease-lifecycle.go | 70 + .../k8s.io/api/rbac/v1alpha1/generated.proto | 18 +- vendor/k8s.io/api/rbac/v1alpha1/types.go | 2 +- .../k8s.io/api/rbac/v1beta1/generated.proto | 18 +- vendor/k8s.io/api/rbac/v1beta1/types.go | 2 +- .../api/resource/v1alpha2/generated.proto | 749 -- .../api/resource/v1alpha2/namedresources.go | 127 - vendor/k8s.io/api/resource/v1alpha2/types.go | 737 -- .../v1alpha2/types_swagger_doc_generated.go | 395 - .../resource/{v1alpha2 => v1alpha3}/doc.go | 4 +- .../{v1alpha2 => v1alpha3}/generated.pb.go | 7720 ++++++-------- .../api/resource/v1alpha3/generated.proto | 912 ++ .../{v1alpha2 => v1alpha3}/register.go | 15 +- vendor/k8s.io/api/resource/v1alpha3/types.go | 1048 ++ .../v1alpha3/types_swagger_doc_generated.go | 404 + .../zz_generated.deepcopy.go | 799 +- vendor/k8s.io/api/scheduling/v1/doc.go | 2 +- .../k8s.io/api/scheduling/v1/generated.proto | 4 +- vendor/k8s.io/api/scheduling/v1/types.go | 2 + .../v1/zz_generated.prerelease-lifecycle.go | 34 + .../api/scheduling/v1alpha1/generated.proto | 4 +- .../api/scheduling/v1beta1/generated.proto | 4 +- vendor/k8s.io/api/storage/v1/doc.go | 1 + vendor/k8s.io/api/storage/v1/generated.proto | 32 +- vendor/k8s.io/api/storage/v1/types.go | 10 + .../v1/zz_generated.prerelease-lifecycle.go | 82 + .../api/storage/v1alpha1/generated.proto | 22 +- .../api/storage/v1beta1/generated.pb.go | 821 +- .../api/storage/v1beta1/generated.proto | 72 +- vendor/k8s.io/api/storage/v1beta1/register.go | 3 + vendor/k8s.io/api/storage/v1beta1/types.go | 52 + .../v1beta1/types_swagger_doc_generated.go | 21 + .../storage/v1beta1/zz_generated.deepcopy.go | 66 + .../zz_generated.prerelease-lifecycle.go | 36 + .../api/storagemigration/v1alpha1/doc.go | 23 + .../storagemigration/v1alpha1/generated.pb.go | 1688 ++++ .../storagemigration/v1alpha1/generated.proto | 127 + .../api/storagemigration/v1alpha1/register.go | 58 + .../api/storagemigration/v1alpha1/types.go | 131 + .../v1alpha1/types_swagger_doc_generated.go | 95 + .../v1alpha1/zz_generated.deepcopy.go | 160 + .../zz_generated.prerelease-lifecycle.go | 58 + .../pkg/apis/apiextensions/types.go | 25 + .../apis/apiextensions/types_jsonschema.go | 1 - .../pkg/apis/apiextensions/v1/conversion.go | 26 +- .../pkg/apis/apiextensions/v1/doc.go | 1 + .../pkg/apis/apiextensions/v1/generated.pb.go | 679 +- .../pkg/apis/apiextensions/v1/generated.proto | 51 +- .../pkg/apis/apiextensions/v1/marshal.go | 2 +- .../pkg/apis/apiextensions/v1/types.go | 33 + .../apis/apiextensions/v1/types_jsonschema.go | 53 +- .../v1/zz_generated.conversion.go | 33 + .../apiextensions/v1/zz_generated.deepcopy.go | 21 + .../v1/zz_generated.prerelease-lifecycle.go | 40 + .../apiextensions/v1beta1/generated.pb.go | 742 +- .../apiextensions/v1beta1/generated.proto | 59 +- .../pkg/apis/apiextensions/v1beta1/marshal.go | 2 +- .../pkg/apis/apiextensions/v1beta1/types.go | 38 + .../apiextensions/v1beta1/types_jsonschema.go | 53 +- .../v1beta1/zz_generated.conversion.go | 34 + .../v1beta1/zz_generated.deepcopy.go | 26 + .../apiextensions/zz_generated.deepcopy.go | 26 + .../v1/customresourcecolumndefinition.go | 4 +- .../v1/customresourceconversion.go | 4 +- .../v1/customresourcedefinition.go | 10 +- .../v1/customresourcedefinitioncondition.go | 4 +- .../v1/customresourcedefinitionnames.go | 4 +- .../v1/customresourcedefinitionspec.go | 4 +- .../v1/customresourcedefinitionstatus.go | 4 +- .../v1/customresourcedefinitionversion.go | 18 +- .../v1/customresourcesubresources.go | 4 +- .../v1/customresourcesubresourcescale.go | 4 +- .../v1/customresourcevalidation.go | 4 +- .../apiextensions/v1/externaldocumentation.go | 4 +- .../apiextensions/v1/jsonschemaprops.go | 4 +- .../apiextensions/v1/selectablefield.go | 39 + .../apiextensions/v1/servicereference.go | 4 +- .../apiextensions/v1/validationrule.go | 4 +- .../apiextensions/v1/webhookclientconfig.go | 4 +- .../apiextensions/v1/webhookconversion.go | 4 +- .../v1beta1/customresourcecolumndefinition.go | 4 +- .../v1beta1/customresourceconversion.go | 4 +- .../v1beta1/customresourcedefinition.go | 10 +- .../customresourcedefinitioncondition.go | 4 +- .../v1beta1/customresourcedefinitionnames.go | 4 +- .../v1beta1/customresourcedefinitionspec.go | 18 +- .../v1beta1/customresourcedefinitionstatus.go | 4 +- .../customresourcedefinitionversion.go | 18 +- .../v1beta1/customresourcesubresources.go | 4 +- .../v1beta1/customresourcesubresourcescale.go | 4 +- .../v1beta1/customresourcevalidation.go | 4 +- .../v1beta1/externaldocumentation.go | 4 +- .../apiextensions/v1beta1/jsonschemaprops.go | 4 +- .../apiextensions/v1beta1/selectablefield.go | 39 + .../apiextensions/v1beta1/servicereference.go | 4 +- .../apiextensions/v1beta1/validationrule.go | 4 +- .../v1beta1/webhookclientconfig.go | 4 +- .../v1/customresourcedefinition.go | 192 +- .../v1beta1/customresourcedefinition.go | 192 +- .../meta/testrestmapper/test_restmapper.go | 165 + .../apimachinery/pkg/api/resource/quantity.go | 29 + .../pkg/apis/meta/v1/controller_ref.go | 13 +- .../pkg/apis/meta/v1/generated.pb.go | 677 +- .../pkg/apis/meta/v1/generated.proto | 23 +- .../apimachinery/pkg/apis/meta/v1/helpers.go | 83 +- .../pkg/apis/meta/v1/micro_time.go | 28 + .../apimachinery/pkg/apis/meta/v1/time.go | 29 + .../apimachinery/pkg/apis/meta/v1/types.go | 27 + .../meta/v1/types_swagger_doc_generated.go | 11 + .../pkg/apis/meta/v1/validation/validation.go | 41 +- .../pkg/apis/meta/v1/zz_generated.deepcopy.go | 21 + .../pkg/apis/meta/v1beta1/generated.proto | 4 +- .../apimachinery/pkg/labels/selector.go | 20 + .../apimachinery/pkg/runtime/extension.go | 100 +- .../runtime/serializer/cbor/direct/direct.go | 36 + .../serializer/cbor/internal/modes/buffers.go | 65 + .../serializer/cbor/internal/modes/custom.go | 422 + .../serializer/cbor/internal/modes/decode.go | 158 + .../cbor/internal/modes/diagnostic.go} | 27 +- .../serializer/cbor/internal/modes/encode.go | 155 + .../k8s.io/apimachinery/pkg/runtime/types.go | 1 + .../apimachinery/pkg/util/framer/framer.go | 18 +- .../apimachinery/pkg/util/intstr/intstr.go | 26 + .../apimachinery/pkg/util/runtime/runtime.go | 135 +- .../k8s.io/apimachinery/pkg/util/sets/set.go | 8 +- .../pkg/util/strategicpatch/patch.go | 4 + .../apimachinery/pkg/util/version/version.go | 112 + vendor/k8s.io/apimachinery/pkg/watch/watch.go | 40 +- .../pkg/admission/initializer/initializer.go | 7 + .../pkg/admission/initializer/interfaces.go | 8 + .../pkg/admission/plugin/cel/compile.go | 77 +- .../pkg/admission/plugin/cel/composition.go | 17 +- .../pkg/admission/plugin/cel/filter.go | 4 + .../pkg/admission/plugin/cel/interface.go | 4 +- .../plugin/policy/generic/accessor.go | 42 + .../plugin/policy/generic/interfaces.go | 64 + .../admission/plugin/policy/generic/plugin.go | 215 + .../policy/generic/policy_dispatcher.go | 354 + .../generic/policy_matcher.go} | 75 +- .../plugin/policy/generic/policy_source.go | 477 + .../policy/generic/policy_test_context.go | 639 ++ .../internal/generic/controller.go | 22 +- .../internal/generic/doc.go | 0 .../internal/generic/informer.go | 4 + .../internal/generic/interface.go | 0 .../internal/generic/lister.go | 0 .../matching/matching.go | 7 +- .../plugin/policy/validating/accessor.go | 82 + .../validating}/caching_authorizer.go | 41 +- .../validating/dispatcher.go} | 386 +- .../plugin/policy/validating/errors.go | 38 + .../validating}/initializer.go | 2 +- .../validating}/interface.go | 20 +- .../validating}/message.go | 2 +- .../policy/validating/metrics/errors.go} | 31 +- .../policy/validating/metrics}/metrics.go | 77 +- .../plugin/policy/validating/plugin.go | 215 + .../validating}/policy_decision.go | 2 +- .../validating}/typechecking.go | 148 +- .../validating}/validator.go | 11 +- .../plugin/validatingadmissionpolicy/OWNERS | 10 - .../validatingadmissionpolicy/admission.go | 197 - .../controller_reconcile.go | 551 - .../pkg/admission/plugin/webhook/accessors.go | 12 + .../config/apis/webhookadmission/doc.go | 2 +- .../config/apis/webhookadmission/v1/doc.go | 2 +- .../apis/webhookadmission/v1alpha1/doc.go | 2 +- .../plugin/webhook/generic/webhook.go | 6 +- .../plugin/webhook/mutating/dispatcher.go | 2 +- .../pkg/apis/apidiscovery/v2/conversion.go | 226 + .../apis/{config => apidiscovery/v2}/doc.go | 6 +- .../pkg/apis/apidiscovery/v2/register.go | 39 + .../apiserver/pkg/apis/apiserver/register.go | 1 + .../apiserver/pkg/apis/apiserver/types.go | 66 +- .../types_encryption.go} | 2 +- .../apis/{config => apiserver}/v1/defaults.go | 0 .../pkg/apis/apiserver/v1/register.go | 4 + .../v1/types_encryption.go} | 0 .../apiserver/v1/zz_generated.conversion.go | 259 + .../apiserver/v1/zz_generated.deepcopy.go | 202 + .../apiserver/v1/zz_generated.defaults.go | 13 + .../pkg/apis/apiserver/v1alpha1/types.go | 100 +- .../v1alpha1/zz_generated.conversion.go | 97 +- .../v1alpha1/zz_generated.deepcopy.go | 47 + .../pkg/apis/apiserver/v1beta1/defaults.go | 36 + .../pkg/apis/apiserver/v1beta1/register.go | 4 +- .../pkg/apis/apiserver/v1beta1/types.go | 460 + .../v1beta1/zz_generated.conversion.go | 589 ++ .../v1beta1/zz_generated.deepcopy.go | 352 + .../v1beta1/zz_generated.defaults.go | 10 + .../apis/apiserver/validation/validation.go | 305 +- .../validation/validation_encryption.go} | 27 +- .../apis/apiserver/zz_generated.deepcopy.go | 244 + .../pkg/apis/audit/v1/generated.pb.go | 187 +- .../pkg/apis/audit/v1/generated.proto | 32 +- .../apiserver/pkg/apis/audit/v1/types.go | 12 + .../apis/config/v1/zz_generated.conversion.go | 299 - .../apis/config/v1/zz_generated.deepcopy.go | 228 - .../apis/config/v1/zz_generated.defaults.go | 46 - .../pkg/apis/config/zz_generated.deepcopy.go | 228 - .../authenticatorfactory/delegating.go | 13 +- .../pkg/authentication/cel/compile.go | 1 + .../pkg/authentication/cel/interface.go | 1 + .../request/anonymous/anonymous.go | 45 +- .../request/headerrequest/requestheader.go | 45 - .../headerrequest/requestheader_controller.go | 9 +- .../pkg/authentication/serviceaccount/util.go | 6 + .../authorization/authorizer/interfaces.go | 27 +- .../authorizerfactory/delegating.go | 7 +- .../authorizerfactory/metrics.go | 39 +- .../pkg/authorization/cel/compile.go | 124 +- .../pkg/authorization/cel/matcher.go | 27 +- .../pkg/authorization/cel/metrics.go | 120 + vendor/k8s.io/apiserver/pkg/cel/cidr.go | 87 + .../apiserver/pkg/cel/environment/base.go | 117 +- .../pkg/cel/environment/environment.go | 34 +- vendor/k8s.io/apiserver/pkg/cel/errors.go | 79 +- vendor/k8s.io/apiserver/pkg/cel/format.go | 73 + vendor/k8s.io/apiserver/pkg/cel/ip.go | 86 + .../k8s.io/apiserver/pkg/cel/library/authz.go | 153 +- .../k8s.io/apiserver/pkg/cel/library/cidr.go | 287 + .../k8s.io/apiserver/pkg/cel/library/cost.go | 269 +- .../apiserver/pkg/cel/library/format.go | 270 + vendor/k8s.io/apiserver/pkg/cel/library/ip.go | 329 + vendor/k8s.io/apiserver/pkg/cel/limits.go | 2 + vendor/k8s.io/apiserver/pkg/cel/quantity.go | 2 +- vendor/k8s.io/apiserver/pkg/cel/types.go | 87 +- .../endpoints/discovery/aggregated/etag.go | 4 +- .../endpoints/discovery/aggregated/fake.go | 6 +- .../endpoints/discovery/aggregated/handler.go | 72 +- .../discovery/aggregated/negotiation.go | 4 +- .../endpoints/discovery/aggregated/wrapper.go | 7 +- .../pkg/endpoints/filters/authorization.go | 31 + .../pkg/endpoints/filters/request_deadline.go | 14 +- .../apiserver/pkg/endpoints/filters/traces.go | 28 + .../pkg/endpoints/filters/webhook_duration.go | 3 +- .../apiserver/pkg/endpoints/groupversion.go | 4 +- .../handlers/fieldmanager/equality.go | 51 +- .../endpoints/handlers/fieldmanager/node.yaml | 2 +- .../apiserver/pkg/endpoints/handlers/get.go | 32 +- .../apiserver/pkg/endpoints/handlers/patch.go | 2 +- .../apiserver/pkg/endpoints/handlers/watch.go | 141 +- .../apiserver/pkg/endpoints/installer.go | 36 +- .../pkg/endpoints/request/requestinfo.go | 31 + .../pkg/endpoints/request/webhook_duration.go | 28 +- .../apiserver/pkg/features/kube_features.go | 150 +- .../apiserver/pkg/registry/generic/options.go | 8 +- .../pkg/registry/generic/registry/store.go | 66 +- .../apiserver/pkg/registry/rest/rest.go | 10 + vendor/k8s.io/apiserver/pkg/server/config.go | 68 +- .../apiserver/pkg/server/deleted_kinds.go | 64 +- .../configmap_cafile_content.go | 7 +- .../dynamic_cafile_content.go | 7 +- .../dynamic_serving_content.go | 7 +- .../server/dynamiccertificates/tlsconfig.go | 7 +- .../apiserver/pkg/server/filters/timeout.go | 4 +- .../apiserver/pkg/server/filters/wrap.go | 3 +- .../apiserver/pkg/server/genericapiserver.go | 116 +- vendor/k8s.io/apiserver/pkg/server/healthz.go | 117 +- .../apiserver/pkg/server/healthz/healthz.go | 29 +- vendor/k8s.io/apiserver/pkg/server/hooks.go | 15 +- .../apiserver/pkg/server/httplog/httplog.go | 19 +- .../apiserver/pkg/server/mux/pathrecorder.go | 4 +- .../apiserver/pkg/server/options/admission.go | 30 +- .../pkg/server/options/authentication.go | 8 +- .../options/deprecated_insecure_serving.go | 126 - .../server/options/encryptionconfig/config.go | 43 +- .../encryptionconfig/controller/controller.go | 11 +- .../encryptionconfig/metrics/metrics.go | 46 +- .../apiserver/pkg/server/options/etcd.go | 14 +- .../apiserver/pkg/server/options/feature.go | 3 + .../pkg/server/options/recommended.go | 19 +- .../pkg/server/options/server_run_options.go | 64 +- .../apiserver/pkg/server/options/serving.go | 6 + vendor/k8s.io/apiserver/pkg/server/plugins.go | 2 +- .../apiserver/pkg/server/routine/routine.go | 91 + .../storage/resource_encoding_config.go | 111 +- .../pkg/server/storage/storage_factory.go | 19 +- .../pkg/server/storage_readiness_hook.go | 91 + .../apiserver/pkg/storage/cacher/cacher.go | 327 +- .../pkg/storage/cacher/metrics/metrics.go | 38 + .../apiserver/pkg/storage/cacher/util.go | 14 - .../pkg/storage/cacher/watch_cache.go | 119 +- .../storage/cacher/watch_cache_interval.go | 17 +- .../pkg/storage/cacher/watch_progress.go | 23 +- .../k8s.io/apiserver/pkg/storage/continue.go | 27 + vendor/k8s.io/apiserver/pkg/storage/errors.go | 20 +- .../apiserver/pkg/storage/errors/storage.go | 2 +- .../k8s.io/apiserver/pkg/storage/etcd3/OWNERS | 3 + .../pkg/storage/etcd3/metrics/metrics.go | 3 +- .../apiserver/pkg/storage/etcd3/store.go | 147 +- .../apiserver/pkg/storage/etcd3/watcher.go | 112 +- .../feature/feature_support_checker.go | 172 + .../apiserver/pkg/storage/interfaces.go | 9 + .../pkg/storage/selection_predicate.go | 22 +- .../pkg/storage/storagebackend/config.go | 3 +- .../storage/storagebackend/factory/etcd3.go | 1 + vendor/k8s.io/apiserver/pkg/storage/util.go | 16 +- .../pkg/util/feature/feature_gate.go | 4 +- .../pkg/util/flowcontrol/apf_controller.go | 99 +- .../flowcontrol/fairqueuing/queueset/doc.go | 2 +- .../fairqueuing/queueset/queueset.go | 27 +- .../request/list_work_estimator.go | 13 +- .../apiserver/pkg/util/version/registry.go | 454 + .../apiserver/pkg/util/version/version.go | 181 + .../apiserver/pkg/util/webhook/client.go | 51 +- .../apiserver/pkg/util/webhook/validation.go | 10 + .../plugin/pkg/authorizer/webhook/metrics.go | 35 - .../pkg/authorizer/webhook/metrics/metrics.go | 166 + .../plugin/pkg/authorizer/webhook/webhook.go | 183 +- .../autoscaling.x-k8s.io/v1beta1/types.go | 16 +- .../genericclioptions/builder_flags_fake.go | 19 +- .../pkg/genericclioptions/record_flags.go | 2 +- .../k8s.io/cli-runtime/pkg/resource/mapper.go | 2 +- .../client-go/applyconfigurations/OWNERS | 5 + .../v1/auditannotation.go | 48 + .../v1/expressionwarning.go | 48 + .../v1/matchcondition.go | 4 +- .../v1/matchresources.go | 90 + .../v1/mutatingwebhook.go | 4 +- .../v1/mutatingwebhookconfiguration.go | 10 +- .../v1/namedrulewithoperations.go | 94 + .../admissionregistration/v1/paramkind.go | 48 + .../admissionregistration/v1/paramref.go | 71 + .../admissionregistration/v1/rule.go | 4 +- .../v1/rulewithoperations.go | 4 +- .../v1/servicereference.go | 4 +- .../admissionregistration/v1/typechecking.go | 44 + .../v1/validatingadmissionpolicy.go | 262 + .../v1/validatingadmissionpolicybinding.go | 253 + .../validatingadmissionpolicybindingspec.go | 72 + .../v1/validatingadmissionpolicyspec.go | 117 + .../v1/validatingadmissionpolicystatus.go | 66 + .../v1/validatingwebhook.go | 4 +- .../v1/validatingwebhookconfiguration.go | 10 +- .../admissionregistration/v1/validation.go | 70 + .../admissionregistration/v1/variable.go | 48 + .../v1/webhookclientconfig.go | 4 +- .../v1alpha1/auditannotation.go | 4 +- .../v1alpha1/expressionwarning.go | 4 +- .../v1alpha1/matchcondition.go | 4 +- .../v1alpha1/matchresources.go | 4 +- .../v1alpha1/namedrulewithoperations.go | 4 +- .../v1alpha1/paramkind.go | 4 +- .../v1alpha1/paramref.go | 4 +- .../v1alpha1/typechecking.go | 4 +- .../v1alpha1/validatingadmissionpolicy.go | 10 +- .../validatingadmissionpolicybinding.go | 10 +- .../validatingadmissionpolicybindingspec.go | 4 +- .../v1alpha1/validatingadmissionpolicyspec.go | 4 +- .../validatingadmissionpolicystatus.go | 4 +- .../v1alpha1/validation.go | 4 +- .../v1alpha1/variable.go | 4 +- .../v1beta1/auditannotation.go | 4 +- .../v1beta1/expressionwarning.go | 4 +- .../v1beta1/matchcondition.go | 4 +- .../v1beta1/matchresources.go | 4 +- .../v1beta1/mutatingwebhook.go | 4 +- .../v1beta1/mutatingwebhookconfiguration.go | 10 +- .../v1beta1/namedrulewithoperations.go | 4 +- .../v1beta1/paramkind.go | 4 +- .../admissionregistration/v1beta1/paramref.go | 4 +- .../v1beta1/servicereference.go | 4 +- .../v1beta1/typechecking.go | 4 +- .../v1beta1/validatingadmissionpolicy.go | 10 +- .../validatingadmissionpolicybinding.go | 10 +- .../validatingadmissionpolicybindingspec.go | 4 +- .../v1beta1/validatingadmissionpolicyspec.go | 4 +- .../validatingadmissionpolicystatus.go | 4 +- .../v1beta1/validatingwebhook.go | 4 +- .../v1beta1/validatingwebhookconfiguration.go | 10 +- .../v1beta1/validation.go | 4 +- .../admissionregistration/v1beta1/variable.go | 4 +- .../v1beta1/webhookclientconfig.go | 4 +- .../v1alpha1/serverstorageversion.go | 4 +- .../v1alpha1/storageversion.go | 10 +- .../v1alpha1/storageversioncondition.go | 4 +- .../v1alpha1/storageversionstatus.go | 4 +- .../apps/v1/controllerrevision.go | 10 +- .../applyconfigurations/apps/v1/daemonset.go | 10 +- .../apps/v1/daemonsetcondition.go | 4 +- .../apps/v1/daemonsetspec.go | 4 +- .../apps/v1/daemonsetstatus.go | 4 +- .../apps/v1/daemonsetupdatestrategy.go | 4 +- .../applyconfigurations/apps/v1/deployment.go | 10 +- .../apps/v1/deploymentcondition.go | 4 +- .../apps/v1/deploymentspec.go | 4 +- .../apps/v1/deploymentstatus.go | 4 +- .../apps/v1/deploymentstrategy.go | 4 +- .../applyconfigurations/apps/v1/replicaset.go | 10 +- .../apps/v1/replicasetcondition.go | 4 +- .../apps/v1/replicasetspec.go | 4 +- .../apps/v1/replicasetstatus.go | 4 +- .../apps/v1/rollingupdatedaemonset.go | 4 +- .../apps/v1/rollingupdatedeployment.go | 4 +- .../v1/rollingupdatestatefulsetstrategy.go | 4 +- .../apps/v1/statefulset.go | 10 +- .../apps/v1/statefulsetcondition.go | 4 +- .../apps/v1/statefulsetordinals.go | 4 +- ...setpersistentvolumeclaimretentionpolicy.go | 4 +- .../apps/v1/statefulsetspec.go | 4 +- .../apps/v1/statefulsetstatus.go | 4 +- .../apps/v1/statefulsetupdatestrategy.go | 4 +- .../apps/v1beta1/controllerrevision.go | 10 +- .../apps/v1beta1/deployment.go | 10 +- .../apps/v1beta1/deploymentcondition.go | 4 +- .../apps/v1beta1/deploymentspec.go | 4 +- .../apps/v1beta1/deploymentstatus.go | 4 +- .../apps/v1beta1/deploymentstrategy.go | 4 +- .../apps/v1beta1/rollbackconfig.go | 4 +- .../apps/v1beta1/rollingupdatedeployment.go | 4 +- .../rollingupdatestatefulsetstrategy.go | 4 +- .../apps/v1beta1/statefulset.go | 10 +- .../apps/v1beta1/statefulsetcondition.go | 4 +- .../apps/v1beta1/statefulsetordinals.go | 4 +- ...setpersistentvolumeclaimretentionpolicy.go | 4 +- .../apps/v1beta1/statefulsetspec.go | 4 +- .../apps/v1beta1/statefulsetstatus.go | 4 +- .../apps/v1beta1/statefulsetupdatestrategy.go | 4 +- .../apps/v1beta2/controllerrevision.go | 10 +- .../apps/v1beta2/daemonset.go | 10 +- .../apps/v1beta2/daemonsetcondition.go | 4 +- .../apps/v1beta2/daemonsetspec.go | 4 +- .../apps/v1beta2/daemonsetstatus.go | 4 +- .../apps/v1beta2/daemonsetupdatestrategy.go | 4 +- .../apps/v1beta2/deployment.go | 10 +- .../apps/v1beta2/deploymentcondition.go | 4 +- .../apps/v1beta2/deploymentspec.go | 4 +- .../apps/v1beta2/deploymentstatus.go | 4 +- .../apps/v1beta2/deploymentstrategy.go | 4 +- .../apps/v1beta2/replicaset.go | 10 +- .../apps/v1beta2/replicasetcondition.go | 4 +- .../apps/v1beta2/replicasetspec.go | 4 +- .../apps/v1beta2/replicasetstatus.go | 4 +- .../apps/v1beta2/rollingupdatedaemonset.go | 4 +- .../apps/v1beta2/rollingupdatedeployment.go | 4 +- .../rollingupdatestatefulsetstrategy.go | 4 +- .../applyconfigurations/apps/v1beta2/scale.go | 10 +- .../apps/v1beta2/statefulset.go | 10 +- .../apps/v1beta2/statefulsetcondition.go | 4 +- .../apps/v1beta2/statefulsetordinals.go | 4 +- ...setpersistentvolumeclaimretentionpolicy.go | 4 +- .../apps/v1beta2/statefulsetspec.go | 4 +- .../apps/v1beta2/statefulsetstatus.go | 4 +- .../apps/v1beta2/statefulsetupdatestrategy.go | 4 +- .../v1/crossversionobjectreference.go | 4 +- .../autoscaling/v1/horizontalpodautoscaler.go | 10 +- .../v1/horizontalpodautoscalerspec.go | 4 +- .../v1/horizontalpodautoscalerstatus.go | 4 +- .../autoscaling/v1/scale.go | 10 +- .../autoscaling/v1/scalespec.go | 4 +- .../autoscaling/v1/scalestatus.go | 4 +- .../v2/containerresourcemetricsource.go | 4 +- .../v2/containerresourcemetricstatus.go | 4 +- .../v2/crossversionobjectreference.go | 4 +- .../autoscaling/v2/externalmetricsource.go | 4 +- .../autoscaling/v2/externalmetricstatus.go | 4 +- .../autoscaling/v2/horizontalpodautoscaler.go | 10 +- .../v2/horizontalpodautoscalerbehavior.go | 4 +- .../v2/horizontalpodautoscalercondition.go | 4 +- .../v2/horizontalpodautoscalerspec.go | 4 +- .../v2/horizontalpodautoscalerstatus.go | 4 +- .../autoscaling/v2/hpascalingpolicy.go | 4 +- .../autoscaling/v2/hpascalingrules.go | 4 +- .../autoscaling/v2/metricidentifier.go | 4 +- .../autoscaling/v2/metricspec.go | 4 +- .../autoscaling/v2/metricstatus.go | 4 +- .../autoscaling/v2/metrictarget.go | 4 +- .../autoscaling/v2/metricvaluestatus.go | 4 +- .../autoscaling/v2/objectmetricsource.go | 4 +- .../autoscaling/v2/objectmetricstatus.go | 4 +- .../autoscaling/v2/podsmetricsource.go | 4 +- .../autoscaling/v2/podsmetricstatus.go | 4 +- .../autoscaling/v2/resourcemetricsource.go | 4 +- .../autoscaling/v2/resourcemetricstatus.go | 4 +- .../v2beta1/containerresourcemetricsource.go | 4 +- .../v2beta1/containerresourcemetricstatus.go | 4 +- .../v2beta1/crossversionobjectreference.go | 4 +- .../v2beta1/externalmetricsource.go | 4 +- .../v2beta1/externalmetricstatus.go | 4 +- .../v2beta1/horizontalpodautoscaler.go | 10 +- .../horizontalpodautoscalercondition.go | 4 +- .../v2beta1/horizontalpodautoscalerspec.go | 4 +- .../v2beta1/horizontalpodautoscalerstatus.go | 4 +- .../autoscaling/v2beta1/metricspec.go | 4 +- .../autoscaling/v2beta1/metricstatus.go | 4 +- .../autoscaling/v2beta1/objectmetricsource.go | 4 +- .../autoscaling/v2beta1/objectmetricstatus.go | 4 +- .../autoscaling/v2beta1/podsmetricsource.go | 4 +- .../autoscaling/v2beta1/podsmetricstatus.go | 4 +- .../v2beta1/resourcemetricsource.go | 4 +- .../v2beta1/resourcemetricstatus.go | 4 +- .../v2beta2/containerresourcemetricsource.go | 4 +- .../v2beta2/containerresourcemetricstatus.go | 4 +- .../v2beta2/crossversionobjectreference.go | 4 +- .../v2beta2/externalmetricsource.go | 4 +- .../v2beta2/externalmetricstatus.go | 4 +- .../v2beta2/horizontalpodautoscaler.go | 10 +- .../horizontalpodautoscalerbehavior.go | 4 +- .../horizontalpodautoscalercondition.go | 4 +- .../v2beta2/horizontalpodautoscalerspec.go | 4 +- .../v2beta2/horizontalpodautoscalerstatus.go | 4 +- .../autoscaling/v2beta2/hpascalingpolicy.go | 4 +- .../autoscaling/v2beta2/hpascalingrules.go | 4 +- .../autoscaling/v2beta2/metricidentifier.go | 4 +- .../autoscaling/v2beta2/metricspec.go | 4 +- .../autoscaling/v2beta2/metricstatus.go | 4 +- .../autoscaling/v2beta2/metrictarget.go | 4 +- .../autoscaling/v2beta2/metricvaluestatus.go | 4 +- .../autoscaling/v2beta2/objectmetricsource.go | 4 +- .../autoscaling/v2beta2/objectmetricstatus.go | 4 +- .../autoscaling/v2beta2/podsmetricsource.go | 4 +- .../autoscaling/v2beta2/podsmetricstatus.go | 4 +- .../v2beta2/resourcemetricsource.go | 4 +- .../v2beta2/resourcemetricstatus.go | 4 +- .../applyconfigurations/batch/v1/cronjob.go | 10 +- .../batch/v1/cronjobspec.go | 4 +- .../batch/v1/cronjobstatus.go | 4 +- .../applyconfigurations/batch/v1/job.go | 10 +- .../batch/v1/jobcondition.go | 4 +- .../applyconfigurations/batch/v1/jobspec.go | 22 +- .../applyconfigurations/batch/v1/jobstatus.go | 4 +- .../batch/v1/jobtemplatespec.go | 10 +- .../batch/v1/podfailurepolicy.go | 4 +- .../podfailurepolicyonexitcodesrequirement.go | 4 +- .../podfailurepolicyonpodconditionspattern.go | 4 +- .../batch/v1/podfailurepolicyrule.go | 4 +- .../batch/v1/successpolicy.go | 44 + .../batch/v1/successpolicyrule.go | 48 + .../batch/v1/uncountedterminatedpods.go | 4 +- .../batch/v1beta1/cronjob.go | 10 +- .../batch/v1beta1/cronjobspec.go | 4 +- .../batch/v1beta1/cronjobstatus.go | 4 +- .../batch/v1beta1/jobtemplatespec.go | 10 +- .../v1/certificatesigningrequest.go | 10 +- .../v1/certificatesigningrequestcondition.go | 4 +- .../v1/certificatesigningrequestspec.go | 4 +- .../v1/certificatesigningrequeststatus.go | 4 +- .../v1alpha1/clustertrustbundle.go | 10 +- .../v1alpha1/clustertrustbundlespec.go | 4 +- .../v1beta1/certificatesigningrequest.go | 10 +- .../certificatesigningrequestcondition.go | 4 +- .../v1beta1/certificatesigningrequestspec.go | 4 +- .../certificatesigningrequeststatus.go | 4 +- .../coordination/v1/lease.go | 10 +- .../coordination/v1/leasespec.go | 33 +- .../coordination/v1alpha1/leasecandidate.go | 255 + .../v1alpha1/leasecandidatespec.go | 91 + .../coordination/v1beta1/lease.go | 10 +- .../coordination/v1beta1/leasespec.go | 33 +- .../applyconfigurations/core/v1/affinity.go | 4 +- .../core/v1/apparmorprofile.go | 52 + .../core/v1/attachedvolume.go | 4 +- .../v1/awselasticblockstorevolumesource.go | 4 +- .../core/v1/azurediskvolumesource.go | 4 +- .../v1/azurefilepersistentvolumesource.go | 4 +- .../core/v1/azurefilevolumesource.go | 4 +- .../core/v1/capabilities.go | 4 +- .../core/v1/cephfspersistentvolumesource.go | 4 +- .../core/v1/cephfsvolumesource.go | 4 +- .../core/v1/cinderpersistentvolumesource.go | 4 +- .../core/v1/cindervolumesource.go | 4 +- .../core/v1/claimsource.go | 48 - .../core/v1/clientipconfig.go | 4 +- .../core/v1/clustertrustbundleprojection.go | 4 +- .../core/v1/componentcondition.go | 4 +- .../core/v1/componentstatus.go | 10 +- .../applyconfigurations/core/v1/configmap.go | 10 +- .../core/v1/configmapenvsource.go | 4 +- .../core/v1/configmapkeyselector.go | 4 +- .../core/v1/configmapnodeconfigsource.go | 4 +- .../core/v1/configmapprojection.go | 4 +- .../core/v1/configmapvolumesource.go | 4 +- .../applyconfigurations/core/v1/container.go | 4 +- .../core/v1/containerimage.go | 4 +- .../core/v1/containerport.go | 4 +- .../core/v1/containerresizepolicy.go | 4 +- .../core/v1/containerstate.go | 4 +- .../core/v1/containerstaterunning.go | 4 +- .../core/v1/containerstateterminated.go | 4 +- .../core/v1/containerstatewaiting.go | 4 +- .../core/v1/containerstatus.go | 67 +- .../core/v1/containeruser.go | 39 + .../core/v1/csipersistentvolumesource.go | 4 +- .../core/v1/csivolumesource.go | 4 +- .../core/v1/daemonendpoint.go | 4 +- .../core/v1/downwardapiprojection.go | 4 +- .../core/v1/downwardapivolumefile.go | 4 +- .../core/v1/downwardapivolumesource.go | 4 +- .../core/v1/emptydirvolumesource.go | 4 +- .../core/v1/endpointaddress.go | 4 +- .../core/v1/endpointport.go | 4 +- .../applyconfigurations/core/v1/endpoints.go | 10 +- .../core/v1/endpointsubset.go | 4 +- .../core/v1/envfromsource.go | 4 +- .../applyconfigurations/core/v1/envvar.go | 4 +- .../core/v1/envvarsource.go | 4 +- .../core/v1/ephemeralcontainer.go | 4 +- .../core/v1/ephemeralcontainercommon.go | 4 +- .../core/v1/ephemeralvolumesource.go | 4 +- .../applyconfigurations/core/v1/event.go | 10 +- .../core/v1/eventseries.go | 4 +- .../core/v1/eventsource.go | 4 +- .../applyconfigurations/core/v1/execaction.go | 4 +- .../core/v1/fcvolumesource.go | 4 +- .../core/v1/flexpersistentvolumesource.go | 4 +- .../core/v1/flexvolumesource.go | 4 +- .../core/v1/flockervolumesource.go | 4 +- .../core/v1/gcepersistentdiskvolumesource.go | 4 +- .../core/v1/gitrepovolumesource.go | 4 +- .../v1/glusterfspersistentvolumesource.go | 4 +- .../core/v1/glusterfsvolumesource.go | 4 +- .../applyconfigurations/core/v1/grpcaction.go | 4 +- .../applyconfigurations/core/v1/hostalias.go | 4 +- .../applyconfigurations/core/v1/hostip.go | 4 +- .../core/v1/hostpathvolumesource.go | 4 +- .../core/v1/httpgetaction.go | 4 +- .../applyconfigurations/core/v1/httpheader.go | 4 +- .../core/v1/imagevolumesource.go | 52 + .../core/v1/iscsipersistentvolumesource.go | 4 +- .../core/v1/iscsivolumesource.go | 4 +- .../applyconfigurations/core/v1/keytopath.go | 4 +- .../applyconfigurations/core/v1/lifecycle.go | 4 +- .../core/v1/lifecyclehandler.go | 4 +- .../applyconfigurations/core/v1/limitrange.go | 10 +- .../core/v1/limitrangeitem.go | 4 +- .../core/v1/limitrangespec.go | 4 +- .../core/v1/linuxcontaineruser.go | 59 + .../core/v1/loadbalanceringress.go | 4 +- .../core/v1/loadbalancerstatus.go | 4 +- .../core/v1/localobjectreference.go | 4 +- .../core/v1/localvolumesource.go | 4 +- .../core/v1/modifyvolumestatus.go | 4 +- .../applyconfigurations/core/v1/namespace.go | 10 +- .../core/v1/namespacecondition.go | 4 +- .../core/v1/namespacespec.go | 4 +- .../core/v1/namespacestatus.go | 4 +- .../core/v1/nfsvolumesource.go | 4 +- .../applyconfigurations/core/v1/node.go | 10 +- .../core/v1/nodeaddress.go | 4 +- .../core/v1/nodeaffinity.go | 4 +- .../core/v1/nodecondition.go | 4 +- .../core/v1/nodeconfigsource.go | 4 +- .../core/v1/nodeconfigstatus.go | 4 +- .../core/v1/nodedaemonendpoints.go | 4 +- .../core/v1/nodefeatures.go | 39 + .../core/v1/noderuntimehandler.go | 48 + .../core/v1/noderuntimehandlerfeatures.go | 48 + .../core/v1/nodeselector.go | 4 +- .../core/v1/nodeselectorrequirement.go | 4 +- .../core/v1/nodeselectorterm.go | 4 +- .../applyconfigurations/core/v1/nodespec.go | 4 +- .../applyconfigurations/core/v1/nodestatus.go | 27 +- .../core/v1/nodesysteminfo.go | 4 +- .../core/v1/objectfieldselector.go | 4 +- .../core/v1/objectreference.go | 4 +- .../core/v1/persistentvolume.go | 10 +- .../core/v1/persistentvolumeclaim.go | 10 +- .../core/v1/persistentvolumeclaimcondition.go | 4 +- .../core/v1/persistentvolumeclaimspec.go | 4 +- .../core/v1/persistentvolumeclaimstatus.go | 4 +- .../core/v1/persistentvolumeclaimtemplate.go | 10 +- .../v1/persistentvolumeclaimvolumesource.go | 4 +- .../core/v1/persistentvolumesource.go | 4 +- .../core/v1/persistentvolumespec.go | 4 +- .../core/v1/persistentvolumestatus.go | 4 +- .../v1/photonpersistentdiskvolumesource.go | 4 +- .../applyconfigurations/core/v1/pod.go | 10 +- .../core/v1/podaffinity.go | 4 +- .../core/v1/podaffinityterm.go | 4 +- .../core/v1/podantiaffinity.go | 4 +- .../core/v1/podcondition.go | 4 +- .../core/v1/poddnsconfig.go | 4 +- .../core/v1/poddnsconfigoption.go | 4 +- .../applyconfigurations/core/v1/podip.go | 4 +- .../applyconfigurations/core/v1/podos.go | 4 +- .../core/v1/podreadinessgate.go | 4 +- .../core/v1/podresourceclaim.go | 25 +- .../core/v1/podresourceclaimstatus.go | 4 +- .../core/v1/podschedulinggate.go | 4 +- .../core/v1/podsecuritycontext.go | 42 +- .../applyconfigurations/core/v1/podspec.go | 4 +- .../applyconfigurations/core/v1/podstatus.go | 4 +- .../core/v1/podtemplate.go | 10 +- .../core/v1/podtemplatespec.go | 10 +- .../applyconfigurations/core/v1/portstatus.go | 4 +- .../core/v1/portworxvolumesource.go | 4 +- .../core/v1/preferredschedulingterm.go | 4 +- .../applyconfigurations/core/v1/probe.go | 4 +- .../core/v1/probehandler.go | 4 +- .../core/v1/projectedvolumesource.go | 4 +- .../core/v1/quobytevolumesource.go | 4 +- .../core/v1/rbdpersistentvolumesource.go | 4 +- .../core/v1/rbdvolumesource.go | 4 +- .../core/v1/replicationcontroller.go | 10 +- .../core/v1/replicationcontrollercondition.go | 4 +- .../core/v1/replicationcontrollerspec.go | 4 +- .../core/v1/replicationcontrollerstatus.go | 4 +- .../core/v1/resourceclaim.go | 15 +- .../core/v1/resourcefieldselector.go | 4 +- .../core/v1/resourcehealth.go | 52 + .../core/v1/resourcequota.go | 10 +- .../core/v1/resourcequotaspec.go | 4 +- .../core/v1/resourcequotastatus.go | 4 +- .../core/v1/resourcerequirements.go | 4 +- .../core/v1/resourcestatus.go | 57 + .../core/v1/scaleiopersistentvolumesource.go | 4 +- .../core/v1/scaleiovolumesource.go | 4 +- .../v1/scopedresourceselectorrequirement.go | 4 +- .../core/v1/scopeselector.go | 4 +- .../core/v1/seccompprofile.go | 4 +- .../applyconfigurations/core/v1/secret.go | 10 +- .../core/v1/secretenvsource.go | 4 +- .../core/v1/secretkeyselector.go | 4 +- .../core/v1/secretprojection.go | 4 +- .../core/v1/secretreference.go | 4 +- .../core/v1/secretvolumesource.go | 4 +- .../core/v1/securitycontext.go | 13 +- .../core/v1/selinuxoptions.go | 4 +- .../applyconfigurations/core/v1/service.go | 10 +- .../core/v1/serviceaccount.go | 10 +- .../core/v1/serviceaccounttokenprojection.go | 4 +- .../core/v1/serviceport.go | 4 +- .../core/v1/servicespec.go | 13 +- .../core/v1/servicestatus.go | 4 +- .../core/v1/sessionaffinityconfig.go | 4 +- .../core/v1/sleepaction.go | 4 +- .../v1/storageospersistentvolumesource.go | 4 +- .../core/v1/storageosvolumesource.go | 4 +- .../applyconfigurations/core/v1/sysctl.go | 4 +- .../applyconfigurations/core/v1/taint.go | 4 +- .../core/v1/tcpsocketaction.go | 4 +- .../applyconfigurations/core/v1/toleration.go | 4 +- .../v1/topologyselectorlabelrequirement.go | 4 +- .../core/v1/topologyselectorterm.go | 4 +- .../core/v1/topologyspreadconstraint.go | 4 +- .../core/v1/typedlocalobjectreference.go | 4 +- .../core/v1/typedobjectreference.go | 4 +- .../applyconfigurations/core/v1/volume.go | 12 +- .../core/v1/volumedevice.go | 4 +- .../core/v1/volumemount.go | 25 +- .../core/v1/volumemountstatus.go | 70 + .../core/v1/volumenodeaffinity.go | 4 +- .../core/v1/volumeprojection.go | 4 +- .../core/v1/volumeresourcerequirements.go | 4 +- .../core/v1/volumesource.go | 13 +- .../core/v1/vspherevirtualdiskvolumesource.go | 4 +- .../core/v1/weightedpodaffinityterm.go | 4 +- .../core/v1/windowssecuritycontextoptions.go | 4 +- .../discovery/v1/endpoint.go | 4 +- .../discovery/v1/endpointconditions.go | 4 +- .../discovery/v1/endpointhints.go | 4 +- .../discovery/v1/endpointport.go | 4 +- .../discovery/v1/endpointslice.go | 10 +- .../discovery/v1/forzone.go | 4 +- .../discovery/v1beta1/endpoint.go | 4 +- .../discovery/v1beta1/endpointconditions.go | 4 +- .../discovery/v1beta1/endpointhints.go | 4 +- .../discovery/v1beta1/endpointport.go | 4 +- .../discovery/v1beta1/endpointslice.go | 10 +- .../discovery/v1beta1/forzone.go | 4 +- .../client-go/applyconfigurations/doc.go | 151 + .../applyconfigurations/events/v1/event.go | 10 +- .../events/v1/eventseries.go | 4 +- .../events/v1beta1/event.go | 10 +- .../events/v1beta1/eventseries.go | 4 +- .../extensions/v1beta1/daemonset.go | 10 +- .../extensions/v1beta1/daemonsetcondition.go | 4 +- .../extensions/v1beta1/daemonsetspec.go | 4 +- .../extensions/v1beta1/daemonsetstatus.go | 4 +- .../v1beta1/daemonsetupdatestrategy.go | 4 +- .../extensions/v1beta1/deployment.go | 10 +- .../extensions/v1beta1/deploymentcondition.go | 4 +- .../extensions/v1beta1/deploymentspec.go | 4 +- .../extensions/v1beta1/deploymentstatus.go | 4 +- .../extensions/v1beta1/deploymentstrategy.go | 4 +- .../extensions/v1beta1/httpingresspath.go | 4 +- .../v1beta1/httpingressrulevalue.go | 4 +- .../extensions/v1beta1/ingress.go | 10 +- .../extensions/v1beta1/ingressbackend.go | 4 +- .../v1beta1/ingressloadbalanceringress.go | 4 +- .../v1beta1/ingressloadbalancerstatus.go | 4 +- .../extensions/v1beta1/ingressportstatus.go | 4 +- .../extensions/v1beta1/ingressrule.go | 6 +- .../extensions/v1beta1/ingressrulevalue.go | 4 +- .../extensions/v1beta1/ingressspec.go | 4 +- .../extensions/v1beta1/ingressstatus.go | 4 +- .../extensions/v1beta1/ingresstls.go | 4 +- .../extensions/v1beta1/ipblock.go | 4 +- .../extensions/v1beta1/networkpolicy.go | 10 +- .../v1beta1/networkpolicyegressrule.go | 4 +- .../v1beta1/networkpolicyingressrule.go | 4 +- .../extensions/v1beta1/networkpolicypeer.go | 4 +- .../extensions/v1beta1/networkpolicyport.go | 4 +- .../extensions/v1beta1/networkpolicyspec.go | 4 +- .../extensions/v1beta1/replicaset.go | 10 +- .../extensions/v1beta1/replicasetcondition.go | 4 +- .../extensions/v1beta1/replicasetspec.go | 4 +- .../extensions/v1beta1/replicasetstatus.go | 4 +- .../extensions/v1beta1/rollbackconfig.go | 4 +- .../v1beta1/rollingupdatedaemonset.go | 4 +- .../v1beta1/rollingupdatedeployment.go | 4 +- .../extensions/v1beta1/scale.go | 10 +- .../v1/exemptprioritylevelconfiguration.go | 4 +- .../flowcontrol/v1/flowdistinguishermethod.go | 4 +- .../flowcontrol/v1/flowschema.go | 10 +- .../flowcontrol/v1/flowschemacondition.go | 4 +- .../flowcontrol/v1/flowschemaspec.go | 4 +- .../flowcontrol/v1/flowschemastatus.go | 4 +- .../flowcontrol/v1/groupsubject.go | 4 +- .../v1/limitedprioritylevelconfiguration.go | 4 +- .../flowcontrol/v1/limitresponse.go | 4 +- .../flowcontrol/v1/nonresourcepolicyrule.go | 4 +- .../flowcontrol/v1/policyruleswithsubjects.go | 4 +- .../v1/prioritylevelconfiguration.go | 10 +- .../v1/prioritylevelconfigurationcondition.go | 4 +- .../v1/prioritylevelconfigurationreference.go | 4 +- .../v1/prioritylevelconfigurationspec.go | 4 +- .../v1/prioritylevelconfigurationstatus.go | 4 +- .../flowcontrol/v1/queuingconfiguration.go | 4 +- .../flowcontrol/v1/resourcepolicyrule.go | 4 +- .../flowcontrol/v1/serviceaccountsubject.go | 4 +- .../flowcontrol/v1/subject.go | 4 +- .../flowcontrol/v1/usersubject.go | 4 +- .../exemptprioritylevelconfiguration.go | 4 +- .../v1beta1/flowdistinguishermethod.go | 4 +- .../flowcontrol/v1beta1/flowschema.go | 10 +- .../v1beta1/flowschemacondition.go | 4 +- .../flowcontrol/v1beta1/flowschemaspec.go | 4 +- .../flowcontrol/v1beta1/flowschemastatus.go | 4 +- .../flowcontrol/v1beta1/groupsubject.go | 4 +- .../limitedprioritylevelconfiguration.go | 4 +- .../flowcontrol/v1beta1/limitresponse.go | 4 +- .../v1beta1/nonresourcepolicyrule.go | 4 +- .../v1beta1/policyruleswithsubjects.go | 4 +- .../v1beta1/prioritylevelconfiguration.go | 10 +- .../prioritylevelconfigurationcondition.go | 4 +- .../prioritylevelconfigurationreference.go | 4 +- .../v1beta1/prioritylevelconfigurationspec.go | 4 +- .../prioritylevelconfigurationstatus.go | 4 +- .../v1beta1/queuingconfiguration.go | 4 +- .../flowcontrol/v1beta1/resourcepolicyrule.go | 4 +- .../v1beta1/serviceaccountsubject.go | 4 +- .../flowcontrol/v1beta1/subject.go | 4 +- .../flowcontrol/v1beta1/usersubject.go | 4 +- .../exemptprioritylevelconfiguration.go | 4 +- .../v1beta2/flowdistinguishermethod.go | 4 +- .../flowcontrol/v1beta2/flowschema.go | 10 +- .../v1beta2/flowschemacondition.go | 4 +- .../flowcontrol/v1beta2/flowschemaspec.go | 4 +- .../flowcontrol/v1beta2/flowschemastatus.go | 4 +- .../flowcontrol/v1beta2/groupsubject.go | 4 +- .../limitedprioritylevelconfiguration.go | 4 +- .../flowcontrol/v1beta2/limitresponse.go | 4 +- .../v1beta2/nonresourcepolicyrule.go | 4 +- .../v1beta2/policyruleswithsubjects.go | 4 +- .../v1beta2/prioritylevelconfiguration.go | 10 +- .../prioritylevelconfigurationcondition.go | 4 +- .../prioritylevelconfigurationreference.go | 4 +- .../v1beta2/prioritylevelconfigurationspec.go | 4 +- .../prioritylevelconfigurationstatus.go | 4 +- .../v1beta2/queuingconfiguration.go | 4 +- .../flowcontrol/v1beta2/resourcepolicyrule.go | 4 +- .../v1beta2/serviceaccountsubject.go | 4 +- .../flowcontrol/v1beta2/subject.go | 4 +- .../flowcontrol/v1beta2/usersubject.go | 4 +- .../exemptprioritylevelconfiguration.go | 4 +- .../v1beta3/flowdistinguishermethod.go | 4 +- .../flowcontrol/v1beta3/flowschema.go | 10 +- .../v1beta3/flowschemacondition.go | 4 +- .../flowcontrol/v1beta3/flowschemaspec.go | 4 +- .../flowcontrol/v1beta3/flowschemastatus.go | 4 +- .../flowcontrol/v1beta3/groupsubject.go | 4 +- .../limitedprioritylevelconfiguration.go | 4 +- .../flowcontrol/v1beta3/limitresponse.go | 4 +- .../v1beta3/nonresourcepolicyrule.go | 4 +- .../v1beta3/policyruleswithsubjects.go | 4 +- .../v1beta3/prioritylevelconfiguration.go | 10 +- .../prioritylevelconfigurationcondition.go | 4 +- .../prioritylevelconfigurationreference.go | 4 +- .../v1beta3/prioritylevelconfigurationspec.go | 4 +- .../prioritylevelconfigurationstatus.go | 4 +- .../v1beta3/queuingconfiguration.go | 4 +- .../flowcontrol/v1beta3/resourcepolicyrule.go | 4 +- .../v1beta3/serviceaccountsubject.go | 4 +- .../flowcontrol/v1beta3/subject.go | 4 +- .../flowcontrol/v1beta3/usersubject.go | 4 +- .../imagepolicy/v1alpha1/imagereview.go | 262 + .../v1alpha1/imagereviewcontainerspec.go | 39 + .../imagepolicy/v1alpha1/imagereviewspec.go | 68 + .../imagepolicy/v1alpha1/imagereviewstatus.go | 63 + .../applyconfigurations/internal/internal.go | 1136 ++- .../applyconfigurations/meta/v1/condition.go | 4 +- .../meta/v1/deleteoptions.go | 4 +- .../meta/v1/labelselector.go | 4 +- .../meta/v1/labelselectorrequirement.go | 4 +- .../meta/v1/managedfieldsentry.go | 4 +- .../applyconfigurations/meta/v1/objectmeta.go | 9 +- .../meta/v1/ownerreference.go | 4 +- .../meta/v1/preconditions.go | 4 +- .../applyconfigurations/meta/v1/typemeta.go | 4 +- .../networking/v1/httpingresspath.go | 4 +- .../networking/v1/httpingressrulevalue.go | 4 +- .../networking/v1/ingress.go | 10 +- .../networking/v1/ingressbackend.go | 4 +- .../networking/v1/ingressclass.go | 10 +- .../v1/ingressclassparametersreference.go | 4 +- .../networking/v1/ingressclassspec.go | 4 +- .../v1/ingressloadbalanceringress.go | 4 +- .../v1/ingressloadbalancerstatus.go | 4 +- .../networking/v1/ingressportstatus.go | 4 +- .../networking/v1/ingressrule.go | 6 +- .../networking/v1/ingressrulevalue.go | 4 +- .../networking/v1/ingressservicebackend.go | 4 +- .../networking/v1/ingressspec.go | 4 +- .../networking/v1/ingressstatus.go | 4 +- .../networking/v1/ingresstls.go | 4 +- .../networking/v1/ipblock.go | 4 +- .../networking/v1/networkpolicy.go | 10 +- .../networking/v1/networkpolicyegressrule.go | 4 +- .../networking/v1/networkpolicyingressrule.go | 4 +- .../networking/v1/networkpolicypeer.go | 4 +- .../networking/v1/networkpolicyport.go | 4 +- .../networking/v1/networkpolicyspec.go | 4 +- .../networking/v1/servicebackendport.go | 4 +- .../networking/v1alpha1/ipaddress.go | 10 +- .../networking/v1alpha1/ipaddressspec.go | 4 +- .../networking/v1alpha1/parentreference.go | 4 +- .../networking/v1alpha1/servicecidr.go | 10 +- .../networking/v1alpha1/servicecidrspec.go | 4 +- .../networking/v1alpha1/servicecidrstatus.go | 4 +- .../networking/v1beta1/httpingresspath.go | 4 +- .../v1beta1/httpingressrulevalue.go | 4 +- .../networking/v1beta1/ingress.go | 10 +- .../networking/v1beta1/ingressbackend.go | 4 +- .../networking/v1beta1/ingressclass.go | 10 +- .../ingressclassparametersreference.go | 4 +- .../networking/v1beta1/ingressclassspec.go | 4 +- .../v1beta1/ingressloadbalanceringress.go | 4 +- .../v1beta1/ingressloadbalancerstatus.go | 4 +- .../networking/v1beta1/ingressportstatus.go | 4 +- .../networking/v1beta1/ingressrule.go | 6 +- .../networking/v1beta1/ingressrulevalue.go | 4 +- .../networking/v1beta1/ingressspec.go | 4 +- .../networking/v1beta1/ingressstatus.go | 4 +- .../networking/v1beta1/ingresstls.go | 4 +- .../networking/v1beta1/ipaddress.go | 253 + .../networking/v1beta1/ipaddressspec.go | 39 + .../v1beta1/parentreference.go} | 50 +- .../networking/v1beta1/servicecidr.go | 262 + .../networking/v1beta1/servicecidrspec.go | 41 + .../networking/v1beta1/servicecidrstatus.go | 48 + .../applyconfigurations/node/v1/overhead.go | 4 +- .../node/v1/runtimeclass.go | 10 +- .../applyconfigurations/node/v1/scheduling.go | 4 +- .../node/v1alpha1/overhead.go | 4 +- .../node/v1alpha1/runtimeclass.go | 10 +- .../node/v1alpha1/runtimeclassspec.go | 4 +- .../node/v1alpha1/scheduling.go | 4 +- .../node/v1beta1/overhead.go | 4 +- .../node/v1beta1/runtimeclass.go | 10 +- .../node/v1beta1/scheduling.go | 4 +- .../applyconfigurations/policy/v1/eviction.go | 10 +- .../policy/v1/poddisruptionbudget.go | 10 +- .../policy/v1/poddisruptionbudgetspec.go | 4 +- .../policy/v1/poddisruptionbudgetstatus.go | 4 +- .../policy/v1beta1/eviction.go | 10 +- .../policy/v1beta1/poddisruptionbudget.go | 10 +- .../policy/v1beta1/poddisruptionbudgetspec.go | 4 +- .../v1beta1/poddisruptionbudgetstatus.go | 4 +- .../rbac/v1/aggregationrule.go | 4 +- .../rbac/v1/clusterrole.go | 10 +- .../rbac/v1/clusterrolebinding.go | 10 +- .../applyconfigurations/rbac/v1/policyrule.go | 4 +- .../applyconfigurations/rbac/v1/role.go | 10 +- .../rbac/v1/rolebinding.go | 10 +- .../applyconfigurations/rbac/v1/roleref.go | 4 +- .../applyconfigurations/rbac/v1/subject.go | 4 +- .../rbac/v1alpha1/aggregationrule.go | 4 +- .../rbac/v1alpha1/clusterrole.go | 10 +- .../rbac/v1alpha1/clusterrolebinding.go | 10 +- .../rbac/v1alpha1/policyrule.go | 4 +- .../applyconfigurations/rbac/v1alpha1/role.go | 10 +- .../rbac/v1alpha1/rolebinding.go | 10 +- .../rbac/v1alpha1/roleref.go | 4 +- .../rbac/v1alpha1/subject.go | 4 +- .../rbac/v1beta1/aggregationrule.go | 4 +- .../rbac/v1beta1/clusterrole.go | 10 +- .../rbac/v1beta1/clusterrolebinding.go | 10 +- .../rbac/v1beta1/policyrule.go | 4 +- .../applyconfigurations/rbac/v1beta1/role.go | 10 +- .../rbac/v1beta1/rolebinding.go | 10 +- .../rbac/v1beta1/roleref.go | 4 +- .../rbac/v1beta1/subject.go | 4 +- .../resource/v1alpha2/allocationresult.go | 66 - .../resourceclaimparametersreference.go | 57 - .../resource/v1alpha2/resourceclaimspec.go | 61 - .../resource/v1alpha2/resourcehandle.go | 48 - .../resource/v1alpha3/allocationresult.go | 61 + .../resource/v1alpha3/basicdevice.go | 65 + .../resource/v1alpha3/celdeviceselector.go | 39 + .../resource/v1alpha3/device.go | 48 + .../v1alpha3/deviceallocationconfiguration.go | 63 + .../v1alpha3/deviceallocationresult.go | 58 + .../resource/v1alpha3/deviceattribute.go | 66 + .../resource/v1alpha3/deviceclaim.go | 72 + .../v1alpha3/deviceclaimconfiguration.go | 50 + .../resource/v1alpha3/deviceclass.go | 253 + .../v1alpha3/deviceclassconfiguration.go | 39 + .../resource/v1alpha3/deviceclassspec.go | 71 + .../resource/v1alpha3/deviceconfiguration.go | 39 + .../resource/v1alpha3/deviceconstraint.go | 54 + .../resource/v1alpha3/devicerequest.go | 93 + .../v1alpha3/devicerequestallocationresult.go | 66 + .../resource/v1alpha3/deviceselector.go | 39 + .../v1alpha3/opaquedeviceconfiguration.go | 52 + .../podschedulingcontext.go | 26 +- .../podschedulingcontextspec.go | 6 +- .../podschedulingcontextstatus.go | 6 +- .../{v1alpha2 => v1alpha3}/resourceclaim.go | 26 +- .../resourceclaimconsumerreference.go | 6 +- .../resourceclaimschedulingstatus.go | 6 +- .../resource/v1alpha3/resourceclaimspec.go | 48 + .../resourceclaimstatus.go | 15 +- .../resourceclaimtemplate.go | 26 +- .../resourceclaimtemplatespec.go | 12 +- .../resource/v1alpha3/resourcepool.go | 57 + .../resourceslice.go} | 113 +- .../resource/v1alpha3/resourceslicespec.go | 93 + .../scheduling/v1/priorityclass.go | 10 +- .../scheduling/v1alpha1/priorityclass.go | 10 +- .../scheduling/v1beta1/priorityclass.go | 10 +- .../storage/v1/csidriver.go | 10 +- .../storage/v1/csidriverspec.go | 4 +- .../applyconfigurations/storage/v1/csinode.go | 10 +- .../storage/v1/csinodedriver.go | 4 +- .../storage/v1/csinodespec.go | 4 +- .../storage/v1/csistoragecapacity.go | 10 +- .../storage/v1/storageclass.go | 10 +- .../storage/v1/tokenrequest.go | 4 +- .../storage/v1/volumeattachment.go | 10 +- .../storage/v1/volumeattachmentsource.go | 4 +- .../storage/v1/volumeattachmentspec.go | 4 +- .../storage/v1/volumeattachmentstatus.go | 4 +- .../storage/v1/volumeerror.go | 4 +- .../storage/v1/volumenoderesources.go | 4 +- .../storage/v1alpha1/csistoragecapacity.go | 10 +- .../storage/v1alpha1/volumeattachment.go | 10 +- .../v1alpha1/volumeattachmentsource.go | 4 +- .../storage/v1alpha1/volumeattachmentspec.go | 4 +- .../v1alpha1/volumeattachmentstatus.go | 4 +- .../storage/v1alpha1/volumeattributesclass.go | 10 +- .../storage/v1alpha1/volumeerror.go | 4 +- .../storage/v1beta1/csidriver.go | 10 +- .../storage/v1beta1/csidriverspec.go | 4 +- .../storage/v1beta1/csinode.go | 10 +- .../storage/v1beta1/csinodedriver.go | 4 +- .../storage/v1beta1/csinodespec.go | 4 +- .../storage/v1beta1/csistoragecapacity.go | 10 +- .../storage/v1beta1/storageclass.go | 10 +- .../storage/v1beta1/tokenrequest.go | 4 +- .../storage/v1beta1/volumeattachment.go | 10 +- .../storage/v1beta1/volumeattachmentsource.go | 4 +- .../storage/v1beta1/volumeattachmentspec.go | 4 +- .../storage/v1beta1/volumeattachmentstatus.go | 4 +- .../storage/v1beta1/volumeattributesclass.go | 268 + .../storage/v1beta1/volumeerror.go | 4 +- .../storage/v1beta1/volumenoderesources.go | 4 +- .../v1alpha1/groupversionresource.go | 57 + .../v1alpha1/migrationcondition.go | 81 + .../v1alpha1/storageversionmigration.go | 262 + .../v1alpha1/storageversionmigrationspec.go | 48 + .../v1alpha1/storageversionmigrationstatus.go | 53 + .../client-go/applyconfigurations/utils.go | 1740 ++++ .../discovery/aggregated_discovery.go | 124 +- .../client-go/discovery/discovery_client.go | 29 +- .../client-go/discovery/fake/discovery.go | 12 +- .../k8s.io/client-go/dynamic/fake/simple.go | 539 + vendor/k8s.io/client-go/dynamic/simple.go | 43 + vendor/k8s.io/client-go/features/envvar.go | 188 + vendor/k8s.io/client-go/features/features.go | 143 + .../client-go/features/known_features.go | 54 + vendor/k8s.io/client-go/gentype/type.go | 360 + .../admissionregistration/v1/interface.go | 14 + .../v1/validatingadmissionpolicy.go | 89 + .../v1/validatingadmissionpolicybinding.go | 89 + .../informers/coordination/interface.go | 8 + .../coordination/v1alpha1/interface.go | 45 + .../coordination/v1alpha1/leasecandidate.go | 90 + vendor/k8s.io/client-go/informers/doc.go | 2 +- vendor/k8s.io/client-go/informers/factory.go | 7 + vendor/k8s.io/client-go/informers/generic.go | 42 +- .../informers/networking/v1beta1/interface.go | 14 + .../informers/networking/v1beta1/ipaddress.go | 89 + .../networking/v1beta1/servicecidr.go | 89 + .../client-go/informers/resource/interface.go | 12 +- .../resource/v1alpha3/deviceclass.go | 89 + .../{v1alpha2 => v1alpha3}/interface.go | 19 +- .../podschedulingcontext.go | 20 +- .../{v1alpha2 => v1alpha3}/resourceclaim.go | 20 +- .../resourceclaimtemplate.go | 20 +- .../resourceslice.go} | 44 +- .../informers/storage/v1beta1/interface.go | 7 + .../storage/v1beta1/volumeattributesclass.go | 89 + .../informers/storagemigration/interface.go | 46 + .../storagemigration/v1alpha1/interface.go | 45 + .../v1alpha1/storageversionmigration.go | 89 + .../k8s.io/client-go/kubernetes/clientset.go | 42 +- vendor/k8s.io/client-go/kubernetes/doc.go | 2 +- .../kubernetes/fake/clientset_generated.go | 63 +- .../client-go/kubernetes/fake/register.go | 8 +- .../client-go/kubernetes/scheme/register.go | 8 +- .../v1/admissionregistration_client.go | 10 + .../fake/fake_admissionregistration_client.go | 8 + .../fake/fake_mutatingwebhookconfiguration.go | 34 +- .../v1/fake/fake_validatingadmissionpolicy.go | 186 + .../fake_validatingadmissionpolicybinding.go | 151 + .../fake_validatingwebhookconfiguration.go | 34 +- .../v1/generated_expansion.go | 4 + .../v1/mutatingwebhookconfiguration.go | 146 +- .../v1/validatingadmissionpolicy.go | 73 + .../v1/validatingadmissionpolicybinding.go | 69 + .../v1/validatingwebhookconfiguration.go | 146 +- .../fake/fake_validatingadmissionpolicy.go | 46 +- .../fake_validatingadmissionpolicybinding.go | 34 +- .../v1alpha1/validatingadmissionpolicy.go | 192 +- .../validatingadmissionpolicybinding.go | 148 +- .../fake/fake_mutatingwebhookconfiguration.go | 34 +- .../fake/fake_validatingadmissionpolicy.go | 46 +- .../fake_validatingadmissionpolicybinding.go | 34 +- .../fake_validatingwebhookconfiguration.go | 34 +- .../v1beta1/mutatingwebhookconfiguration.go | 146 +- .../v1beta1/validatingadmissionpolicy.go | 192 +- .../validatingadmissionpolicybinding.go | 148 +- .../v1beta1/validatingwebhookconfiguration.go | 148 +- .../v1alpha1/fake/fake_storageversion.go | 46 +- .../v1alpha1/storageversion.go | 192 +- .../typed/apps/v1/controllerrevision.go | 157 +- .../kubernetes/typed/apps/v1/daemonset.go | 205 +- .../kubernetes/typed/apps/v1/deployment.go | 215 +- .../apps/v1/fake/fake_controllerrevision.go | 34 +- .../typed/apps/v1/fake/fake_daemonset.go | 46 +- .../typed/apps/v1/fake/fake_deployment.go | 61 +- .../typed/apps/v1/fake/fake_replicaset.go | 61 +- .../typed/apps/v1/fake/fake_statefulset.go | 61 +- .../kubernetes/typed/apps/v1/replicaset.go | 215 +- .../kubernetes/typed/apps/v1/statefulset.go | 215 +- .../typed/apps/v1beta1/controllerrevision.go | 157 +- .../typed/apps/v1beta1/deployment.go | 205 +- .../v1beta1/fake/fake_controllerrevision.go | 34 +- .../apps/v1beta1/fake/fake_deployment.go | 46 +- .../apps/v1beta1/fake/fake_statefulset.go | 46 +- .../typed/apps/v1beta1/statefulset.go | 205 +- .../typed/apps/v1beta2/controllerrevision.go | 157 +- .../typed/apps/v1beta2/daemonset.go | 205 +- .../typed/apps/v1beta2/deployment.go | 205 +- .../v1beta2/fake/fake_controllerrevision.go | 34 +- .../typed/apps/v1beta2/fake/fake_daemonset.go | 46 +- .../apps/v1beta2/fake/fake_deployment.go | 46 +- .../apps/v1beta2/fake/fake_replicaset.go | 46 +- .../apps/v1beta2/fake/fake_statefulset.go | 61 +- .../typed/apps/v1beta2/replicaset.go | 205 +- .../typed/apps/v1beta2/statefulset.go | 215 +- .../v1/fake/fake_selfsubjectreview.go | 5 +- .../v1/fake/fake_tokenreview.go | 5 +- .../authentication/v1/selfsubjectreview.go | 23 +- .../typed/authentication/v1/tokenreview.go | 23 +- .../v1alpha1/fake/fake_selfsubjectreview.go | 5 +- .../v1alpha1/selfsubjectreview.go | 23 +- .../v1beta1/fake/fake_selfsubjectreview.go | 5 +- .../v1beta1/fake/fake_tokenreview.go | 5 +- .../v1beta1/selfsubjectreview.go | 23 +- .../authentication/v1beta1/tokenreview.go | 23 +- .../v1/fake/fake_localsubjectaccessreview.go | 5 +- .../v1/fake/fake_selfsubjectaccessreview.go | 5 +- .../v1/fake/fake_selfsubjectrulesreview.go | 5 +- .../v1/fake/fake_subjectaccessreview.go | 5 +- .../v1/localsubjectaccessreview.go | 26 +- .../v1/selfsubjectaccessreview.go | 23 +- .../v1/selfsubjectrulesreview.go | 23 +- .../authorization/v1/subjectaccessreview.go | 23 +- .../fake/fake_localsubjectaccessreview.go | 5 +- .../fake/fake_selfsubjectaccessreview.go | 5 +- .../fake/fake_selfsubjectrulesreview.go | 5 +- .../v1beta1/fake/fake_subjectaccessreview.go | 5 +- .../v1beta1/localsubjectaccessreview.go | 26 +- .../v1beta1/selfsubjectaccessreview.go | 23 +- .../v1beta1/selfsubjectrulesreview.go | 23 +- .../v1beta1/subjectaccessreview.go | 23 +- .../v1/fake/fake_horizontalpodautoscaler.go | 46 +- .../autoscaling/v1/horizontalpodautoscaler.go | 205 +- .../v2/fake/fake_horizontalpodautoscaler.go | 46 +- .../autoscaling/v2/horizontalpodautoscaler.go | 205 +- .../fake/fake_horizontalpodautoscaler.go | 46 +- .../v2beta1/horizontalpodautoscaler.go | 205 +- .../fake/fake_horizontalpodautoscaler.go | 46 +- .../v2beta2/horizontalpodautoscaler.go | 205 +- .../kubernetes/typed/batch/v1/cronjob.go | 205 +- .../typed/batch/v1/fake/fake_cronjob.go | 46 +- .../typed/batch/v1/fake/fake_job.go | 46 +- .../kubernetes/typed/batch/v1/job.go | 205 +- .../kubernetes/typed/batch/v1beta1/cronjob.go | 205 +- .../typed/batch/v1beta1/fake/fake_cronjob.go | 46 +- .../v1/certificatesigningrequest.go | 194 +- .../v1/fake/fake_certificatesigningrequest.go | 51 +- .../v1alpha1/clustertrustbundle.go | 146 +- .../v1alpha1/fake/fake_clustertrustbundle.go | 34 +- .../v1beta1/certificatesigningrequest.go | 192 +- .../certificatesigningrequest_expansion.go | 2 +- .../fake/fake_certificatesigningrequest.go | 46 +- .../typed/coordination/v1/fake/fake_lease.go | 34 +- .../kubernetes/typed/coordination/v1/lease.go | 157 +- .../v1alpha1/coordination_client.go | 107 + .../v1alpha2 => coordination/v1alpha1}/doc.go | 2 +- .../v1alpha1}/fake/doc.go | 0 .../v1alpha1/fake/fake_coordination_client.go | 40 + .../v1alpha1/fake/fake_leasecandidate.go | 160 + .../v1alpha1/generated_expansion.go | 21 + .../coordination/v1alpha1/leasecandidate.go | 69 + .../coordination/v1beta1/fake/fake_lease.go | 34 +- .../typed/coordination/v1beta1/lease.go | 157 +- .../typed/core/v1/componentstatus.go | 146 +- .../kubernetes/typed/core/v1/configmap.go | 157 +- .../kubernetes/typed/core/v1/endpoints.go | 157 +- .../kubernetes/typed/core/v1/event.go | 157 +- .../typed/core/v1/event_expansion.go | 22 +- .../core/v1/fake/fake_componentstatus.go | 34 +- .../typed/core/v1/fake/fake_configmap.go | 34 +- .../typed/core/v1/fake/fake_endpoints.go | 34 +- .../typed/core/v1/fake/fake_event.go | 34 +- .../typed/core/v1/fake/fake_limitrange.go | 34 +- .../typed/core/v1/fake/fake_namespace.go | 44 +- .../typed/core/v1/fake/fake_node.go | 46 +- .../core/v1/fake/fake_persistentvolume.go | 46 +- .../v1/fake/fake_persistentvolumeclaim.go | 46 +- .../kubernetes/typed/core/v1/fake/fake_pod.go | 51 +- .../typed/core/v1/fake/fake_podtemplate.go | 34 +- .../v1/fake/fake_replicationcontroller.go | 56 +- .../typed/core/v1/fake/fake_resourcequota.go | 46 +- .../typed/core/v1/fake/fake_secret.go | 34 +- .../typed/core/v1/fake/fake_service.go | 44 +- .../typed/core/v1/fake/fake_serviceaccount.go | 39 +- .../kubernetes/typed/core/v1/limitrange.go | 157 +- .../kubernetes/typed/core/v1/namespace.go | 177 +- .../typed/core/v1/namespace_expansion.go | 2 +- .../kubernetes/typed/core/v1/node.go | 192 +- .../typed/core/v1/node_expansion.go | 2 +- .../typed/core/v1/persistentvolume.go | 192 +- .../typed/core/v1/persistentvolumeclaim.go | 205 +- .../client-go/kubernetes/typed/core/v1/pod.go | 209 +- .../kubernetes/typed/core/v1/pod_expansion.go | 14 +- .../kubernetes/typed/core/v1/podtemplate.go | 157 +- .../typed/core/v1/replicationcontroller.go | 213 +- .../kubernetes/typed/core/v1/resourcequota.go | 205 +- .../kubernetes/typed/core/v1/secret.go | 157 +- .../kubernetes/typed/core/v1/service.go | 189 +- .../typed/core/v1/service_expansion.go | 4 +- .../typed/core/v1/serviceaccount.go | 161 +- .../typed/discovery/v1/endpointslice.go | 157 +- .../discovery/v1/fake/fake_endpointslice.go | 34 +- .../typed/discovery/v1beta1/endpointslice.go | 157 +- .../v1beta1/fake/fake_endpointslice.go | 34 +- .../kubernetes/typed/events/v1/event.go | 157 +- .../typed/events/v1/fake/fake_event.go | 34 +- .../kubernetes/typed/events/v1beta1/event.go | 157 +- .../typed/events/v1beta1/event_expansion.go | 18 +- .../typed/events/v1beta1/fake/fake_event.go | 34 +- .../typed/extensions/v1beta1/daemonset.go | 205 +- .../typed/extensions/v1beta1/deployment.go | 215 +- .../v1beta1/deployment_expansion.go | 2 +- .../extensions/v1beta1/fake/fake_daemonset.go | 46 +- .../v1beta1/fake/fake_deployment.go | 61 +- .../extensions/v1beta1/fake/fake_ingress.go | 46 +- .../v1beta1/fake/fake_networkpolicy.go | 34 +- .../v1beta1/fake/fake_replicaset.go | 61 +- .../typed/extensions/v1beta1/ingress.go | 205 +- .../typed/extensions/v1beta1/networkpolicy.go | 157 +- .../typed/extensions/v1beta1/replicaset.go | 215 +- .../flowcontrol/v1/fake/fake_flowschema.go | 46 +- .../fake/fake_prioritylevelconfiguration.go | 46 +- .../typed/flowcontrol/v1/flowschema.go | 192 +- .../v1/prioritylevelconfiguration.go | 192 +- .../v1beta1/fake/fake_flowschema.go | 46 +- .../fake/fake_prioritylevelconfiguration.go | 46 +- .../typed/flowcontrol/v1beta1/flowschema.go | 192 +- .../v1beta1/prioritylevelconfiguration.go | 192 +- .../v1beta2/fake/fake_flowschema.go | 46 +- .../fake/fake_prioritylevelconfiguration.go | 46 +- .../typed/flowcontrol/v1beta2/flowschema.go | 192 +- .../v1beta2/prioritylevelconfiguration.go | 192 +- .../v1beta3/fake/fake_flowschema.go | 46 +- .../fake/fake_prioritylevelconfiguration.go | 46 +- .../typed/flowcontrol/v1beta3/flowschema.go | 192 +- .../v1beta3/prioritylevelconfiguration.go | 192 +- .../typed/networking/v1/fake/fake_ingress.go | 46 +- .../networking/v1/fake/fake_ingressclass.go | 34 +- .../networking/v1/fake/fake_networkpolicy.go | 34 +- .../kubernetes/typed/networking/v1/ingress.go | 205 +- .../typed/networking/v1/ingressclass.go | 146 +- .../typed/networking/v1/networkpolicy.go | 157 +- .../v1alpha1/fake/fake_ipaddress.go | 34 +- .../v1alpha1/fake/fake_servicecidr.go | 46 +- .../typed/networking/v1alpha1/ipaddress.go | 146 +- .../typed/networking/v1alpha1/servicecidr.go | 192 +- .../networking/v1beta1/fake/fake_ingress.go | 46 +- .../v1beta1/fake/fake_ingressclass.go | 34 +- .../networking/v1beta1/fake/fake_ipaddress.go | 151 + .../v1beta1/fake/fake_networking_client.go | 8 + .../v1beta1/fake/fake_servicecidr.go | 186 + .../networking/v1beta1/generated_expansion.go | 4 + .../typed/networking/v1beta1/ingress.go | 205 +- .../typed/networking/v1beta1/ingressclass.go | 146 +- .../typed/networking/v1beta1/ipaddress.go | 69 + .../networking/v1beta1/networking_client.go | 10 + .../typed/networking/v1beta1/servicecidr.go | 73 + .../typed/node/v1/fake/fake_runtimeclass.go | 34 +- .../kubernetes/typed/node/v1/runtimeclass.go | 146 +- .../node/v1alpha1/fake/fake_runtimeclass.go | 34 +- .../typed/node/v1alpha1/runtimeclass.go | 146 +- .../node/v1beta1/fake/fake_runtimeclass.go | 34 +- .../typed/node/v1beta1/runtimeclass.go | 146 +- .../kubernetes/typed/policy/v1/eviction.go | 15 +- .../typed/policy/v1/eviction_expansion.go | 2 +- .../v1/fake/fake_poddisruptionbudget.go | 46 +- .../typed/policy/v1/poddisruptionbudget.go | 205 +- .../typed/policy/v1beta1/eviction.go | 15 +- .../policy/v1beta1/eviction_expansion.go | 2 +- .../v1beta1/fake/fake_poddisruptionbudget.go | 46 +- .../policy/v1beta1/poddisruptionbudget.go | 205 +- .../kubernetes/typed/rbac/v1/clusterrole.go | 146 +- .../typed/rbac/v1/clusterrolebinding.go | 146 +- .../typed/rbac/v1/fake/fake_clusterrole.go | 34 +- .../rbac/v1/fake/fake_clusterrolebinding.go | 34 +- .../typed/rbac/v1/fake/fake_role.go | 34 +- .../typed/rbac/v1/fake/fake_rolebinding.go | 34 +- .../kubernetes/typed/rbac/v1/role.go | 157 +- .../kubernetes/typed/rbac/v1/rolebinding.go | 157 +- .../typed/rbac/v1alpha1/clusterrole.go | 146 +- .../typed/rbac/v1alpha1/clusterrolebinding.go | 146 +- .../rbac/v1alpha1/fake/fake_clusterrole.go | 34 +- .../v1alpha1/fake/fake_clusterrolebinding.go | 34 +- .../typed/rbac/v1alpha1/fake/fake_role.go | 34 +- .../rbac/v1alpha1/fake/fake_rolebinding.go | 34 +- .../kubernetes/typed/rbac/v1alpha1/role.go | 157 +- .../typed/rbac/v1alpha1/rolebinding.go | 157 +- .../typed/rbac/v1beta1/clusterrole.go | 146 +- .../typed/rbac/v1beta1/clusterrolebinding.go | 146 +- .../rbac/v1beta1/fake/fake_clusterrole.go | 34 +- .../v1beta1/fake/fake_clusterrolebinding.go | 34 +- .../typed/rbac/v1beta1/fake/fake_role.go | 34 +- .../rbac/v1beta1/fake/fake_rolebinding.go | 34 +- .../kubernetes/typed/rbac/v1beta1/role.go | 157 +- .../typed/rbac/v1beta1/rolebinding.go | 157 +- .../v1alpha2/fake/fake_resourceclass.go | 145 - .../resource/v1alpha2/podschedulingcontext.go | 256 - .../typed/resource/v1alpha2/resourceclaim.go | 256 - .../v1alpha2/resourceclaimtemplate.go | 208 - .../typed/resource/v1alpha2/resourceclass.go | 197 - .../typed/resource/v1alpha3/deviceclass.go | 69 + .../typed/resource/v1alpha3}/doc.go | 9 +- .../typed/resource/v1alpha3/fake/doc.go | 20 + .../v1alpha3/fake/fake_deviceclass.go | 151 + .../fake/fake_podschedulingcontext.go | 92 +- .../fake/fake_resource_client.go | 20 +- .../fake/fake_resourceclaim.go | 92 +- .../fake/fake_resourceclaimtemplate.go | 74 +- .../v1alpha3/fake/fake_resourceslice.go | 151 + .../generated_expansion.go | 6 +- .../resource/v1alpha3/podschedulingcontext.go | 73 + .../{v1alpha2 => v1alpha3}/resource_client.go | 51 +- .../typed/resource/v1alpha3/resourceclaim.go | 73 + .../v1alpha3/resourceclaimtemplate.go | 69 + .../typed/resource/v1alpha3/resourceslice.go | 69 + .../scheduling/v1/fake/fake_priorityclass.go | 34 +- .../typed/scheduling/v1/priorityclass.go | 146 +- .../v1alpha1/fake/fake_priorityclass.go | 34 +- .../scheduling/v1alpha1/priorityclass.go | 146 +- .../v1beta1/fake/fake_priorityclass.go | 34 +- .../typed/scheduling/v1beta1/priorityclass.go | 146 +- .../kubernetes/typed/storage/v1/csidriver.go | 146 +- .../kubernetes/typed/storage/v1/csinode.go | 146 +- .../typed/storage/v1/csistoragecapacity.go | 157 +- .../typed/storage/v1/fake/fake_csidriver.go | 34 +- .../typed/storage/v1/fake/fake_csinode.go | 34 +- .../v1/fake/fake_csistoragecapacity.go | 34 +- .../storage/v1/fake/fake_storageclass.go | 34 +- .../storage/v1/fake/fake_volumeattachment.go | 46 +- .../typed/storage/v1/storageclass.go | 146 +- .../typed/storage/v1/volumeattachment.go | 192 +- .../storage/v1alpha1/csistoragecapacity.go | 157 +- .../v1alpha1/fake/fake_csistoragecapacity.go | 34 +- .../v1alpha1/fake/fake_volumeattachment.go | 46 +- .../fake/fake_volumeattributesclass.go | 34 +- .../storage/v1alpha1/volumeattachment.go | 192 +- .../storage/v1alpha1/volumeattributesclass.go | 146 +- .../typed/storage/v1beta1/csidriver.go | 146 +- .../typed/storage/v1beta1/csinode.go | 146 +- .../storage/v1beta1/csistoragecapacity.go | 157 +- .../storage/v1beta1/fake/fake_csidriver.go | 34 +- .../storage/v1beta1/fake/fake_csinode.go | 34 +- .../v1beta1/fake/fake_csistoragecapacity.go | 34 +- .../v1beta1/fake/fake_storage_client.go | 4 + .../storage/v1beta1/fake/fake_storageclass.go | 34 +- .../v1beta1/fake/fake_volumeattachment.go | 46 +- .../fake/fake_volumeattributesclass.go | 151 + .../storage/v1beta1/generated_expansion.go | 2 + .../typed/storage/v1beta1/storage_client.go | 5 + .../typed/storage/v1beta1/storageclass.go | 146 +- .../typed/storage/v1beta1/volumeattachment.go | 192 +- .../storage/v1beta1/volumeattributesclass.go | 69 + .../typed/storagemigration/v1alpha1/doc.go | 20 + .../storagemigration/v1alpha1/fake/doc.go | 20 + .../fake/fake_storagemigration_client.go | 40 + .../fake/fake_storageversionmigration.go | 186 + .../v1alpha1/generated_expansion.go | 21 + .../v1alpha1/storagemigration_client.go | 107 + .../v1alpha1/storageversionmigration.go | 73 + .../v1/expansion_generated.go | 8 + .../v1/mutatingwebhookconfiguration.go | 26 +- .../v1/validatingadmissionpolicy.go | 48 + .../v1/validatingadmissionpolicybinding.go | 48 + .../v1/validatingwebhookconfiguration.go | 26 +- .../v1alpha1/validatingadmissionpolicy.go | 26 +- .../validatingadmissionpolicybinding.go | 26 +- .../v1beta1/mutatingwebhookconfiguration.go | 26 +- .../v1beta1/validatingadmissionpolicy.go | 26 +- .../validatingadmissionpolicybinding.go | 26 +- .../v1beta1/validatingwebhookconfiguration.go | 26 +- .../v1alpha1/storageversion.go | 26 +- .../listers/apps/v1/controllerrevision.go | 39 +- .../client-go/listers/apps/v1/daemonset.go | 39 +- .../client-go/listers/apps/v1/deployment.go | 39 +- .../client-go/listers/apps/v1/replicaset.go | 39 +- .../client-go/listers/apps/v1/statefulset.go | 39 +- .../apps/v1beta1/controllerrevision.go | 39 +- .../listers/apps/v1beta1/deployment.go | 39 +- .../listers/apps/v1beta1/statefulset.go | 39 +- .../apps/v1beta2/controllerrevision.go | 39 +- .../listers/apps/v1beta2/daemonset.go | 39 +- .../listers/apps/v1beta2/deployment.go | 39 +- .../listers/apps/v1beta2/replicaset.go | 39 +- .../listers/apps/v1beta2/statefulset.go | 39 +- .../autoscaling/v1/horizontalpodautoscaler.go | 39 +- .../autoscaling/v2/horizontalpodautoscaler.go | 39 +- .../v2beta1/horizontalpodautoscaler.go | 39 +- .../v2beta2/horizontalpodautoscaler.go | 39 +- .../client-go/listers/batch/v1/cronjob.go | 39 +- .../k8s.io/client-go/listers/batch/v1/job.go | 39 +- .../listers/batch/v1beta1/cronjob.go | 39 +- .../v1/certificatesigningrequest.go | 26 +- .../v1alpha1/clustertrustbundle.go | 26 +- .../v1beta1/certificatesigningrequest.go | 26 +- .../listers/coordination/v1/lease.go | 39 +- .../v1alpha1/expansion_generated.go | 27 + .../coordination/v1alpha1/leasecandidate.go | 70 + .../listers/coordination/v1beta1/lease.go | 39 +- .../listers/core/v1/componentstatus.go | 26 +- .../client-go/listers/core/v1/configmap.go | 39 +- .../client-go/listers/core/v1/endpoints.go | 39 +- .../k8s.io/client-go/listers/core/v1/event.go | 39 +- .../client-go/listers/core/v1/limitrange.go | 39 +- .../client-go/listers/core/v1/namespace.go | 26 +- .../k8s.io/client-go/listers/core/v1/node.go | 26 +- .../listers/core/v1/persistentvolume.go | 26 +- .../listers/core/v1/persistentvolumeclaim.go | 39 +- .../k8s.io/client-go/listers/core/v1/pod.go | 39 +- .../client-go/listers/core/v1/podtemplate.go | 39 +- .../listers/core/v1/replicationcontroller.go | 39 +- .../listers/core/v1/resourcequota.go | 39 +- .../client-go/listers/core/v1/secret.go | 39 +- .../client-go/listers/core/v1/service.go | 39 +- .../listers/core/v1/serviceaccount.go | 39 +- .../listers/discovery/v1/endpointslice.go | 39 +- .../discovery/v1beta1/endpointslice.go | 39 +- .../parser => client-go/listers}/doc.go | 7 +- .../client-go/listers/events/v1/event.go | 39 +- .../client-go/listers/events/v1beta1/event.go | 39 +- .../listers/extensions/v1beta1/daemonset.go | 39 +- .../listers/extensions/v1beta1/deployment.go | 39 +- .../listers/extensions/v1beta1/ingress.go | 39 +- .../extensions/v1beta1/networkpolicy.go | 39 +- .../listers/extensions/v1beta1/replicaset.go | 39 +- .../listers/flowcontrol/v1/flowschema.go | 26 +- .../v1/prioritylevelconfiguration.go | 26 +- .../listers/flowcontrol/v1beta1/flowschema.go | 26 +- .../v1beta1/prioritylevelconfiguration.go | 26 +- .../listers/flowcontrol/v1beta2/flowschema.go | 26 +- .../v1beta2/prioritylevelconfiguration.go | 26 +- .../listers/flowcontrol/v1beta3/flowschema.go | 26 +- .../v1beta3/prioritylevelconfiguration.go | 26 +- .../client-go/listers/generic_helpers.go | 72 + .../listers/networking/v1/ingress.go | 39 +- .../listers/networking/v1/ingressclass.go | 26 +- .../listers/networking/v1/networkpolicy.go | 39 +- .../listers/networking/v1alpha1/ipaddress.go | 26 +- .../networking/v1alpha1/servicecidr.go | 26 +- .../networking/v1beta1/expansion_generated.go | 8 + .../listers/networking/v1beta1/ingress.go | 39 +- .../networking/v1beta1/ingressclass.go | 26 +- .../listers/networking/v1beta1/ipaddress.go | 48 + .../listers/networking/v1beta1/servicecidr.go | 48 + .../client-go/listers/node/v1/runtimeclass.go | 26 +- .../listers/node/v1alpha1/runtimeclass.go | 26 +- .../listers/node/v1beta1/runtimeclass.go | 26 +- .../client-go/listers/policy/v1/eviction.go | 39 +- .../listers/policy/v1/poddisruptionbudget.go | 39 +- .../listers/policy/v1beta1/eviction.go | 39 +- .../policy/v1beta1/poddisruptionbudget.go | 39 +- .../client-go/listers/rbac/v1/clusterrole.go | 26 +- .../listers/rbac/v1/clusterrolebinding.go | 26 +- .../k8s.io/client-go/listers/rbac/v1/role.go | 39 +- .../client-go/listers/rbac/v1/rolebinding.go | 39 +- .../listers/rbac/v1alpha1/clusterrole.go | 26 +- .../rbac/v1alpha1/clusterrolebinding.go | 26 +- .../client-go/listers/rbac/v1alpha1/role.go | 39 +- .../listers/rbac/v1alpha1/rolebinding.go | 39 +- .../listers/rbac/v1beta1/clusterrole.go | 26 +- .../rbac/v1beta1/clusterrolebinding.go | 26 +- .../client-go/listers/rbac/v1beta1/role.go | 39 +- .../listers/rbac/v1beta1/rolebinding.go | 39 +- .../resource/v1alpha2/resourceclass.go | 68 - .../listers/resource/v1alpha3/deviceclass.go | 48 + .../expansion_generated.go | 12 +- .../podschedulingcontext.go | 49 +- .../{v1alpha2 => v1alpha3}/resourceclaim.go | 49 +- .../resourceclaimtemplate.go | 49 +- .../resource/v1alpha3/resourceslice.go | 48 + .../listers/scheduling/v1/priorityclass.go | 26 +- .../scheduling/v1alpha1/priorityclass.go | 26 +- .../scheduling/v1beta1/priorityclass.go | 26 +- .../client-go/listers/storage/v1/csidriver.go | 26 +- .../client-go/listers/storage/v1/csinode.go | 26 +- .../listers/storage/v1/csistoragecapacity.go | 39 +- .../listers/storage/v1/storageclass.go | 26 +- .../listers/storage/v1/volumeattachment.go | 26 +- .../storage/v1alpha1/csistoragecapacity.go | 39 +- .../storage/v1alpha1/volumeattachment.go | 26 +- .../storage/v1alpha1/volumeattributesclass.go | 26 +- .../listers/storage/v1beta1/csidriver.go | 26 +- .../listers/storage/v1beta1/csinode.go | 26 +- .../storage/v1beta1/csistoragecapacity.go | 39 +- .../storage/v1beta1/expansion_generated.go | 4 + .../listers/storage/v1beta1/storageclass.go | 26 +- .../storage/v1beta1/volumeattachment.go | 26 +- .../storage/v1beta1/volumeattributesclass.go | 48 + .../v1alpha1/expansion_generated.go | 23 + .../v1alpha1/storageversionmigration.go | 48 + vendor/k8s.io/client-go/metadata/metadata.go | 4 +- .../pkg/client/auth/plugins_providers.go | 3 - vendor/k8s.io/client-go/rest/request.go | 146 + vendor/k8s.io/client-go/rest/watch/decoder.go | 2 +- .../k8s.io/client-go/restmapper/shortcut.go | 2 +- .../client-go/scale/scheme/appsint/doc.go | 2 +- .../client-go/scale/scheme/appsv1beta1/doc.go | 2 +- .../client-go/scale/scheme/appsv1beta2/doc.go | 2 +- .../scale/scheme/autoscalingv1/doc.go | 2 +- vendor/k8s.io/client-go/scale/scheme/doc.go | 2 +- .../scale/scheme/extensionsint/doc.go | 2 +- .../scale/scheme/extensionsv1beta1/doc.go | 2 +- vendor/k8s.io/client-go/testing/actions.go | 235 +- vendor/k8s.io/client-go/testing/fixture.go | 670 +- .../client-go/tools/cache/controller.go | 142 +- .../client-go/tools/cache/delta_fifo.go | 53 +- vendor/k8s.io/client-go/tools/cache/index.go | 3 +- .../k8s.io/client-go/tools/cache/listers.go | 6 +- .../k8s.io/client-go/tools/cache/listwatch.go | 4 + .../k8s.io/client-go/tools/cache/reflector.go | 265 +- .../reflector_data_consistency_detector.go | 94 +- .../client-go/tools/cache/shared_informer.go | 10 +- .../tools/cache/thread_safe_store.go | 92 +- .../client-go/tools/clientcmd/api/doc.go | 2 +- .../client-go/tools/clientcmd/api/helpers.go | 5 +- .../client-go/tools/clientcmd/api/v1/doc.go | 2 +- .../tools/clientcmd/client_config.go | 49 +- .../client-go/tools/clientcmd/config.go | 3 +- .../tools/events/event_broadcaster.go | 10 +- .../tools/leaderelection/leaderelection.go | 125 +- .../tools/leaderelection/leasecandidate.go | 202 + .../client-go/tools/leaderelection/metrics.go | 30 +- .../leaderelection/resourcelock/interface.go | 17 +- .../leaderelection/resourcelock/leaselock.go | 15 +- vendor/k8s.io/client-go/tools/record/event.go | 23 +- .../client-go/tools/remotecommand/OWNERS | 10 + .../client-go/tools/remotecommand/fallback.go | 13 +- .../tools/remotecommand/websocket.go | 16 +- .../client-go/tools/watch/retrywatcher.go | 12 +- .../client-go/transport/cert_rotation.go | 7 +- .../transport/websocket/roundtripper.go | 31 +- .../data_consistency_detector.go | 146 + .../list_data_consistency_detector.go | 70 + .../watch_list_data_consistency_detector.go | 54 + .../client-go/util/flowcontrol/backoff.go | 3 +- .../client-go/util/watchlist/watch_list.go | 82 + .../util/workqueue/default_rate_limiters.go | 139 +- .../util/workqueue/delaying_queue.go | 66 +- .../k8s.io/client-go/util/workqueue/queue.go | 153 +- .../util/workqueue/rate_limiting_queue.go | 64 +- vendor/k8s.io/code-generator/OWNERS | 1 + vendor/k8s.io/code-generator/README.md | 4 + .../cmd/applyconfiguration-gen/args/args.go | 63 +- .../args/externaltypes.go | 2 +- .../generators/applyconfiguration.go | 95 +- .../generators/internal.go | 8 +- .../generators/jsontagutil.go | 2 +- .../generators/openapi.go | 20 +- .../generators/refgraph.go | 8 +- .../generators/{packages.go => targets.go} | 149 +- .../generators/types.go | 26 +- .../applyconfiguration-gen/generators/util.go | 23 +- .../cmd/applyconfiguration-gen/main.go | 26 +- .../cmd/client-gen/args/args.go | 95 +- .../cmd/client-gen/args/gvpackages.go | 4 +- .../client-gen/generators/client_generator.go | 235 +- .../generators/fake/fake_client_generator.go | 98 +- .../fake/generator_fake_for_clientset.go | 73 +- .../fake/generator_fake_for_group.go | 18 +- .../fake/generator_fake_for_type.go | 183 +- .../generators/generator_for_clientset.go | 17 +- .../generators/generator_for_expansion.go | 6 +- .../generators/generator_for_group.go | 42 +- .../generators/generator_for_type.go | 496 +- .../generators/scheme/generator_for_scheme.go | 24 +- .../cmd/client-gen/generators/util/tags.go | 4 +- .../code-generator/cmd/client-gen/main.go | 32 +- .../cmd/client-gen/types/helpers.go | 8 +- .../cmd/client-gen/types/types.go | 16 +- .../cmd/conversion-gen/args/args.go | 44 +- .../conversion-gen/generators/conversion.go | 257 +- .../code-generator/cmd/conversion-gen/main.go | 28 +- .../cmd/deepcopy-gen/args/args.go | 36 +- .../cmd}/deepcopy-gen/generators/deepcopy.go | 161 +- .../code-generator/cmd/deepcopy-gen/main.go | 71 +- .../cmd/defaulter-gen/args/args.go | 35 +- .../defaulter-gen/generators/defaulter.go | 199 +- .../code-generator/cmd/defaulter-gen/main.go | 24 +- .../cmd/go-to-protobuf/protobuf/cmd.go | 278 +- .../cmd/go-to-protobuf/protobuf/generator.go | 32 +- .../go-to-protobuf/protobuf/import_tracker.go | 4 +- .../cmd/go-to-protobuf/protobuf/namer.go | 38 +- .../cmd/go-to-protobuf/protobuf/package.go | 54 +- .../cmd/go-to-protobuf/protobuf/parser.go | 30 +- .../cmd/go-to-protobuf/protobuf/tags.go | 4 +- .../code-generator/cmd/import-boss/.gitignore | 1 - .../code-generator/cmd/import-boss/README.md | 97 - .../code-generator/cmd/import-boss/main.go | 45 - .../cmd/informer-gen/args/args.go | 79 +- .../cmd/informer-gen/generators/factory.go | 11 +- .../generators/factoryinterface.go | 8 +- .../cmd/informer-gen/generators/generic.go | 8 +- .../informer-gen/generators/groupinterface.go | 12 +- .../cmd/informer-gen/generators/informer.go | 8 +- .../generators/{packages.go => targets.go} | 206 +- .../cmd/informer-gen/generators/types.go | 2 +- .../generators/versioninterface.go | 8 +- .../code-generator/cmd/informer-gen/main.go | 31 +- .../cmd/lister-gen/args/args.go | 50 +- .../cmd/lister-gen/generators/expansion.go | 18 +- .../cmd/lister-gen/generators/lister.go | 143 +- .../code-generator/cmd/lister-gen/main.go | 28 +- .../cmd/register-gen/args/args.go | 27 +- .../generators/register_external.go | 10 +- .../generators/{packages.go => targets.go} | 50 +- .../code-generator/cmd/register-gen/main.go | 23 +- .../code-generator/cmd/set-gen/.gitignore | 1 - .../k8s.io/code-generator/cmd/set-gen/main.go | 53 - .../k8s.io/code-generator/generate-groups.sh | 52 +- .../generate-internal-groups.sh | 280 +- vendor/k8s.io/code-generator/kube_codegen.sh | 554 +- .../code-generator/pkg/namer/tag-override.go | 7 +- .../k8s.io/code-generator/pkg/util/build.go | 60 - vendor/k8s.io/code-generator/tools.go | 4 +- .../colon_separated_multimap_string_string.go | 24 +- .../featuregate/feature_gate.go | 517 +- .../featuregate/testing/feature_gate.go | 135 +- .../logs/api/v1/kube_features.go | 10 +- .../component-base/logs/api/v1/options.go | 37 +- .../logs/api/v1/options_no_slog.go | 24 + .../logs/api/v1/options_slog.go | 37 + .../component-base/logs/api/v1/registry.go | 2 +- .../k8s.io/component-base/logs/api/v1/text.go | 142 + .../component-base/logs/api/v1/types.go | 13 + .../logs/api/v1/zz_generated.deepcopy.go | 37 +- .../metrics/prometheus/slis/metrics.go | 2 - .../metrics/testutil/metrics.go | 2 +- .../metrics/testutil/promlint.go | 6 +- .../metrics/testutil/testutil.go | 11 +- vendor/k8s.io/component-base/tracing/utils.go | 7 +- vendor/k8s.io/component-base/version/base.go | 7 + .../corev1/nodeaffinity/nodeaffinity.go | 20 +- vendor/k8s.io/gengo/LICENSE | 202 - vendor/k8s.io/gengo/args/args.go | 200 - .../import-boss/generators/import_restrict.go | 443 - .../gengo/examples/set-gen/generators/sets.go | 378 - .../gengo/generator/default_generator.go | 62 - .../k8s.io/gengo/generator/default_package.go | 75 - vendor/k8s.io/gengo/generator/doc.go | 31 - .../k8s.io/gengo/generator/error_tracker.go | 50 - vendor/k8s.io/gengo/generator/execute.go | 329 - vendor/k8s.io/gengo/generator/generator.go | 259 - .../k8s.io/gengo/generator/import_tracker.go | 89 - .../k8s.io/gengo/generator/snippet_writer.go | 154 - .../gengo/generator/transitive_closure.go | 65 - vendor/k8s.io/gengo/namer/doc.go | 31 - vendor/k8s.io/gengo/namer/import_tracker.go | 121 - vendor/k8s.io/gengo/namer/namer.go | 395 - vendor/k8s.io/gengo/namer/order.go | 72 - vendor/k8s.io/gengo/namer/plural_namer.go | 120 - vendor/k8s.io/gengo/parser/parse.go | 925 -- vendor/k8s.io/gengo/types/comments.go | 82 - vendor/k8s.io/gengo/types/doc.go | 19 - vendor/k8s.io/gengo/types/flatten.go | 57 - vendor/k8s.io/gengo/types/types.go | 537 - .../gengo/v2/generator/snippet_writer.go | 38 +- .../klog/v2/internal/verbosity/verbosity.go | 303 + vendor/k8s.io/klog/v2/textlogger/options.go | 154 + .../k8s.io/klog/v2/textlogger/textlogger.go | 187 + .../klog/v2/textlogger/textlogger_slog.go | 52 + .../cmd/openapi-gen/openapi-gen.go} | 25 +- .../kube-openapi/pkg/builder3/openapi.go | 5 +- .../kube-openapi/pkg/generators/openapi.go | 2 +- vendor/k8s.io/kubectl/pkg/cmd/get/get.go | 24 +- vendor/k8s.io/kubectl/pkg/cmd/get/sorter.go | 11 +- vendor/k8s.io/kubectl/pkg/cmd/util/helpers.go | 9 +- vendor/k8s.io/kubectl/pkg/scheme/install.go | 3 +- .../kubectl/de_DE/LC_MESSAGES/k8s.po | 4 +- .../kubectl/default/LC_MESSAGES/k8s.po | 4 +- .../kubectl/en_US/LC_MESSAGES/k8s.po | 4 +- .../kubectl/it_IT/LC_MESSAGES/k8s.po | 4 +- .../kubectl/ja_JP/LC_MESSAGES/k8s.po | 6 +- .../kubectl/pt_BR/LC_MESSAGES/k8s.po | 4 +- .../kubectl/zh_CN/LC_MESSAGES/k8s.po | 4 +- vendor/k8s.io/kubectl/pkg/util/openapi/doc.go | 2 +- .../pkg/apis/metrics/v1beta1/generated.pb.go | 101 +- .../pkg/apis/metrics/v1beta1/generated.proto | 21 +- .../metrics/pkg/apis/metrics/v1beta1/types.go | 1 + vendor/k8s.io/utils/integer/integer.go | 73 - vendor/k8s.io/utils/net/multi_listen.go | 195 + vendor/modules.txt | 248 +- .../sigs.k8s.io/controller-runtime/.gitignore | 5 +- .../controller-runtime/.golangci.yml | 16 +- .../controller-runtime/.gomodcheck.yaml | 14 + vendor/sigs.k8s.io/controller-runtime/FAQ.md | 4 +- .../sigs.k8s.io/controller-runtime/Makefile | 122 +- vendor/sigs.k8s.io/controller-runtime/OWNERS | 3 +- .../controller-runtime/OWNERS_ALIASES | 6 - .../sigs.k8s.io/controller-runtime/README.md | 20 + .../sigs.k8s.io/controller-runtime/alias.go | 12 +- .../pkg/builder/controller.go | 181 +- .../controller-runtime/pkg/builder/options.go | 10 +- .../controller-runtime/pkg/builder/webhook.go | 37 +- .../controller-runtime/pkg/cache/cache.go | 25 +- .../pkg/cache/internal/cache_reader.go | 2 +- .../pkg/cache/internal/informers.go | 13 +- .../pkg/cache/multi_namespace_cache.go | 14 +- .../pkg/certwatcher/certwatcher.go | 10 +- .../pkg/client/apiutil/apimachinery.go | 5 +- .../controller-runtime/pkg/client/client.go | 41 +- .../pkg/client/fake/client.go | 288 +- .../pkg/client/fieldowner.go | 20 +- .../pkg/client/fieldvalidation.go | 106 + .../controller-runtime/pkg/client/options.go | 99 + .../controller-runtime/pkg/config/config.go | 112 - .../pkg/config/controller.go | 9 +- .../pkg/config/v1alpha1/doc.go | 22 - .../pkg/config/v1alpha1/register.go | 43 - .../pkg/config/v1alpha1/types.go | 179 - .../config/v1alpha1/zz_generated.deepcopy.go | 157 - .../pkg/controller/controller.go | 104 +- .../controllerutil/controllerutil.go | 20 +- .../doc.go => controller/name.go} | 31 +- .../controller-runtime/pkg/envtest/server.go | 25 + .../controller-runtime/pkg/event/event.go | 51 +- .../controller-runtime/pkg/handler/enqueue.go | 43 +- .../pkg/handler/enqueue_mapped.go | 68 +- .../pkg/handler/enqueue_owner.go | 58 +- .../pkg/handler/eventhandler.go | 61 +- .../pkg/internal/controller/controller.go | 87 +- .../internal/controller/metrics/metrics.go | 8 + .../pkg/internal/source/event_handler.go | 38 +- .../pkg/internal/source/kind.go | 58 +- .../pkg/manager/internal.go | 92 +- .../controller-runtime/pkg/manager/manager.go | 123 - .../pkg/manager/runnable_group.go | 5 +- .../controller-runtime/pkg/manager/server.go | 74 +- .../pkg/metrics/leaderelection.go | 23 +- .../pkg/metrics/server/server.go | 12 +- .../pkg/metrics/workqueue.go | 28 +- .../pkg/predicate/predicate.go | 192 +- .../pkg/ratelimiter/ratelimiter.go | 30 - .../pkg/reconcile/reconcile.go | 36 +- .../controller-runtime/pkg/source/source.go | 186 +- .../pkg/webhook/admission/decode.go | 25 +- .../pkg/webhook/admission/defaulter.go | 2 +- .../pkg/webhook/admission/defaulter_custom.go | 2 +- .../pkg/webhook/admission/metrics/metrics.go | 39 + .../pkg/webhook/admission/validator.go | 2 +- .../pkg/webhook/admission/validator_custom.go | 2 +- .../pkg/webhook/admission/webhook.go | 33 +- .../kustomize/api/filters/imagetag/updater.go | 2 +- .../kustomize/api/filters/nameref/nameref.go | 9 +- .../filters/patchjson6902/patchjson6902.go | 2 +- .../api/filters/replacement/replacement.go | 15 +- .../accumulator/loadconfigfromcrds.go | 2 +- .../builtins/HelmChartInflationGenerator.go | 68 +- .../builtins/PatchJson6902Transformer.go | 2 +- .../api/internal/builtins/PatchTransformer.go | 144 +- .../internal/builtins/SortOrderTransformer.go | 53 +- .../kustomize/api/internal/git/cloner.go | 6 + .../api/{ => internal}/image/image.go | 0 .../builtinpluginconsts/commonannotations.go | 0 .../builtinpluginconsts/commonlabels.go | 0 .../builtinpluginconsts/defaultconfig.go | 0 .../konfig/builtinpluginconsts/doc.go | 0 .../konfig/builtinpluginconsts/images.go | 0 .../builtinpluginconsts/metadatalabels.go | 0 .../konfig/builtinpluginconsts/nameprefix.go | 0 .../builtinpluginconsts/namereference.go | 7 + .../konfig/builtinpluginconsts/namespace.go | 0 .../konfig/builtinpluginconsts/namesuffix.go | 0 .../konfig/builtinpluginconsts/replicas.go | 0 .../builtinpluginconsts/templatelabels.go | 0 .../builtinpluginconsts/varreference.go | 0 .../api/{ => internal}/loader/errors.go | 0 .../api/{ => internal}/loader/fileloader.go | 101 +- .../api/{ => internal}/loader/loader.go | 0 .../{ => internal}/loader/loadrestrictions.go | 0 .../builtinconfig/loaddefaultconfig.go | 2 +- .../builtinconfig/namebackreferences.go | 13 + .../builtinconfig/transformerconfig.go | 62 +- .../internal/plugins/execplugin/execplugin.go | 26 +- .../internal/plugins/loader/load_go_plugin.go | 62 + .../plugins/loader/load_go_plugin_disabled.go | 25 + .../api/internal/plugins/loader/loader.go | 47 - .../api/internal/target/kusttarget.go | 28 +- .../target/kusttarget_configplugin.go | 29 +- .../api/internal/utils/errtimeout.go | 6 +- .../kustomize/api/internal/utils/timedcall.go | 2 +- .../kustomize/api/krusty/kustomizer.go | 2 +- .../kustomize/api/provenance/provenance.go | 35 + .../kustomize/api/resmap/reswrangler.go | 3 +- .../kustomize/api/resource/factory.go | 26 +- .../kustomize/api/resource/resource.go | 25 +- .../kustomize/api/types/fieldspec.go | 9 + .../kustomize/api/types/generatorargs.go | 2 +- .../kustomize/api/types/helmchartargs.go | 7 + .../kustomize/api/types/kustomization.go | 5 + .../sigs.k8s.io/kustomize/api/types/labels.go | 4 +- .../kustomize/api/types/pluginconfig.go | 6 +- .../kyaml/fn/runtime/container/container.go | 2 +- .../kustomize/kyaml/kio/ignorefilesmatcher.go | 2 +- .../kyaml/openapi/kustomizationapi/swagger.go | 2 +- .../kustomize/kyaml/openapi/openapi.go | 67 +- .../sigs.k8s.io/kustomize/kyaml/yaml/alias.go | 4 +- .../kustomize/kyaml/yaml/compatibility.go | 6 +- .../sigs.k8s.io/kustomize/kyaml/yaml/fns.go | 17 +- .../sigs.k8s.io/kustomize/kyaml/yaml/kfns.go | 2 +- .../sigs.k8s.io/kustomize/kyaml/yaml/match.go | 2 +- .../kustomize/kyaml/yaml/merge2/merge2.go | 5 +- .../sigs.k8s.io/kustomize/kyaml/yaml/rnode.go | 19 +- .../sigs.k8s.io/kustomize/kyaml/yaml/types.go | 2 +- .../kustomize/kyaml/yaml/walk/map.go | 21 +- .../go-yaml/yaml => yaml/goyaml.v3}/LICENSE | 0 .../go-yaml/yaml => yaml/goyaml.v3}/NOTICE | 0 vendor/sigs.k8s.io/yaml/goyaml.v3/OWNERS | 24 + .../go-yaml/yaml => yaml/goyaml.v3}/README.md | 10 + .../go-yaml/yaml => yaml/goyaml.v3}/apic.go | 0 .../go-yaml/yaml => yaml/goyaml.v3}/decode.go | 0 .../yaml => yaml/goyaml.v3}/emitterc.go | 57 +- .../go-yaml/yaml => yaml/goyaml.v3}/encode.go | 0 .../yaml => yaml/goyaml.v3}/parserc.go | 0 vendor/sigs.k8s.io/yaml/goyaml.v3/patch.go | 39 + .../yaml => yaml/goyaml.v3}/readerc.go | 0 .../yaml => yaml/goyaml.v3}/resolve.go | 0 .../yaml => yaml/goyaml.v3}/scannerc.go | 0 .../go-yaml/yaml => yaml/goyaml.v3}/sorter.go | 0 .../yaml => yaml/goyaml.v3}/writerc.go | 0 .../go-yaml/yaml => yaml/goyaml.v3}/yaml.go | 10 - .../go-yaml/yaml => yaml/goyaml.v3}/yamlh.go | 0 .../yaml => yaml/goyaml.v3}/yamlprivateh.go | 0 2653 files changed, 137476 insertions(+), 72653 deletions(-) delete mode 100644 vendor/github.com/antlr/antlr4/runtime/Go/antlr/v4/LICENSE delete mode 100644 vendor/github.com/antlr/antlr4/runtime/Go/antlr/v4/antlrdoc.go delete mode 100644 vendor/github.com/antlr/antlr4/runtime/Go/antlr/v4/atn_config.go delete mode 100644 vendor/github.com/antlr/antlr4/runtime/Go/antlr/v4/atn_config_set.go delete mode 100644 vendor/github.com/antlr/antlr4/runtime/Go/antlr/v4/input_stream.go delete mode 100644 vendor/github.com/antlr/antlr4/runtime/Go/antlr/v4/jcollect.go delete mode 100644 vendor/github.com/antlr/antlr4/runtime/Go/antlr/v4/prediction_context.go delete mode 100644 vendor/github.com/antlr/antlr4/runtime/Go/antlr/v4/prediction_mode.go delete mode 100644 vendor/github.com/antlr/antlr4/runtime/Go/antlr/v4/rule_context.go delete mode 100644 vendor/github.com/antlr/antlr4/runtime/Go/antlr/v4/utils_set.go create mode 100644 vendor/github.com/antlr4-go/antlr/v4/.gitignore create mode 100644 vendor/github.com/antlr4-go/antlr/v4/LICENSE create mode 100644 vendor/github.com/antlr4-go/antlr/v4/README.md create mode 100644 vendor/github.com/antlr4-go/antlr/v4/antlrdoc.go rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/atn.go (94%) create mode 100644 vendor/github.com/antlr4-go/antlr/v4/atn_config.go create mode 100644 vendor/github.com/antlr4-go/antlr/v4/atn_config_set.go rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/atn_deserialization_options.go (86%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/atn_deserializer.go (97%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/atn_simulator.go (66%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/atn_state.go (65%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/atn_type.go (100%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/char_stream.go (89%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/common_token_factory.go (100%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/common_token_stream.go (88%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/comparators.go (82%) create mode 100644 vendor/github.com/antlr4-go/antlr/v4/configuration.go rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/dfa.go (76%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/dfa_serializer.go (97%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/dfa_state.go (81%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/diagnostic_error_listener.go (92%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/error_listener.go (62%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/error_strategy.go (58%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/errors.go (73%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/file_stream.go (52%) create mode 100644 vendor/github.com/antlr4-go/antlr/v4/input_stream.go rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/int_stream.go (100%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/interval_set.go (82%) create mode 100644 vendor/github.com/antlr4-go/antlr/v4/jcollect.go rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/lexer.go (78%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/lexer_action.go (78%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/lexer_action_executor.go (70%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/lexer_atn_simulator.go (80%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/ll1_analyzer.go (73%) create mode 100644 vendor/github.com/antlr4-go/antlr/v4/nostatistics.go rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/parser.go (80%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/parser_atn_simulator.go (64%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/parser_rule_context.go (77%) create mode 100644 vendor/github.com/antlr4-go/antlr/v4/prediction_context.go create mode 100644 vendor/github.com/antlr4-go/antlr/v4/prediction_context_cache.go create mode 100644 vendor/github.com/antlr4-go/antlr/v4/prediction_mode.go rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/recognizer.go (70%) create mode 100644 vendor/github.com/antlr4-go/antlr/v4/rule_context.go rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/semantic_context.go (92%) create mode 100644 vendor/github.com/antlr4-go/antlr/v4/statistics.go create mode 100644 vendor/github.com/antlr4-go/antlr/v4/stats_data.go rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/token.go (86%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/token_source.go (100%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/token_stream.go (90%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/tokenstream_rewriter.go (73%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/trace_listener.go (100%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/transition.go (67%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/tree.go (62%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/trees.go (81%) rename vendor/github.com/{antlr/antlr4/runtime/Go => antlr4-go}/antlr/v4/utils.go (85%) delete mode 100644 vendor/github.com/fvbommel/sortorder/.gitignore delete mode 100644 vendor/github.com/fvbommel/sortorder/README.md delete mode 100644 vendor/github.com/fvbommel/sortorder/doc.go delete mode 100644 vendor/github.com/fvbommel/sortorder/natsort.go create mode 100644 vendor/github.com/fxamacker/cbor/v2/.gitignore create mode 100644 vendor/github.com/fxamacker/cbor/v2/.golangci.yml create mode 100644 vendor/github.com/fxamacker/cbor/v2/CODE_OF_CONDUCT.md create mode 100644 vendor/github.com/fxamacker/cbor/v2/CONTRIBUTING.md rename vendor/github.com/{fvbommel/sortorder => fxamacker/cbor/v2}/LICENSE (93%) create mode 100644 vendor/github.com/fxamacker/cbor/v2/README.md create mode 100644 vendor/github.com/fxamacker/cbor/v2/SECURITY.md create mode 100644 vendor/github.com/fxamacker/cbor/v2/bytestring.go create mode 100644 vendor/github.com/fxamacker/cbor/v2/cache.go create mode 100644 vendor/github.com/fxamacker/cbor/v2/common.go create mode 100644 vendor/github.com/fxamacker/cbor/v2/decode.go create mode 100644 vendor/github.com/fxamacker/cbor/v2/diagnose.go create mode 100644 vendor/github.com/fxamacker/cbor/v2/doc.go create mode 100644 vendor/github.com/fxamacker/cbor/v2/encode.go create mode 100644 vendor/github.com/fxamacker/cbor/v2/encode_map.go create mode 100644 vendor/github.com/fxamacker/cbor/v2/encode_map_go117.go create mode 100644 vendor/github.com/fxamacker/cbor/v2/simplevalue.go create mode 100644 vendor/github.com/fxamacker/cbor/v2/stream.go create mode 100644 vendor/github.com/fxamacker/cbor/v2/structfields.go create mode 100644 vendor/github.com/fxamacker/cbor/v2/tag.go create mode 100644 vendor/github.com/fxamacker/cbor/v2/valid.go create mode 100644 vendor/github.com/google/cel-go/cel/folding.go create mode 100644 vendor/github.com/google/cel-go/cel/inlining.go create mode 100644 vendor/github.com/google/cel-go/cel/optimizer.go create mode 100644 vendor/github.com/google/cel-go/common/ast/conversion.go create mode 100644 vendor/github.com/google/cel-go/common/ast/factory.go create mode 100644 vendor/github.com/google/cel-go/common/ast/navigable.go create mode 100644 vendor/github.com/google/cel-go/ext/formatting.go delete mode 100644 vendor/github.com/google/cel-go/interpreter/formatting.go create mode 100644 vendor/github.com/moby/term/doc.go delete mode 100644 vendor/github.com/moby/term/tc.go create mode 100644 vendor/github.com/moby/term/term_unix.go rename vendor/github.com/moby/term/{termios.go => termios_unix.go} (50%) create mode 100644 vendor/github.com/moby/term/termios_windows.go delete mode 100644 vendor/github.com/moby/term/winsize.go create mode 100644 vendor/github.com/x448/float16/.travis.yml create mode 100644 vendor/github.com/x448/float16/LICENSE create mode 100644 vendor/github.com/x448/float16/README.md create mode 100644 vendor/github.com/x448/float16/float16.go create mode 100644 vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv/env.go create mode 100644 vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv/util.go create mode 100644 vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv/v1.20.0.go create mode 100644 vendor/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv/v1.24.0.go delete mode 100644 vendor/go.opentelemetry.io/otel/.gitmodules create mode 100644 vendor/go.opentelemetry.io/otel/attribute/README.md create mode 100644 vendor/go.opentelemetry.io/otel/baggage/README.md create mode 100644 vendor/go.opentelemetry.io/otel/codes/README.md create mode 100644 vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/README.md create mode 100644 vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/README.md create mode 100644 vendor/go.opentelemetry.io/otel/metric/README.md create mode 100644 vendor/go.opentelemetry.io/otel/metric/embedded/README.md create mode 100644 vendor/go.opentelemetry.io/otel/metric/noop/README.md create mode 100644 vendor/go.opentelemetry.io/otel/metric/noop/noop.go create mode 100644 vendor/go.opentelemetry.io/otel/propagation/README.md create mode 100644 vendor/go.opentelemetry.io/otel/renovate.json create mode 100644 vendor/go.opentelemetry.io/otel/sdk/README.md create mode 100644 vendor/go.opentelemetry.io/otel/sdk/instrumentation/README.md delete mode 100644 vendor/go.opentelemetry.io/otel/sdk/internal/gen.go delete mode 100644 vendor/go.opentelemetry.io/otel/sdk/internal/internal.go create mode 100644 vendor/go.opentelemetry.io/otel/sdk/internal/x/README.md create mode 100644 vendor/go.opentelemetry.io/otel/sdk/internal/x/x.go create mode 100644 vendor/go.opentelemetry.io/otel/sdk/resource/README.md create mode 100644 vendor/go.opentelemetry.io/otel/sdk/trace/README.md create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.12.0/README.md create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.17.0/README.md create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.20.0/README.md create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.20.0/attribute_group.go create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.20.0/doc.go rename vendor/go.opentelemetry.io/otel/semconv/{v1.21.0 => v1.20.0}/event.go (92%) create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.20.0/exception.go create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.20.0/http.go rename vendor/go.opentelemetry.io/otel/semconv/{v1.21.0 => v1.20.0}/resource.go (86%) create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.20.0/schema.go rename vendor/go.opentelemetry.io/otel/semconv/{v1.21.0 => v1.20.0}/trace.go (94%) delete mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.21.0/attribute_group.go delete mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.21.0/doc.go delete mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.21.0/exception.go delete mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.21.0/schema.go create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.24.0/README.md create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.24.0/attribute_group.go create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.24.0/doc.go create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.24.0/event.go create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.24.0/exception.go create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.24.0/metric.go create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.24.0/resource.go create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.24.0/schema.go create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.24.0/trace.go create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.26.0/README.md create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.26.0/attribute_group.go create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.26.0/doc.go create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.26.0/exception.go create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.26.0/metric.go create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.26.0/schema.go create mode 100644 vendor/go.opentelemetry.io/otel/trace/README.md create mode 100644 vendor/go.opentelemetry.io/otel/trace/embedded/README.md create mode 100644 vendor/go.opentelemetry.io/otel/trace/noop/README.md create mode 100644 vendor/go.opentelemetry.io/otel/verify_readmes.sh create mode 100644 vendor/golang.org/x/text/cases/cases.go create mode 100644 vendor/golang.org/x/text/cases/context.go create mode 100644 vendor/golang.org/x/text/cases/fold.go create mode 100644 vendor/golang.org/x/text/cases/icu.go create mode 100644 vendor/golang.org/x/text/cases/info.go create mode 100644 vendor/golang.org/x/text/cases/map.go create mode 100644 vendor/golang.org/x/text/cases/tables10.0.0.go create mode 100644 vendor/golang.org/x/text/cases/tables11.0.0.go create mode 100644 vendor/golang.org/x/text/cases/tables12.0.0.go create mode 100644 vendor/golang.org/x/text/cases/tables13.0.0.go create mode 100644 vendor/golang.org/x/text/cases/tables15.0.0.go create mode 100644 vendor/golang.org/x/text/cases/tables9.0.0.go create mode 100644 vendor/golang.org/x/text/cases/trieval.go rename vendor/google.golang.org/grpc/{ => balancer/pickfirst}/pickfirst.go (89%) delete mode 100644 vendor/google.golang.org/grpc/internal/grpcrand/grpcrand.go delete mode 100644 vendor/google.golang.org/grpc/internal/grpcrand/grpcrand_go1.21.go rename vendor/{github.com/evanphx/json-patch => gopkg.in/evanphx/json-patch.v4}/.gitignore (100%) rename vendor/{github.com/evanphx/json-patch => gopkg.in/evanphx/json-patch.v4}/LICENSE (100%) rename vendor/{github.com/evanphx/json-patch => gopkg.in/evanphx/json-patch.v4}/README.md (97%) rename vendor/{github.com/evanphx/json-patch => gopkg.in/evanphx/json-patch.v4}/errors.go (100%) rename vendor/{github.com/evanphx/json-patch => gopkg.in/evanphx/json-patch.v4}/merge.go (100%) rename vendor/{github.com/evanphx/json-patch => gopkg.in/evanphx/json-patch.v4}/patch.go (99%) create mode 100644 vendor/k8s.io/api/admission/v1/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/api/admissionregistration/v1/zz_generated.prerelease-lifecycle.go rename vendor/k8s.io/{apiserver/pkg/apis/config/v1 => api/apidiscovery/v2}/doc.go (71%) create mode 100644 vendor/k8s.io/api/apidiscovery/v2/generated.pb.go create mode 100644 vendor/k8s.io/api/apidiscovery/v2/generated.proto rename vendor/k8s.io/{apiserver/pkg/apis/config => api/apidiscovery/v2}/register.go (73%) create mode 100644 vendor/k8s.io/api/apidiscovery/v2/types.go create mode 100644 vendor/k8s.io/api/apidiscovery/v2/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/apidiscovery/v2/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/api/apps/v1/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/api/authentication/v1/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/api/authorization/v1/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/api/autoscaling/v1/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/api/autoscaling/v2/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/api/batch/v1/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/api/certificates/v1/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/api/coordination/v1/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/api/coordination/v1alpha1/doc.go create mode 100644 vendor/k8s.io/api/coordination/v1alpha1/generated.pb.go create mode 100644 vendor/k8s.io/api/coordination/v1alpha1/generated.proto rename vendor/k8s.io/{apiserver/pkg/apis/config/v1 => api/coordination/v1alpha1}/register.go (51%) create mode 100644 vendor/k8s.io/api/coordination/v1alpha1/types.go create mode 100644 vendor/k8s.io/api/coordination/v1alpha1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/coordination/v1alpha1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/coordination/v1alpha1/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/api/core/v1/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/api/discovery/v1/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/api/events/v1/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/api/flowcontrol/v1/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/api/networking/v1/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/api/networking/v1beta1/well_known_labels.go create mode 100644 vendor/k8s.io/api/node/v1/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/api/policy/v1/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/api/rbac/v1/zz_generated.prerelease-lifecycle.go delete mode 100644 vendor/k8s.io/api/resource/v1alpha2/generated.proto delete mode 100644 vendor/k8s.io/api/resource/v1alpha2/namedresources.go delete mode 100644 vendor/k8s.io/api/resource/v1alpha2/types.go delete mode 100644 vendor/k8s.io/api/resource/v1alpha2/types_swagger_doc_generated.go rename vendor/k8s.io/api/resource/{v1alpha2 => v1alpha3}/doc.go (84%) rename vendor/k8s.io/api/resource/{v1alpha2 => v1alpha3}/generated.pb.go (60%) create mode 100644 vendor/k8s.io/api/resource/v1alpha3/generated.proto rename vendor/k8s.io/api/resource/{v1alpha2 => v1alpha3}/register.go (86%) create mode 100644 vendor/k8s.io/api/resource/v1alpha3/types.go create mode 100644 vendor/k8s.io/api/resource/v1alpha3/types_swagger_doc_generated.go rename vendor/k8s.io/api/resource/{v1alpha2 => v1alpha3}/zz_generated.deepcopy.go (60%) create mode 100644 vendor/k8s.io/api/scheduling/v1/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/api/storage/v1/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/api/storagemigration/v1alpha1/doc.go create mode 100644 vendor/k8s.io/api/storagemigration/v1alpha1/generated.pb.go create mode 100644 vendor/k8s.io/api/storagemigration/v1alpha1/generated.proto create mode 100644 vendor/k8s.io/api/storagemigration/v1alpha1/register.go create mode 100644 vendor/k8s.io/api/storagemigration/v1alpha1/types.go create mode 100644 vendor/k8s.io/api/storagemigration/v1alpha1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/storagemigration/v1alpha1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/storagemigration/v1alpha1/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/apiextensions-apiserver/pkg/client/applyconfiguration/apiextensions/v1/selectablefield.go create mode 100644 vendor/k8s.io/apiextensions-apiserver/pkg/client/applyconfiguration/apiextensions/v1beta1/selectablefield.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/meta/testrestmapper/test_restmapper.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/cbor/direct/direct.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/cbor/internal/modes/buffers.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/cbor/internal/modes/custom.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/cbor/internal/modes/decode.go rename vendor/k8s.io/{gengo/examples/set-gen/generators/tags.go => apimachinery/pkg/runtime/serializer/cbor/internal/modes/diagnostic.go} (56%) create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/cbor/internal/modes/encode.go create mode 100644 vendor/k8s.io/apiserver/pkg/admission/plugin/policy/generic/accessor.go create mode 100644 vendor/k8s.io/apiserver/pkg/admission/plugin/policy/generic/interfaces.go create mode 100644 vendor/k8s.io/apiserver/pkg/admission/plugin/policy/generic/plugin.go create mode 100644 vendor/k8s.io/apiserver/pkg/admission/plugin/policy/generic/policy_dispatcher.go rename vendor/k8s.io/apiserver/pkg/admission/plugin/{validatingadmissionpolicy/matcher.go => policy/generic/policy_matcher.go} (55%) create mode 100644 vendor/k8s.io/apiserver/pkg/admission/plugin/policy/generic/policy_source.go create mode 100644 vendor/k8s.io/apiserver/pkg/admission/plugin/policy/generic/policy_test_context.go rename vendor/k8s.io/apiserver/pkg/admission/plugin/{validatingadmissionpolicy => policy}/internal/generic/controller.go (90%) rename vendor/k8s.io/apiserver/pkg/admission/plugin/{validatingadmissionpolicy => policy}/internal/generic/doc.go (100%) rename vendor/k8s.io/apiserver/pkg/admission/plugin/{validatingadmissionpolicy => policy}/internal/generic/informer.go (79%) rename vendor/k8s.io/apiserver/pkg/admission/plugin/{validatingadmissionpolicy => policy}/internal/generic/interface.go (100%) rename vendor/k8s.io/apiserver/pkg/admission/plugin/{validatingadmissionpolicy => policy}/internal/generic/lister.go (100%) rename vendor/k8s.io/apiserver/pkg/admission/plugin/{validatingadmissionpolicy => policy}/matching/matching.go (94%) create mode 100644 vendor/k8s.io/apiserver/pkg/admission/plugin/policy/validating/accessor.go rename vendor/k8s.io/apiserver/pkg/admission/plugin/{validatingadmissionpolicy => policy/validating}/caching_authorizer.go (72%) rename vendor/k8s.io/apiserver/pkg/admission/plugin/{validatingadmissionpolicy/controller.go => policy/validating/dispatcher.go} (50%) create mode 100644 vendor/k8s.io/apiserver/pkg/admission/plugin/policy/validating/errors.go rename vendor/k8s.io/apiserver/pkg/admission/plugin/{validatingadmissionpolicy => policy/validating}/initializer.go (96%) rename vendor/k8s.io/apiserver/pkg/admission/plugin/{validatingadmissionpolicy => policy/validating}/interface.go (75%) rename vendor/k8s.io/apiserver/pkg/admission/plugin/{validatingadmissionpolicy => policy/validating}/message.go (96%) rename vendor/k8s.io/{code-generator/cmd/client-gen/path/path.go => apiserver/pkg/admission/plugin/policy/validating/metrics/errors.go} (51%) rename vendor/k8s.io/apiserver/pkg/admission/{cel => plugin/policy/validating/metrics}/metrics.go (62%) create mode 100644 vendor/k8s.io/apiserver/pkg/admission/plugin/policy/validating/plugin.go rename vendor/k8s.io/apiserver/pkg/admission/plugin/{validatingadmissionpolicy => policy/validating}/policy_decision.go (98%) rename vendor/k8s.io/apiserver/pkg/admission/plugin/{validatingadmissionpolicy => policy/validating}/typechecking.go (73%) rename vendor/k8s.io/apiserver/pkg/admission/plugin/{validatingadmissionpolicy => policy/validating}/validator.go (96%) delete mode 100644 vendor/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/OWNERS delete mode 100644 vendor/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/admission.go delete mode 100644 vendor/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/controller_reconcile.go create mode 100644 vendor/k8s.io/apiserver/pkg/apis/apidiscovery/v2/conversion.go rename vendor/k8s.io/apiserver/pkg/apis/{config => apidiscovery/v2}/doc.go (79%) create mode 100644 vendor/k8s.io/apiserver/pkg/apis/apidiscovery/v2/register.go rename vendor/k8s.io/apiserver/pkg/apis/{config/types.go => apiserver/types_encryption.go} (99%) rename vendor/k8s.io/apiserver/pkg/apis/{config => apiserver}/v1/defaults.go (100%) rename vendor/k8s.io/apiserver/pkg/apis/{config/v1/types.go => apiserver/v1/types_encryption.go} (100%) create mode 100644 vendor/k8s.io/apiserver/pkg/apis/apiserver/v1beta1/defaults.go rename vendor/k8s.io/apiserver/pkg/apis/{config/validation/validation.go => apiserver/validation/validation_encryption.go} (91%) delete mode 100644 vendor/k8s.io/apiserver/pkg/apis/config/v1/zz_generated.conversion.go delete mode 100644 vendor/k8s.io/apiserver/pkg/apis/config/v1/zz_generated.deepcopy.go delete mode 100644 vendor/k8s.io/apiserver/pkg/apis/config/v1/zz_generated.defaults.go delete mode 100644 vendor/k8s.io/apiserver/pkg/apis/config/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/apiserver/pkg/authorization/cel/metrics.go create mode 100644 vendor/k8s.io/apiserver/pkg/cel/cidr.go create mode 100644 vendor/k8s.io/apiserver/pkg/cel/format.go create mode 100644 vendor/k8s.io/apiserver/pkg/cel/ip.go create mode 100644 vendor/k8s.io/apiserver/pkg/cel/library/cidr.go create mode 100644 vendor/k8s.io/apiserver/pkg/cel/library/format.go create mode 100644 vendor/k8s.io/apiserver/pkg/cel/library/ip.go delete mode 100644 vendor/k8s.io/apiserver/pkg/server/options/deprecated_insecure_serving.go create mode 100644 vendor/k8s.io/apiserver/pkg/server/routine/routine.go create mode 100644 vendor/k8s.io/apiserver/pkg/server/storage_readiness_hook.go create mode 100644 vendor/k8s.io/apiserver/pkg/storage/feature/feature_support_checker.go create mode 100644 vendor/k8s.io/apiserver/pkg/util/version/registry.go create mode 100644 vendor/k8s.io/apiserver/pkg/util/version/version.go delete mode 100644 vendor/k8s.io/apiserver/plugin/pkg/authorizer/webhook/metrics.go create mode 100644 vendor/k8s.io/apiserver/plugin/pkg/authorizer/webhook/metrics/metrics.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/OWNERS create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/auditannotation.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/expressionwarning.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/matchresources.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/namedrulewithoperations.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/paramkind.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/paramref.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/typechecking.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/validatingadmissionpolicy.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/validatingadmissionpolicybinding.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/validatingadmissionpolicybindingspec.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/validatingadmissionpolicyspec.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/validatingadmissionpolicystatus.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/validation.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/variable.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/batch/v1/successpolicy.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/batch/v1/successpolicyrule.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/coordination/v1alpha1/leasecandidate.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/coordination/v1alpha1/leasecandidatespec.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/core/v1/apparmorprofile.go delete mode 100644 vendor/k8s.io/client-go/applyconfigurations/core/v1/claimsource.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/core/v1/containeruser.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/core/v1/imagevolumesource.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/core/v1/linuxcontaineruser.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/core/v1/nodefeatures.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/core/v1/noderuntimehandler.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/core/v1/noderuntimehandlerfeatures.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/core/v1/resourcehealth.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/core/v1/resourcestatus.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/core/v1/volumemountstatus.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/doc.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/imagepolicy/v1alpha1/imagereview.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/imagepolicy/v1alpha1/imagereviewcontainerspec.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/imagepolicy/v1alpha1/imagereviewspec.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/imagepolicy/v1alpha1/imagereviewstatus.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/networking/v1beta1/ipaddress.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/networking/v1beta1/ipaddressspec.go rename vendor/k8s.io/client-go/applyconfigurations/{resource/v1alpha2/resourceclassparametersreference.go => networking/v1beta1/parentreference.go} (51%) create mode 100644 vendor/k8s.io/client-go/applyconfigurations/networking/v1beta1/servicecidr.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/networking/v1beta1/servicecidrspec.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/networking/v1beta1/servicecidrstatus.go delete mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha2/allocationresult.go delete mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha2/resourceclaimparametersreference.go delete mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha2/resourceclaimspec.go delete mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha2/resourcehandle.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha3/allocationresult.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha3/basicdevice.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha3/celdeviceselector.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha3/device.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha3/deviceallocationconfiguration.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha3/deviceallocationresult.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha3/deviceattribute.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha3/deviceclaim.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha3/deviceclaimconfiguration.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha3/deviceclass.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha3/deviceclassconfiguration.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha3/deviceclassspec.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha3/deviceconfiguration.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha3/deviceconstraint.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha3/devicerequest.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha3/devicerequestallocationresult.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha3/deviceselector.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha3/opaquedeviceconfiguration.go rename vendor/k8s.io/client-go/applyconfigurations/resource/{v1alpha2 => v1alpha3}/podschedulingcontext.go (93%) rename vendor/k8s.io/client-go/applyconfigurations/resource/{v1alpha2 => v1alpha3}/podschedulingcontextspec.go (87%) rename vendor/k8s.io/client-go/applyconfigurations/resource/{v1alpha2 => v1alpha3}/podschedulingcontextstatus.go (84%) rename vendor/k8s.io/client-go/applyconfigurations/resource/{v1alpha2 => v1alpha3}/resourceclaim.go (93%) rename vendor/k8s.io/client-go/applyconfigurations/resource/{v1alpha2 => v1alpha3}/resourceclaimconsumerreference.go (94%) rename vendor/k8s.io/client-go/applyconfigurations/resource/{v1alpha2 => v1alpha3}/resourceclaimschedulingstatus.go (86%) create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha3/resourceclaimspec.go rename vendor/k8s.io/client-go/applyconfigurations/resource/{v1alpha2 => v1alpha3}/resourceclaimstatus.go (77%) rename vendor/k8s.io/client-go/applyconfigurations/resource/{v1alpha2 => v1alpha3}/resourceclaimtemplate.go (93%) rename vendor/k8s.io/client-go/applyconfigurations/resource/{v1alpha2 => v1alpha3}/resourceclaimtemplatespec.go (94%) create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha3/resourcepool.go rename vendor/k8s.io/client-go/applyconfigurations/resource/{v1alpha2/resourceclass.go => v1alpha3/resourceslice.go} (61%) create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha3/resourceslicespec.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/storage/v1beta1/volumeattributesclass.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/storagemigration/v1alpha1/groupversionresource.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/storagemigration/v1alpha1/migrationcondition.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/storagemigration/v1alpha1/storageversionmigration.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/storagemigration/v1alpha1/storageversionmigrationspec.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/storagemigration/v1alpha1/storageversionmigrationstatus.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/utils.go create mode 100644 vendor/k8s.io/client-go/dynamic/fake/simple.go create mode 100644 vendor/k8s.io/client-go/features/envvar.go create mode 100644 vendor/k8s.io/client-go/features/features.go create mode 100644 vendor/k8s.io/client-go/features/known_features.go create mode 100644 vendor/k8s.io/client-go/gentype/type.go create mode 100644 vendor/k8s.io/client-go/informers/admissionregistration/v1/validatingadmissionpolicy.go create mode 100644 vendor/k8s.io/client-go/informers/admissionregistration/v1/validatingadmissionpolicybinding.go create mode 100644 vendor/k8s.io/client-go/informers/coordination/v1alpha1/interface.go create mode 100644 vendor/k8s.io/client-go/informers/coordination/v1alpha1/leasecandidate.go create mode 100644 vendor/k8s.io/client-go/informers/networking/v1beta1/ipaddress.go create mode 100644 vendor/k8s.io/client-go/informers/networking/v1beta1/servicecidr.go create mode 100644 vendor/k8s.io/client-go/informers/resource/v1alpha3/deviceclass.go rename vendor/k8s.io/client-go/informers/resource/{v1alpha2 => v1alpha3}/interface.go (80%) rename vendor/k8s.io/client-go/informers/resource/{v1alpha2 => v1alpha3}/podschedulingcontext.go (86%) rename vendor/k8s.io/client-go/informers/resource/{v1alpha2 => v1alpha3}/resourceclaim.go (85%) rename vendor/k8s.io/client-go/informers/resource/{v1alpha2 => v1alpha3}/resourceclaimtemplate.go (86%) rename vendor/k8s.io/client-go/informers/resource/{v1alpha2/resourceclass.go => v1alpha3/resourceslice.go} (64%) create mode 100644 vendor/k8s.io/client-go/informers/storage/v1beta1/volumeattributesclass.go create mode 100644 vendor/k8s.io/client-go/informers/storagemigration/interface.go create mode 100644 vendor/k8s.io/client-go/informers/storagemigration/v1alpha1/interface.go create mode 100644 vendor/k8s.io/client-go/informers/storagemigration/v1alpha1/storageversionmigration.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1/fake/fake_validatingadmissionpolicy.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1/fake/fake_validatingadmissionpolicybinding.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1/validatingadmissionpolicy.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1/validatingadmissionpolicybinding.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/coordination/v1alpha1/coordination_client.go rename vendor/k8s.io/client-go/kubernetes/typed/{resource/v1alpha2 => coordination/v1alpha1}/doc.go (97%) rename vendor/k8s.io/client-go/kubernetes/typed/{resource/v1alpha2 => coordination/v1alpha1}/fake/doc.go (100%) create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/coordination/v1alpha1/fake/fake_coordination_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/coordination/v1alpha1/fake/fake_leasecandidate.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/coordination/v1alpha1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/coordination/v1alpha1/leasecandidate.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1beta1/fake/fake_ipaddress.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1beta1/fake/fake_servicecidr.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1beta1/ipaddress.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1beta1/servicecidr.go delete mode 100644 vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha2/fake/fake_resourceclass.go delete mode 100644 vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha2/podschedulingcontext.go delete mode 100644 vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha2/resourceclaim.go delete mode 100644 vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha2/resourceclaimtemplate.go delete mode 100644 vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha2/resourceclass.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha3/deviceclass.go rename vendor/{sigs.k8s.io/controller-runtime/pkg/config => k8s.io/client-go/kubernetes/typed/resource/v1alpha3}/doc.go (76%) create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha3/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha3/fake/fake_deviceclass.go rename vendor/k8s.io/client-go/kubernetes/typed/resource/{v1alpha2 => v1alpha3}/fake/fake_podschedulingcontext.go (56%) rename vendor/k8s.io/client-go/kubernetes/typed/resource/{v1alpha2 => v1alpha3}/fake/fake_resource_client.go (59%) rename vendor/k8s.io/client-go/kubernetes/typed/resource/{v1alpha2 => v1alpha3}/fake/fake_resourceclaim.go (57%) rename vendor/k8s.io/client-go/kubernetes/typed/resource/{v1alpha2 => v1alpha3}/fake/fake_resourceclaimtemplate.go (58%) create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha3/fake/fake_resourceslice.go rename vendor/k8s.io/client-go/kubernetes/typed/resource/{v1alpha2 => v1alpha3}/generated_expansion.go (88%) create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha3/podschedulingcontext.go rename vendor/k8s.io/client-go/kubernetes/typed/resource/{v1alpha2 => v1alpha3}/resource_client.go (65%) create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha3/resourceclaim.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha3/resourceclaimtemplate.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha3/resourceslice.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_volumeattributesclass.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1beta1/volumeattributesclass.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storagemigration/v1alpha1/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storagemigration/v1alpha1/fake/doc.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storagemigration/v1alpha1/fake/fake_storagemigration_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storagemigration/v1alpha1/fake/fake_storageversionmigration.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storagemigration/v1alpha1/generated_expansion.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storagemigration/v1alpha1/storagemigration_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storagemigration/v1alpha1/storageversionmigration.go create mode 100644 vendor/k8s.io/client-go/listers/admissionregistration/v1/validatingadmissionpolicy.go create mode 100644 vendor/k8s.io/client-go/listers/admissionregistration/v1/validatingadmissionpolicybinding.go create mode 100644 vendor/k8s.io/client-go/listers/coordination/v1alpha1/expansion_generated.go create mode 100644 vendor/k8s.io/client-go/listers/coordination/v1alpha1/leasecandidate.go rename vendor/k8s.io/{gengo/parser => client-go/listers}/doc.go (75%) create mode 100644 vendor/k8s.io/client-go/listers/generic_helpers.go create mode 100644 vendor/k8s.io/client-go/listers/networking/v1beta1/ipaddress.go create mode 100644 vendor/k8s.io/client-go/listers/networking/v1beta1/servicecidr.go delete mode 100644 vendor/k8s.io/client-go/listers/resource/v1alpha2/resourceclass.go create mode 100644 vendor/k8s.io/client-go/listers/resource/v1alpha3/deviceclass.go rename vendor/k8s.io/client-go/listers/resource/{v1alpha2 => v1alpha3}/expansion_generated.go (85%) rename vendor/k8s.io/client-go/listers/resource/{v1alpha2 => v1alpha3}/podschedulingcontext.go (59%) rename vendor/k8s.io/client-go/listers/resource/{v1alpha2 => v1alpha3}/resourceclaim.go (58%) rename vendor/k8s.io/client-go/listers/resource/{v1alpha2 => v1alpha3}/resourceclaimtemplate.go (59%) create mode 100644 vendor/k8s.io/client-go/listers/resource/v1alpha3/resourceslice.go create mode 100644 vendor/k8s.io/client-go/listers/storage/v1beta1/volumeattributesclass.go create mode 100644 vendor/k8s.io/client-go/listers/storagemigration/v1alpha1/expansion_generated.go create mode 100644 vendor/k8s.io/client-go/listers/storagemigration/v1alpha1/storageversionmigration.go create mode 100644 vendor/k8s.io/client-go/tools/leaderelection/leasecandidate.go create mode 100644 vendor/k8s.io/client-go/tools/remotecommand/OWNERS create mode 100644 vendor/k8s.io/client-go/util/consistencydetector/data_consistency_detector.go create mode 100644 vendor/k8s.io/client-go/util/consistencydetector/list_data_consistency_detector.go create mode 100644 vendor/k8s.io/client-go/util/consistencydetector/watch_list_data_consistency_detector.go create mode 100644 vendor/k8s.io/client-go/util/watchlist/watch_list.go rename vendor/k8s.io/code-generator/cmd/applyconfiguration-gen/generators/{packages.go => targets.go} (62%) rename vendor/k8s.io/{gengo/examples => code-generator/cmd}/deepcopy-gen/generators/deepcopy.go (87%) rename vendor/k8s.io/{gengo/examples => code-generator/cmd}/defaulter-gen/generators/defaulter.go (90%) delete mode 100644 vendor/k8s.io/code-generator/cmd/import-boss/.gitignore delete mode 100644 vendor/k8s.io/code-generator/cmd/import-boss/README.md delete mode 100644 vendor/k8s.io/code-generator/cmd/import-boss/main.go rename vendor/k8s.io/code-generator/cmd/informer-gen/generators/{packages.go => targets.go} (56%) rename vendor/k8s.io/code-generator/cmd/register-gen/generators/{packages.go => targets.go} (74%) delete mode 100644 vendor/k8s.io/code-generator/cmd/set-gen/.gitignore delete mode 100644 vendor/k8s.io/code-generator/cmd/set-gen/main.go delete mode 100644 vendor/k8s.io/code-generator/pkg/util/build.go create mode 100644 vendor/k8s.io/component-base/logs/api/v1/options_no_slog.go create mode 100644 vendor/k8s.io/component-base/logs/api/v1/options_slog.go create mode 100644 vendor/k8s.io/component-base/logs/api/v1/text.go delete mode 100644 vendor/k8s.io/gengo/LICENSE delete mode 100644 vendor/k8s.io/gengo/args/args.go delete mode 100644 vendor/k8s.io/gengo/examples/import-boss/generators/import_restrict.go delete mode 100644 vendor/k8s.io/gengo/examples/set-gen/generators/sets.go delete mode 100644 vendor/k8s.io/gengo/generator/default_generator.go delete mode 100644 vendor/k8s.io/gengo/generator/default_package.go delete mode 100644 vendor/k8s.io/gengo/generator/doc.go delete mode 100644 vendor/k8s.io/gengo/generator/error_tracker.go delete mode 100644 vendor/k8s.io/gengo/generator/execute.go delete mode 100644 vendor/k8s.io/gengo/generator/generator.go delete mode 100644 vendor/k8s.io/gengo/generator/import_tracker.go delete mode 100644 vendor/k8s.io/gengo/generator/snippet_writer.go delete mode 100644 vendor/k8s.io/gengo/generator/transitive_closure.go delete mode 100644 vendor/k8s.io/gengo/namer/doc.go delete mode 100644 vendor/k8s.io/gengo/namer/import_tracker.go delete mode 100644 vendor/k8s.io/gengo/namer/namer.go delete mode 100644 vendor/k8s.io/gengo/namer/order.go delete mode 100644 vendor/k8s.io/gengo/namer/plural_namer.go delete mode 100644 vendor/k8s.io/gengo/parser/parse.go delete mode 100644 vendor/k8s.io/gengo/types/comments.go delete mode 100644 vendor/k8s.io/gengo/types/doc.go delete mode 100644 vendor/k8s.io/gengo/types/flatten.go delete mode 100644 vendor/k8s.io/gengo/types/types.go create mode 100644 vendor/k8s.io/klog/v2/internal/verbosity/verbosity.go create mode 100644 vendor/k8s.io/klog/v2/textlogger/options.go create mode 100644 vendor/k8s.io/klog/v2/textlogger/textlogger.go create mode 100644 vendor/k8s.io/klog/v2/textlogger/textlogger_slog.go rename vendor/k8s.io/{code-generator/cmd/openapi-gen/main.go => kube-openapi/cmd/openapi-gen/openapi-gen.go} (78%) delete mode 100644 vendor/k8s.io/utils/integer/integer.go create mode 100644 vendor/k8s.io/utils/net/multi_listen.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/.gomodcheck.yaml create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/fieldvalidation.go delete mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/config/config.go delete mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/doc.go delete mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/register.go delete mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/types.go delete mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/zz_generated.deepcopy.go rename vendor/sigs.k8s.io/controller-runtime/pkg/{ratelimiter/doc.go => controller/name.go} (53%) delete mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/ratelimiter/ratelimiter.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/metrics/metrics.go rename vendor/sigs.k8s.io/kustomize/api/{ => internal}/image/image.go (100%) rename vendor/sigs.k8s.io/kustomize/api/{ => internal}/konfig/builtinpluginconsts/commonannotations.go (100%) rename vendor/sigs.k8s.io/kustomize/api/{ => internal}/konfig/builtinpluginconsts/commonlabels.go (100%) rename vendor/sigs.k8s.io/kustomize/api/{ => internal}/konfig/builtinpluginconsts/defaultconfig.go (100%) rename vendor/sigs.k8s.io/kustomize/api/{ => internal}/konfig/builtinpluginconsts/doc.go (100%) rename vendor/sigs.k8s.io/kustomize/api/{ => internal}/konfig/builtinpluginconsts/images.go (100%) rename vendor/sigs.k8s.io/kustomize/api/{ => internal}/konfig/builtinpluginconsts/metadatalabels.go (100%) rename vendor/sigs.k8s.io/kustomize/api/{ => internal}/konfig/builtinpluginconsts/nameprefix.go (100%) rename vendor/sigs.k8s.io/kustomize/api/{ => internal}/konfig/builtinpluginconsts/namereference.go (98%) rename vendor/sigs.k8s.io/kustomize/api/{ => internal}/konfig/builtinpluginconsts/namespace.go (100%) rename vendor/sigs.k8s.io/kustomize/api/{ => internal}/konfig/builtinpluginconsts/namesuffix.go (100%) rename vendor/sigs.k8s.io/kustomize/api/{ => internal}/konfig/builtinpluginconsts/replicas.go (100%) rename vendor/sigs.k8s.io/kustomize/api/{ => internal}/konfig/builtinpluginconsts/templatelabels.go (100%) rename vendor/sigs.k8s.io/kustomize/api/{ => internal}/konfig/builtinpluginconsts/varreference.go (100%) rename vendor/sigs.k8s.io/kustomize/api/{ => internal}/loader/errors.go (100%) rename vendor/sigs.k8s.io/kustomize/api/{ => internal}/loader/fileloader.go (75%) rename vendor/sigs.k8s.io/kustomize/api/{ => internal}/loader/loader.go (100%) rename vendor/sigs.k8s.io/kustomize/api/{ => internal}/loader/loadrestrictions.go (100%) create mode 100644 vendor/sigs.k8s.io/kustomize/api/internal/plugins/loader/load_go_plugin.go create mode 100644 vendor/sigs.k8s.io/kustomize/api/internal/plugins/loader/load_go_plugin_disabled.go rename vendor/sigs.k8s.io/{kustomize/kyaml/internal/forked/github.com/go-yaml/yaml => yaml/goyaml.v3}/LICENSE (100%) rename vendor/sigs.k8s.io/{kustomize/kyaml/internal/forked/github.com/go-yaml/yaml => yaml/goyaml.v3}/NOTICE (100%) create mode 100644 vendor/sigs.k8s.io/yaml/goyaml.v3/OWNERS rename vendor/sigs.k8s.io/{kustomize/kyaml/internal/forked/github.com/go-yaml/yaml => yaml/goyaml.v3}/README.md (87%) rename vendor/sigs.k8s.io/{kustomize/kyaml/internal/forked/github.com/go-yaml/yaml => yaml/goyaml.v3}/apic.go (100%) rename vendor/sigs.k8s.io/{kustomize/kyaml/internal/forked/github.com/go-yaml/yaml => yaml/goyaml.v3}/decode.go (100%) rename vendor/sigs.k8s.io/{kustomize/kyaml/internal/forked/github.com/go-yaml/yaml => yaml/goyaml.v3}/emitterc.go (95%) rename vendor/sigs.k8s.io/{kustomize/kyaml/internal/forked/github.com/go-yaml/yaml => yaml/goyaml.v3}/encode.go (100%) rename vendor/sigs.k8s.io/{kustomize/kyaml/internal/forked/github.com/go-yaml/yaml => yaml/goyaml.v3}/parserc.go (100%) create mode 100644 vendor/sigs.k8s.io/yaml/goyaml.v3/patch.go rename vendor/sigs.k8s.io/{kustomize/kyaml/internal/forked/github.com/go-yaml/yaml => yaml/goyaml.v3}/readerc.go (100%) rename vendor/sigs.k8s.io/{kustomize/kyaml/internal/forked/github.com/go-yaml/yaml => yaml/goyaml.v3}/resolve.go (100%) rename vendor/sigs.k8s.io/{kustomize/kyaml/internal/forked/github.com/go-yaml/yaml => yaml/goyaml.v3}/scannerc.go (100%) rename vendor/sigs.k8s.io/{kustomize/kyaml/internal/forked/github.com/go-yaml/yaml => yaml/goyaml.v3}/sorter.go (100%) rename vendor/sigs.k8s.io/{kustomize/kyaml/internal/forked/github.com/go-yaml/yaml => yaml/goyaml.v3}/writerc.go (100%) rename vendor/sigs.k8s.io/{kustomize/kyaml/internal/forked/github.com/go-yaml/yaml => yaml/goyaml.v3}/yaml.go (98%) rename vendor/sigs.k8s.io/{kustomize/kyaml/internal/forked/github.com/go-yaml/yaml => yaml/goyaml.v3}/yamlh.go (100%) rename vendor/sigs.k8s.io/{kustomize/kyaml/internal/forked/github.com/go-yaml/yaml => yaml/goyaml.v3}/yamlprivateh.go (100%) diff --git a/Makefile b/Makefile index 534e6584f0..bbf7b090d5 100644 --- a/Makefile +++ b/Makefile @@ -122,7 +122,7 @@ update-helm: manifests yq .PHONY: generate generate: gomod-download controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations and client-go libraries. $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./apis/..." - ./hack/update-codegen.sh $(GO_CMD) + TOOLS_DIR=${TOOLS_DIR} ./hack/update-codegen.sh $(GO_CMD) .PHONY: fmt fmt: ## Run go fmt against code. diff --git a/Makefile-test.mk b/Makefile-test.mk index 261a51c415..933255bed4 100644 --- a/Makefile-test.mk +++ b/Makefile-test.mk @@ -27,7 +27,7 @@ LD_FLAGS += -X '$(version_pkg).GitVersion=$(GIT_TAG)' LD_FLAGS += -X '$(version_pkg).GitCommit=$(shell git rev-parse HEAD)' # ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. -ENVTEST_K8S_VERSION ?= 1.30 +ENVTEST_K8S_VERSION ?= 1.31 # Number of processes to use during integration tests to run specs within a # suite in parallel. Suites still run sequentially. User may set this value to 1 @@ -41,9 +41,9 @@ INTEGRATION_API_LOG_LEVEL ?= 0 # Folder where the e2e tests are located. E2E_TARGET ?= ./test/e2e/... -E2E_KIND_VERSION ?= kindest/node:v1.30.0 +E2E_KIND_VERSION ?= kindest/node:v1.31.0 # E2E_K8S_VERSIONS sets the list of k8s versions included in test-e2e-all -E2E_K8S_VERSIONS ?= 1.28.9 1.29.4 1.30.0 +E2E_K8S_VERSIONS ?= 1.28.13 1.29.8 1.30.4 1.31.0 # For local testing, we should allow user to use different kind cluster name # Default will delete default kind cluster diff --git a/apis/visibility/v1alpha1/openapi/zz_generated.openapi.go b/apis/visibility/v1alpha1/openapi/zz_generated.openapi.go index 69a5e0e6b7..c0599621e5 100644 --- a/apis/visibility/v1alpha1/openapi/zz_generated.openapi.go +++ b/apis/visibility/v1alpha1/openapi/zz_generated.openapi.go @@ -18,8 +18,6 @@ limitations under the License. */ // Code generated by openapi-gen. DO NOT EDIT. -// This file was autogenerated by openapi-gen. Do not edit it manually! - package openapi import ( @@ -40,6 +38,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "k8s.io/apimachinery/pkg/apis/meta/v1.CreateOptions": schema_pkg_apis_meta_v1_CreateOptions(ref), "k8s.io/apimachinery/pkg/apis/meta/v1.DeleteOptions": schema_pkg_apis_meta_v1_DeleteOptions(ref), "k8s.io/apimachinery/pkg/apis/meta/v1.Duration": schema_pkg_apis_meta_v1_Duration(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.FieldSelectorRequirement": schema_pkg_apis_meta_v1_FieldSelectorRequirement(ref), "k8s.io/apimachinery/pkg/apis/meta/v1.FieldsV1": schema_pkg_apis_meta_v1_FieldsV1(ref), "k8s.io/apimachinery/pkg/apis/meta/v1.GetOptions": schema_pkg_apis_meta_v1_GetOptions(ref), "k8s.io/apimachinery/pkg/apis/meta/v1.GroupKind": schema_pkg_apis_meta_v1_GroupKind(ref), @@ -746,6 +745,56 @@ func schema_pkg_apis_meta_v1_Duration(ref common.ReferenceCallback) common.OpenA } } +func schema_pkg_apis_meta_v1_FieldSelectorRequirement(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "FieldSelectorRequirement is a selector that contains values, a key, and an operator that relates the key and values.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "key": { + SchemaProps: spec.SchemaProps{ + Description: "key is the field selector key that the requirement applies to.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "operator": { + SchemaProps: spec.SchemaProps{ + Description: "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. The list of operators may grow in the future.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "values": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + Required: []string{"key", "operator"}, + }, + }, + } +} + func schema_pkg_apis_meta_v1_FieldsV1(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/charts/kueue/templates/crd/kueue.x-k8s.io_admissionchecks.yaml b/charts/kueue/templates/crd/kueue.x-k8s.io_admissionchecks.yaml index 2663dfc25a..de8d0e83a8 100644 --- a/charts/kueue/templates/crd/kueue.x-k8s.io_admissionchecks.yaml +++ b/charts/kueue/templates/crd/kueue.x-k8s.io_admissionchecks.yaml @@ -8,7 +8,7 @@ metadata: {{- if .Values.enableCertManager }} cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "kueue.fullname" . }}-serving-cert {{- end }} - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.16.1 name: admissionchecks.kueue.x-k8s.io spec: conversion: @@ -107,16 +107,8 @@ spec: conditions hold the latest available observations of the AdmissionCheck current state. 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}" + description: Condition contains details for one aspect of the current + state of this API Resource. properties: lastTransitionTime: description: |- @@ -157,12 +149,7 @@ spec: - 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) + description: type of condition in CamelCase or in foo.example.com/CamelCase. 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 diff --git a/charts/kueue/templates/crd/kueue.x-k8s.io_clusterqueues.yaml b/charts/kueue/templates/crd/kueue.x-k8s.io_clusterqueues.yaml index 81be518e27..ccf055ed52 100644 --- a/charts/kueue/templates/crd/kueue.x-k8s.io_clusterqueues.yaml +++ b/charts/kueue/templates/crd/kueue.x-k8s.io_clusterqueues.yaml @@ -8,7 +8,7 @@ metadata: {{- if .Values.enableCertManager }} cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "kueue.fullname" . }}-serving-cert {{- end }} - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.16.1 name: clusterqueues.kueue.x-k8s.io spec: conversion: @@ -117,7 +117,6 @@ spec: cohort that this ClusterQueue belongs to. CQs that belong to the same cohort can borrow unused resources from each other. - A CQ can be a member of a single borrowing cohort. A workload submitted to a queue referencing this CQ can borrow quota from any CQ in the cohort. Only quota for the [resource, flavor] pairs listed in the CQ can be @@ -125,11 +124,9 @@ spec: If empty, this ClusterQueue cannot borrow from any other ClusterQueue and vice versa. - A cohort is a name that links CQs together, but it doesn't reference any object. - Validation of a cohort name is equivalent to that of object names: subdomain in DNS (RFC 1123). maxLength: 253 @@ -169,7 +166,6 @@ spec: whenCanBorrow determines whether a workload should try the next flavor before borrowing in current flavor. The possible values are: - - `Borrow` (default): allocate in current flavor if borrowing is possible. - `TryNextFlavor`: try next flavor even if the current @@ -184,7 +180,6 @@ spec: whenCanPreempt determines whether a workload should try the next flavor before borrowing in current flavor. The possible values are: - - `Preempt`: allocate in current flavor if it's possible to preempt some workloads. - `TryNextFlavor` (default): try next flavor even if there are enough candidates for preemption in the current flavor. @@ -250,10 +245,8 @@ spec: preemption describes policies to preempt Workloads from this ClusterQueue or the ClusterQueue's cohort. - Preemption can happen in two scenarios: - - When a Workload fits within the nominal quota of the ClusterQueue, but the quota is currently borrowed by other ClusterQueues in the cohort. Preempting Workloads in other ClusterQueues allows this ClusterQueue to @@ -261,7 +254,6 @@ spec: - When a Workload doesn't fit within the nominal quota of the ClusterQueue and there are admitted Workloads in the ClusterQueue with lower priority. - The preemption algorithm tries to find a minimal set of Workloads to preempt to accomomdate the pending Workload, preempting Workloads with lower priority first. @@ -303,7 +295,6 @@ spec: Workloads from other ClusterQueues in the cohort that are using more than their nominal quota. The possible values are: - - `Never` (default): do not preempt Workloads in the cohort. - `LowerPriority`: if the pending Workload fits within the nominal quota of its ClusterQueue, only preempt Workloads in the cohort that have @@ -323,7 +314,6 @@ spec: within the nominal quota for its ClusterQueue, can preempt active Workloads in the ClusterQueue. The possible values are: - - `Never` (default): do not preempt Workloads in the ClusterQueue. - `LowerPriority`: only preempt Workloads in the ClusterQueue that have lower priority than the pending Workload. @@ -347,7 +337,6 @@ spec: across the queues in this ClusterQueue. Current Supported Strategies: - - StrictFIFO: workloads are ordered strictly by creation time. Older workloads that can't be admitted will block admitting newer workloads even if they fit available quota. @@ -454,7 +443,6 @@ spec: 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. @@ -497,10 +485,8 @@ spec: stopPolicy - if set to a value different from None, the ClusterQueue is considered Inactive, no new reservation being made. - Depending on its value, its associated workloads will: - - None - Workloads are admitted - HoldAndDrain - Admitted workloads are evicted and Reserving workloads will cancel the reservation. - Hold - Admitted workloads will run to completion and Reserving workloads will cancel the reservation. @@ -528,16 +514,8 @@ spec: conditions hold the latest available observations of the ClusterQueue current state. 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}" + description: Condition contains details for one aspect of the current + state of this API Resource. properties: lastTransitionTime: description: |- @@ -578,12 +556,7 @@ spec: - 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) + description: type of condition in CamelCase or in foo.example.com/CamelCase. 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 diff --git a/charts/kueue/templates/crd/kueue.x-k8s.io_cohorts.yaml b/charts/kueue/templates/crd/kueue.x-k8s.io_cohorts.yaml index 20353ad668..e82e0f484a 100644 --- a/charts/kueue/templates/crd/kueue.x-k8s.io_cohorts.yaml +++ b/charts/kueue/templates/crd/kueue.x-k8s.io_cohorts.yaml @@ -8,7 +8,7 @@ metadata: {{- if .Values.enableCertManager }} cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "kueue.fullname" . }}-serving-cert {{- end }} - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.16.1 name: cohorts.kueue.x-k8s.io spec: conversion: @@ -62,7 +62,6 @@ spec: 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 @@ -79,15 +78,12 @@ spec: 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. @@ -180,7 +176,6 @@ spec: 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. @@ -223,16 +218,8 @@ spec: 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}" + description: Condition contains details for one aspect of the current + state of this API Resource. properties: lastTransitionTime: description: |- @@ -273,12 +260,7 @@ spec: - 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) + description: type of condition in CamelCase or in foo.example.com/CamelCase. 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 diff --git a/charts/kueue/templates/crd/kueue.x-k8s.io_localqueues.yaml b/charts/kueue/templates/crd/kueue.x-k8s.io_localqueues.yaml index ce39a3f9ae..d719ed8473 100644 --- a/charts/kueue/templates/crd/kueue.x-k8s.io_localqueues.yaml +++ b/charts/kueue/templates/crd/kueue.x-k8s.io_localqueues.yaml @@ -8,7 +8,7 @@ metadata: {{- if .Values.enableCertManager }} cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "kueue.fullname" . }}-serving-cert {{- end }} - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.16.1 name: localqueues.kueue.x-k8s.io spec: conversion: @@ -86,10 +86,8 @@ spec: stopPolicy - if set to a value different from None, the LocalQueue is considered Inactive, no new reservation being made. - Depending on its value, its associated workloads will: - - None - Workloads are admitted - HoldAndDrain - Admitted workloads are evicted and Reserving workloads will cancel the reservation. - Hold - Admitted workloads will run to completion and Reserving workloads will cancel the reservation. @@ -113,16 +111,8 @@ spec: Conditions hold the latest available observations of the LocalQueue current state. 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}" + description: Condition contains details for one aspect of the current + state of this API Resource. properties: lastTransitionTime: description: |- @@ -163,12 +153,7 @@ spec: - 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) + description: type of condition in CamelCase or in foo.example.com/CamelCase. 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 diff --git a/charts/kueue/templates/crd/kueue.x-k8s.io_multikueueclusters.yaml b/charts/kueue/templates/crd/kueue.x-k8s.io_multikueueclusters.yaml index 72466573ad..8334226f79 100644 --- a/charts/kueue/templates/crd/kueue.x-k8s.io_multikueueclusters.yaml +++ b/charts/kueue/templates/crd/kueue.x-k8s.io_multikueueclusters.yaml @@ -8,7 +8,7 @@ metadata: {{- if .Values.enableCertManager }} cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "kueue.fullname" . }}-serving-cert {{- end }} - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.16.1 name: multikueueclusters.kueue.x-k8s.io spec: conversion: @@ -60,7 +60,6 @@ spec: description: |- Location of the KubeConfig. - If LocationType is Secret then Location is the name of the secret inside the namespace in which the kueue controller manager is running. The config should be stored in the "kubeconfig" key. type: string @@ -82,16 +81,8 @@ spec: 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}" + description: Condition contains details for one aspect of the current + state of this API Resource. properties: lastTransitionTime: description: |- @@ -132,12 +123,7 @@ spec: - 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) + description: type of condition in CamelCase or in foo.example.com/CamelCase. 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 diff --git a/charts/kueue/templates/crd/kueue.x-k8s.io_multikueueconfigs.yaml b/charts/kueue/templates/crd/kueue.x-k8s.io_multikueueconfigs.yaml index bb8bef3e48..779a118e3e 100644 --- a/charts/kueue/templates/crd/kueue.x-k8s.io_multikueueconfigs.yaml +++ b/charts/kueue/templates/crd/kueue.x-k8s.io_multikueueconfigs.yaml @@ -8,7 +8,7 @@ metadata: {{- if .Values.enableCertManager }} cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "kueue.fullname" . }}-serving-cert {{- end }} - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.16.1 name: multikueueconfigs.kueue.x-k8s.io spec: conversion: diff --git a/charts/kueue/templates/crd/kueue.x-k8s.io_provisioningrequestconfigs.yaml b/charts/kueue/templates/crd/kueue.x-k8s.io_provisioningrequestconfigs.yaml index 4b2c22d34d..f60c309f40 100644 --- a/charts/kueue/templates/crd/kueue.x-k8s.io_provisioningrequestconfigs.yaml +++ b/charts/kueue/templates/crd/kueue.x-k8s.io_provisioningrequestconfigs.yaml @@ -8,7 +8,7 @@ metadata: {{- if .Values.enableCertManager }} cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "kueue.fullname" . }}-serving-cert {{- end }} - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.16.1 name: provisioningrequestconfigs.kueue.x-k8s.io spec: conversion: @@ -60,14 +60,11 @@ spec: description: |- managedResources contains the list of resources managed by the autoscaling. - If empty, all resources are considered managed. - If not empty, the ProvisioningRequest will contain only the podsets that are requesting at least one of them. - If none of the workloads podsets is requesting at least a managed resource, the workload is considered ready. items: diff --git a/charts/kueue/templates/crd/kueue.x-k8s.io_resourceflavors.yaml b/charts/kueue/templates/crd/kueue.x-k8s.io_resourceflavors.yaml index 075e8f3cfc..6b95db7bd9 100644 --- a/charts/kueue/templates/crd/kueue.x-k8s.io_resourceflavors.yaml +++ b/charts/kueue/templates/crd/kueue.x-k8s.io_resourceflavors.yaml @@ -8,7 +8,7 @@ metadata: {{- if .Values.enableCertManager }} cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "kueue.fullname" . }}-serving-cert {{- end }} - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.16.1 name: resourceflavors.kueue.x-k8s.io spec: conversion: @@ -71,7 +71,6 @@ spec: nodeLabels should be injected into the pods of the Workload by the controller that integrates with the Workload object. - nodeLabels can be up to 8 elements. maxProperties: 8 type: object @@ -83,11 +82,9 @@ spec: Workloads' podsets must have tolerations for these nodeTaints in order to get assigned this ResourceFlavor during admission. - An example of a nodeTaint is cloud.provider.com/preemptible="true":NoSchedule - nodeTaints can be up to 8 elements. items: description: |- @@ -129,11 +126,9 @@ spec: tolerations are extra tolerations that will be added to the pods admitted in the quota associated with this resource flavor. - An example of a toleration is cloud.provider.com/preemptible="true":NoSchedule - tolerations can be up to 8 elements. items: description: |- diff --git a/charts/kueue/templates/crd/kueue.x-k8s.io_workloadpriorityclasses.yaml b/charts/kueue/templates/crd/kueue.x-k8s.io_workloadpriorityclasses.yaml index 7e17b420f1..ff65164bc7 100644 --- a/charts/kueue/templates/crd/kueue.x-k8s.io_workloadpriorityclasses.yaml +++ b/charts/kueue/templates/crd/kueue.x-k8s.io_workloadpriorityclasses.yaml @@ -8,7 +8,7 @@ metadata: {{- if .Values.enableCertManager }} cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "kueue.fullname" . }}-serving-cert {{- end }} - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.16.1 name: workloadpriorityclasses.kueue.x-k8s.io spec: conversion: diff --git a/charts/kueue/templates/crd/kueue.x-k8s.io_workloads.yaml b/charts/kueue/templates/crd/kueue.x-k8s.io_workloads.yaml index fcb07466c8..6202d8654a 100644 --- a/charts/kueue/templates/crd/kueue.x-k8s.io_workloads.yaml +++ b/charts/kueue/templates/crd/kueue.x-k8s.io_workloads.yaml @@ -8,7 +8,7 @@ metadata: {{- if .Values.enableCertManager }} cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "kueue.fullname" . }}-serving-cert {{- end }} - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.16.1 name: workloads.kueue.x-k8s.io spec: conversion: @@ -84,11 +84,9 @@ spec: Changing active from true to false will evict any running workloads. Possible values are: - - false: indicates that a workload should never be admitted and evicts running workloads - true: indicates that a workload can be evaluated for admission into it's respective queue. - Defaults to true type: boolean podSets: @@ -110,14 +108,11 @@ spec: minCount is the minimum number of pods for the spec acceptable if the workload supports partial admission. - If not provided, partial admission for the current PodSet is not enabled. - Only one podSet within the workload can use this. - This is an alpha field and requires enabling PartialAdmission feature gate. format: int32 minimum: 1 @@ -132,15 +127,12 @@ spec: description: |- template is the Pod template. - The only allowed fields in template.metadata are labels and annotations. - If requests are omitted for a container or initContainer, they default to the limits if they are explicitly specified for the container or initContainer. - During admission, the rules in nodeSelector and nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution that match the keys in the nodeLabels from the ResourceFlavors considered for this @@ -471,7 +463,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -486,7 +478,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -656,7 +648,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -671,7 +663,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -840,7 +832,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -855,7 +847,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1025,7 +1017,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1040,7 +1032,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1208,9 +1200,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the @@ -1281,9 +1271,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the @@ -1323,9 +1311,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap @@ -1348,9 +1334,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret @@ -1654,11 +1638,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -1871,11 +1855,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -2025,11 +2009,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one @@ -2041,6 +2023,12 @@ spec: the Pod where this field is used. It makes that resource available inside a container. type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string required: - name type: object @@ -2164,7 +2152,7 @@ spec: procMount: description: |- procMount denotes the type of proc mount to use for the containers. - The default is DefaultProcMount which uses the container runtime defaults for + The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. @@ -2246,7 +2234,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -2330,11 +2317,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -2552,10 +2539,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -2563,11 +2548,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -2676,7 +2659,6 @@ spec: removed or restarted. The kubelet may evict a Pod if an ephemeral container causes the Pod to exceed its resource allocation. - To add an ephemeral container, use the ephemeralcontainers subresource of an existing Pod. Ephemeral containers may not be removed or restarted. properties: @@ -2750,9 +2732,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the @@ -2823,9 +2803,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the @@ -2865,9 +2843,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap @@ -2890,9 +2866,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret @@ -3190,11 +3164,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -3397,11 +3371,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -3550,11 +3524,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one @@ -3566,6 +3538,12 @@ spec: the Pod where this field is used. It makes that resource available inside a container. type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string required: - name type: object @@ -3677,7 +3655,7 @@ spec: procMount: description: |- procMount denotes the type of proc mount to use for the containers. - The default is DefaultProcMount which uses the container runtime defaults for + The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. @@ -3759,7 +3737,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -3837,11 +3814,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -3980,7 +3957,6 @@ spec: The ephemeral container will be run in the namespaces (IPC, PID, etc) of this container. If not set then the ephemeral container uses the namespaces configured in the Pod spec. - The container runtime must implement support for this feature. If the runtime does not support namespace targeting then the result of setting this field is undefined. type: string @@ -4069,10 +4045,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -4080,11 +4054,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -4196,9 +4168,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -4295,9 +4265,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the @@ -4368,9 +4336,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the @@ -4410,9 +4376,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap @@ -4435,9 +4399,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret @@ -4741,11 +4703,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -4958,11 +4920,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -5112,11 +5074,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one @@ -5128,6 +5088,12 @@ spec: the Pod where this field is used. It makes that resource available inside a container. type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string required: - name type: object @@ -5251,7 +5217,7 @@ spec: procMount: description: |- procMount denotes the type of proc mount to use for the containers. - The default is DefaultProcMount which uses the container runtime defaults for + The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. @@ -5333,7 +5299,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -5417,11 +5382,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -5639,10 +5604,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -5650,11 +5613,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -5693,9 +5654,11 @@ spec: x-kubernetes-list-type: map nodeName: description: |- - NodeName is a request to schedule this pod onto a specific node. If it is non-empty, - the scheduler simply schedules this pod onto that node, assuming that it fits resource - requirements. + NodeName indicates in which node this pod is scheduled. + If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. + Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. + This field should not be used to express a desire for the pod to be scheduled on a specific node. + https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename type: string nodeSelector: additionalProperties: @@ -5711,11 +5674,9 @@ spec: Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set. - If the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions - If the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC @@ -5730,6 +5691,7 @@ spec: - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups + - spec.securityContext.supplementalGroupsPolicy - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile @@ -5817,15 +5779,16 @@ spec: will be made available to those containers which consume them by name. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. items: description: |- - PodResourceClaim references exactly one ResourceClaim through a ClaimSource. + PodResourceClaim references exactly one ResourceClaim, either directly + or by naming a ResourceClaimTemplate which is then turned into a ResourceClaim + for the pod. + It adds a name to it that uniquely identifies the ResourceClaim inside the Pod. Containers that need access to the ResourceClaim reference it with this name. properties: @@ -5834,33 +5797,32 @@ spec: Name uniquely identifies this resource claim inside the pod. This must be a DNS_LABEL. type: string - source: - description: Source describes where to find the - ResourceClaim. - properties: - resourceClaimName: - description: |- - ResourceClaimName is the name of a ResourceClaim object in the same - namespace as this pod. - type: string - resourceClaimTemplateName: - description: |- - ResourceClaimTemplateName is the name of a ResourceClaimTemplate - object in the same namespace as this pod. + resourceClaimName: + description: |- + ResourceClaimName is the name of a ResourceClaim object in the same + namespace as this pod. + Exactly one of ResourceClaimName and ResourceClaimTemplateName must + be set. + type: string + resourceClaimTemplateName: + description: |- + ResourceClaimTemplateName is the name of a ResourceClaimTemplate + object in the same namespace as this pod. - The template will be used to create a new ResourceClaim, which will - be bound to this pod. When this pod is deleted, the ResourceClaim - will also be deleted. The pod name and resource name, along with a - generated component, will be used to form a unique name for the - ResourceClaim, which will be recorded in pod.status.resourceClaimStatuses. + The template will be used to create a new ResourceClaim, which will + be bound to this pod. When this pod is deleted, the ResourceClaim + will also be deleted. The pod name and resource name, along with a + generated component, will be used to form a unique name for the + ResourceClaim, which will be recorded in pod.status.resourceClaimStatuses. + This field is immutable and no changes will be made to the + corresponding ResourceClaim by the control plane after creating the + ResourceClaim. - This field is immutable and no changes will be made to the - corresponding ResourceClaim by the control plane after creating the - ResourceClaim. - type: string - type: object + Exactly one of ResourceClaimName and ResourceClaimTemplateName must + be set. + type: string required: - name type: object @@ -5894,7 +5856,6 @@ spec: If schedulingGates is not empty, the pod will stay in the SchedulingGated state and the scheduler will not attempt to schedule the pod. - SchedulingGates can only be set at pod creation time, and be removed only afterwards. items: description: PodSchedulingGate is associated to a @@ -5946,12 +5907,10 @@ spec: Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: - 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- - If unset, the Kubelet will not modify the ownership and permissions of any volume. Note that this field cannot be set when spec.os.name is windows. format: int64 @@ -6038,7 +5997,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -6048,18 +6006,28 @@ spec: type: object supplementalGroups: description: |- - A list of groups applied to the first process run in each container, in addition - to the container's primary GID, the fsGroup (if specified), and group memberships - defined in the container image for the uid of the container process. If unspecified, - no additional groups are added to any container. Note that group memberships - defined in the container image for the uid of the container process are still effective, - even if they are not included in this list. + A list of groups applied to the first process run in each container, in + addition to the container's primary GID and fsGroup (if specified). If + the SupplementalGroupsPolicy feature is enabled, the + supplementalGroupsPolicy field determines whether these are in addition + to or instead of any group memberships defined in the container image. + If unspecified, no additional groups are added, though group memberships + defined in the container image may still be used, depending on the + supplementalGroupsPolicy field. Note that this field cannot be set when spec.os.name is windows. items: format: int64 type: integer type: array x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + description: |- + Defines how supplemental groups of the first container processes are calculated. + Valid values are "Merge" and "Strict". If not specified, "Merge" is used. + (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled + and the container runtime must implement support for this feature. + Note that this field cannot be set when spec.os.name is windows. + type: string sysctls: description: |- Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported @@ -6267,7 +6235,6 @@ spec: Keys that don't exist in the incoming pod labels will be ignored. A null or empty list means only match against labelSelector. - This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). items: type: string @@ -6307,7 +6274,6 @@ spec: Valid values are integers greater than 0. When value is not nil, WhenUnsatisfiable must be DoNotSchedule. - For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same labelSelector spread as 2/2/2: | zone1 | zone2 | zone3 | @@ -6325,7 +6291,6 @@ spec: - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. - If this value is nil, the behavior is equivalent to the Honor policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -6337,7 +6302,6 @@ spec: has a toleration, are included. - Ignore: node taints are ignored. All nodes are included. - If this value is nil, the behavior is equivalent to the Ignore policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -6406,7 +6370,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - TODO: how do we prevent errors in the filesystem from compromising the machine type: string partition: description: |- @@ -6447,6 +6410,7 @@ spec: in the blob storage type: string fsType: + default: ext4 description: |- fsType is Filesystem type to mount. Must be a filesystem type supported by the host operating system. @@ -6460,6 +6424,7 @@ spec: availability set). defaults to shared' type: string readOnly: + default: false description: |- readOnly Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. @@ -6531,9 +6496,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -6575,9 +6538,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -6650,9 +6611,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional specify whether the @@ -6691,9 +6650,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -6837,7 +6794,6 @@ spec: The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted when the pod is removed. - Use this if: a) the volume is only needed while the pod runs, b) features of normal volumes like restoring from snapshot or capacity @@ -6848,17 +6804,14 @@ spec: information on the connection between this volume type and PersistentVolumeClaim). - Use PersistentVolumeClaim or one of the vendor-specific APIs for volumes that persist for longer than the lifecycle of an individual pod. - Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to be used that way - see the documentation of the driver for more information. - A pod can use both types of ephemeral volumes and persistent volumes at the same time. properties: @@ -6872,7 +6825,6 @@ spec: entry. Pod validation will reject the pod if the concatenated name is not valid for a PVC (for example, too long). - An existing PVC with that name that is not owned by the pod will *not* be used for the pod to avoid using an unrelated volume by mistake. Starting the pod is then blocked until @@ -6882,11 +6834,9 @@ spec: this should not be necessary, but it may be useful when manually reconstructing a broken cluster. - This field is read-only and no changes will be made by Kubernetes to the PVC after it has been created. - Required, must not be nil. properties: metadata: @@ -7108,7 +7058,7 @@ spec: set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource exists. More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Alpha) Using this field requires the VolumeAttributesClass feature gate to be enabled. + (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). type: string volumeMode: description: |- @@ -7135,7 +7085,6 @@ spec: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - TODO: how do we prevent errors in the filesystem from compromising the machine type: string lun: description: 'lun is Optional: FC target lun @@ -7204,9 +7153,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -7241,7 +7188,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - TODO: how do we prevent errors in the filesystem from compromising the machine type: string partition: description: |- @@ -7322,9 +7268,6 @@ spec: used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - --- - TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not - mount host directories as read/write. properties: path: description: |- @@ -7341,6 +7284,41 @@ spec: required: - path type: object + image: + description: |- + image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine. + The volume is resolved at pod startup depending on which PullPolicy value is provided: + + - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + + The volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation. + A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message. + The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field. + The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images. + The volume will be mounted read-only (ro) and non-executable files (noexec). + Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath). + The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. + properties: + pullPolicy: + description: |- + Policy for pulling OCI objects. Possible values are: + Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + type: string + reference: + description: |- + Required: Image or artifact reference to be used. + Behaves in the same way as pod.spec.containers[*].image. + Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets. + More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management to default or override + container images in workload controllers like Deployments and StatefulSets. + type: string + type: object iscsi: description: |- iscsi represents an ISCSI Disk resource that is attached to a @@ -7361,7 +7339,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi - TODO: how do we prevent errors in the filesystem from compromising the machine type: string initiatorName: description: |- @@ -7374,6 +7351,7 @@ spec: Name. type: string iscsiInterface: + default: default description: |- iscsiInterface is the interface Name that uses an iSCSI transport. Defaults to 'default' (tcp). @@ -7407,9 +7385,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -7529,25 +7505,24 @@ spec: format: int32 type: integer sources: - description: sources is the list of volume - projections + description: |- + sources is the list of volume projections. Each entry in this list + handles one source. items: - description: Projection that may be projected - along with other supported volume types + description: |- + Projection that may be projected along with other supported volume types. + Exactly one of these fields must be set. properties: clusterTrustBundle: description: |- ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field of ClusterTrustBundle objects in an auto-updating file. - Alpha, gated by the ClusterTrustBundleProjection feature gate. - ClusterTrustBundle objects can either be selected by name, or by the combination of signer name and a label selector. - Kubelet performs aggressive normalization of the PEM contents written into the pod filesystem. Esoteric PEM features such as inter-block comments and block headers are stripped. Certificates are deduplicated. @@ -7684,9 +7659,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional specify whether @@ -7835,9 +7808,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional field specify @@ -7929,7 +7900,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd - TODO: how do we prevent errors in the filesystem from compromising the machine type: string image: description: |- @@ -7937,6 +7907,7 @@ spec: More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it type: string keyring: + default: /etc/ceph/keyring description: |- keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. @@ -7951,6 +7922,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd description: |- pool is the rados pool name. Default is rbd. @@ -7976,13 +7948,12 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic user: + default: admin description: |- user is the rados user name. Default is admin. @@ -7997,6 +7968,7 @@ spec: volume attached and mounted on Kubernetes nodes. properties: fsType: + default: xfs description: |- fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. @@ -8029,9 +8001,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -8041,6 +8011,7 @@ spec: false type: boolean storageMode: + default: ThinProvisioned description: |- storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. Default is ThinProvisioned. @@ -8155,9 +8126,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -8327,7 +8296,6 @@ spec: description: |- resourceUsage keeps track of the total resources all the pods in the podset need to run. - Beside what is provided in podSet's specs, this calculation takes into account the LimitRange defaults and RuntimeClass overheads at the moment of admission. This field will not change in case of quota reclaim. @@ -8479,25 +8447,15 @@ spec: conditions hold the latest available observations of the Workload current state. - The type of the condition could be: - - Admitted: the Workload was admitted through a ClusterQueue. - Finished: the associated workload finished running (failed or succeeded). - PodsReady: at least `.spec.podSets[*].count` Pods are ready or have succeeded. 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}" + description: Condition contains details for one aspect of the current + state of this API Resource. properties: lastTransitionTime: description: |- @@ -8538,12 +8496,7 @@ spec: - 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) + description: type of condition in CamelCase or in foo.example.com/CamelCase. 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 diff --git a/charts/kueue/templates/rbac/role.yaml b/charts/kueue/templates/rbac/role.yaml index 41f948e72d..62d4c67056 100644 --- a/charts/kueue/templates/rbac/role.yaml +++ b/charts/kueue/templates/rbac/role.yaml @@ -18,13 +18,6 @@ rules: - "" resources: - limitranges - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - namespaces verbs: - get @@ -79,14 +72,6 @@ rules: - admissionregistration.k8s.io resources: - mutatingwebhookconfigurations - verbs: - - get - - list - - update - - watch - - apiGroups: - - admissionregistration.k8s.io - resources: - validatingwebhookconfigurations verbs: - get @@ -125,13 +110,6 @@ rules: - batch resources: - jobs/finalizers - verbs: - - get - - patch - - update - - apiGroups: - - batch - resources: - jobs/status verbs: - get @@ -141,6 +119,7 @@ rules: - flowcontrol.apiserver.k8s.io resources: - flowschemas + - prioritylevelconfigurations verbs: - list - watch @@ -150,13 +129,6 @@ rules: - flowschemas/status verbs: - patch - - apiGroups: - - flowcontrol.apiserver.k8s.io - resources: - - prioritylevelconfigurations - verbs: - - list - - watch - apiGroups: - jobset.x-k8s.io resources: @@ -186,31 +158,11 @@ rules: - kubeflow.org resources: - mpijobs - verbs: - - get - - list - - patch - - update - - watch - - apiGroups: - - kubeflow.org - resources: - - mpijobs/finalizers - verbs: - - get - - update - - apiGroups: - - kubeflow.org - resources: - - mpijobs/status - verbs: - - get - - patch - - update - - apiGroups: - - kubeflow.org - resources: - mxjobs + - paddlejobs + - pytorchjobs + - tfjobs + - xgboostjobs verbs: - get - list @@ -220,105 +172,12 @@ rules: - apiGroups: - kubeflow.org resources: + - mpijobs/finalizers - mxjobs/finalizers - verbs: - - get - - update - - apiGroups: - - kubeflow.org - resources: - mxjobs/status - verbs: - - get - - update - - apiGroups: - - kubeflow.org - resources: - - paddlejobs - verbs: - - get - - list - - patch - - update - - watch - - apiGroups: - - kubeflow.org - resources: - paddlejobs/finalizers - verbs: - - get - - update - - apiGroups: - - kubeflow.org - resources: - - paddlejobs/status - verbs: - - get - - patch - - update - - apiGroups: - - kubeflow.org - resources: - - pytorchjobs - verbs: - - get - - list - - patch - - update - - watch - - apiGroups: - - kubeflow.org - resources: - pytorchjobs/finalizers - verbs: - - get - - update - - apiGroups: - - kubeflow.org - resources: - - pytorchjobs/status - verbs: - - get - - patch - - update - - apiGroups: - - kubeflow.org - resources: - - tfjobs - verbs: - - get - - list - - patch - - update - - watch - - apiGroups: - - kubeflow.org - resources: - tfjobs/finalizers - verbs: - - get - - update - - apiGroups: - - kubeflow.org - resources: - - tfjobs/status - verbs: - - get - - patch - - update - - apiGroups: - - kubeflow.org - resources: - - xgboostjobs - verbs: - - get - - list - - patch - - update - - watch - - apiGroups: - - kubeflow.org - resources: - xgboostjobs/finalizers verbs: - get @@ -326,6 +185,10 @@ rules: - apiGroups: - kubeflow.org resources: + - mpijobs/status + - paddlejobs/status + - pytorchjobs/status + - tfjobs/status - xgboostjobs/status verbs: - get @@ -335,58 +198,9 @@ rules: - kueue.x-k8s.io resources: - admissionchecks - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - kueue.x-k8s.io - resources: - - admissionchecks/finalizers - verbs: - - update - - apiGroups: - - kueue.x-k8s.io - resources: - - admissionchecks/status - verbs: - - get - - patch - - update - - apiGroups: - - kueue.x-k8s.io - resources: - clusterqueues - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - kueue.x-k8s.io - resources: - - clusterqueues/finalizers - verbs: - - update - - apiGroups: - - kueue.x-k8s.io - resources: - - clusterqueues/status - verbs: - - get - - patch - - update - - apiGroups: - - kueue.x-k8s.io - resources: - localqueues + - workloads verbs: - create - delete @@ -398,29 +212,21 @@ rules: - apiGroups: - kueue.x-k8s.io resources: + - admissionchecks/finalizers + - clusterqueues/finalizers - localqueues/finalizers + - resourceflavors/finalizers + - workloads/finalizers verbs: - update - apiGroups: - kueue.x-k8s.io resources: + - admissionchecks/status + - clusterqueues/status - localqueues/status - verbs: - - get - - patch - - update - - apiGroups: - - kueue.x-k8s.io - resources: - - multikueueclusters - verbs: - - get - - list - - watch - - apiGroups: - - kueue.x-k8s.io - resources: - multikueueclusters/status + - workloads/status verbs: - get - patch @@ -428,38 +234,9 @@ rules: - apiGroups: - kueue.x-k8s.io resources: + - multikueueclusters - multikueueconfigs - verbs: - - get - - list - - watch - - apiGroups: - - kueue.x-k8s.io - resources: - provisioningrequestconfigs - verbs: - - get - - list - - watch - - apiGroups: - - kueue.x-k8s.io - resources: - - resourceflavors - verbs: - - delete - - get - - list - - update - - watch - - apiGroups: - - kueue.x-k8s.io - resources: - - resourceflavors/finalizers - verbs: - - update - - apiGroups: - - kueue.x-k8s.io - resources: - workloadpriorityclasses verbs: - get @@ -468,29 +245,13 @@ rules: - apiGroups: - kueue.x-k8s.io resources: - - workloads + - resourceflavors verbs: - - create - delete - get - list - - patch - update - watch - - apiGroups: - - kueue.x-k8s.io - resources: - - workloads/finalizers - verbs: - - update - - apiGroups: - - kueue.x-k8s.io - resources: - - workloads/status - verbs: - - get - - patch - - update - apiGroups: - node.k8s.io resources: @@ -503,6 +264,7 @@ rules: - ray.io resources: - rayclusters + - rayjobs verbs: - get - list @@ -513,36 +275,8 @@ rules: - ray.io resources: - rayclusters/finalizers - verbs: - - get - - update - - apiGroups: - - ray.io - resources: - rayclusters/status - verbs: - - get - - update - - apiGroups: - - ray.io - resources: - - rayjobs - verbs: - - get - - list - - patch - - update - - watch - - apiGroups: - - ray.io - resources: - rayjobs/finalizers - verbs: - - get - - update - - apiGroups: - - ray.io - resources: - rayjobs/status verbs: - get diff --git a/client-go/applyconfiguration/kueue/v1alpha1/kubeconfig.go b/client-go/applyconfiguration/kueue/v1alpha1/kubeconfig.go index 7a0422c836..fbaef32cc1 100644 --- a/client-go/applyconfiguration/kueue/v1alpha1/kubeconfig.go +++ b/client-go/applyconfiguration/kueue/v1alpha1/kubeconfig.go @@ -21,14 +21,14 @@ import ( v1alpha1 "sigs.k8s.io/kueue/apis/kueue/v1alpha1" ) -// KubeConfigApplyConfiguration represents an declarative configuration of the KubeConfig type for use +// KubeConfigApplyConfiguration represents a declarative configuration of the KubeConfig type for use // with apply. type KubeConfigApplyConfiguration struct { Location *string `json:"location,omitempty"` LocationType *v1alpha1.LocationType `json:"locationType,omitempty"` } -// KubeConfigApplyConfiguration constructs an declarative configuration of the KubeConfig type for use with +// KubeConfigApplyConfiguration constructs a declarative configuration of the KubeConfig type for use with // apply. func KubeConfig() *KubeConfigApplyConfiguration { return &KubeConfigApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1alpha1/multikueuecluster.go b/client-go/applyconfiguration/kueue/v1alpha1/multikueuecluster.go index cd1300384a..cfc1579c66 100644 --- a/client-go/applyconfiguration/kueue/v1alpha1/multikueuecluster.go +++ b/client-go/applyconfiguration/kueue/v1alpha1/multikueuecluster.go @@ -23,7 +23,7 @@ import ( v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) -// MultiKueueClusterApplyConfiguration represents an declarative configuration of the MultiKueueCluster type for use +// MultiKueueClusterApplyConfiguration represents a declarative configuration of the MultiKueueCluster type for use // with apply. type MultiKueueClusterApplyConfiguration struct { v1.TypeMetaApplyConfiguration `json:",inline"` @@ -32,7 +32,7 @@ type MultiKueueClusterApplyConfiguration struct { Status *MultiKueueClusterStatusApplyConfiguration `json:"status,omitempty"` } -// MultiKueueCluster constructs an declarative configuration of the MultiKueueCluster type for use with +// MultiKueueCluster constructs a declarative configuration of the MultiKueueCluster type for use with // apply. func MultiKueueCluster(name string) *MultiKueueClusterApplyConfiguration { b := &MultiKueueClusterApplyConfiguration{} @@ -215,3 +215,9 @@ func (b *MultiKueueClusterApplyConfiguration) WithStatus(value *MultiKueueCluste b.Status = value return b } + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *MultiKueueClusterApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.Name +} diff --git a/client-go/applyconfiguration/kueue/v1alpha1/multikueueclusterspec.go b/client-go/applyconfiguration/kueue/v1alpha1/multikueueclusterspec.go index e7e304f7ea..12592bbd8b 100644 --- a/client-go/applyconfiguration/kueue/v1alpha1/multikueueclusterspec.go +++ b/client-go/applyconfiguration/kueue/v1alpha1/multikueueclusterspec.go @@ -17,13 +17,13 @@ limitations under the License. package v1alpha1 -// MultiKueueClusterSpecApplyConfiguration represents an declarative configuration of the MultiKueueClusterSpec type for use +// MultiKueueClusterSpecApplyConfiguration represents a declarative configuration of the MultiKueueClusterSpec type for use // with apply. type MultiKueueClusterSpecApplyConfiguration struct { KubeConfig *KubeConfigApplyConfiguration `json:"kubeConfig,omitempty"` } -// MultiKueueClusterSpecApplyConfiguration constructs an declarative configuration of the MultiKueueClusterSpec type for use with +// MultiKueueClusterSpecApplyConfiguration constructs a declarative configuration of the MultiKueueClusterSpec type for use with // apply. func MultiKueueClusterSpec() *MultiKueueClusterSpecApplyConfiguration { return &MultiKueueClusterSpecApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1alpha1/multikueueclusterstatus.go b/client-go/applyconfiguration/kueue/v1alpha1/multikueueclusterstatus.go index c01eaf7d06..f79e499da8 100644 --- a/client-go/applyconfiguration/kueue/v1alpha1/multikueueclusterstatus.go +++ b/client-go/applyconfiguration/kueue/v1alpha1/multikueueclusterstatus.go @@ -18,16 +18,16 @@ limitations under the License. package v1alpha1 import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) -// MultiKueueClusterStatusApplyConfiguration represents an declarative configuration of the MultiKueueClusterStatus type for use +// MultiKueueClusterStatusApplyConfiguration represents a declarative configuration of the MultiKueueClusterStatus type for use // with apply. type MultiKueueClusterStatusApplyConfiguration struct { - Conditions []v1.Condition `json:"conditions,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` } -// MultiKueueClusterStatusApplyConfiguration constructs an declarative configuration of the MultiKueueClusterStatus type for use with +// MultiKueueClusterStatusApplyConfiguration constructs a declarative configuration of the MultiKueueClusterStatus type for use with // apply. func MultiKueueClusterStatus() *MultiKueueClusterStatusApplyConfiguration { return &MultiKueueClusterStatusApplyConfiguration{} @@ -36,9 +36,12 @@ func MultiKueueClusterStatus() *MultiKueueClusterStatusApplyConfiguration { // WithConditions adds the given value to the Conditions field in the declarative configuration // and returns the receiver, so that objects can be build by chaining "With" function invocations. // If called multiple times, values provided by each call will be appended to the Conditions field. -func (b *MultiKueueClusterStatusApplyConfiguration) WithConditions(values ...v1.Condition) *MultiKueueClusterStatusApplyConfiguration { +func (b *MultiKueueClusterStatusApplyConfiguration) WithConditions(values ...*v1.ConditionApplyConfiguration) *MultiKueueClusterStatusApplyConfiguration { for i := range values { - b.Conditions = append(b.Conditions, values[i]) + if values[i] == nil { + panic("nil value passed to WithConditions") + } + b.Conditions = append(b.Conditions, *values[i]) } return b } diff --git a/client-go/applyconfiguration/kueue/v1alpha1/multikueueconfig.go b/client-go/applyconfiguration/kueue/v1alpha1/multikueueconfig.go index 63c7f1dabb..33aa7b8707 100644 --- a/client-go/applyconfiguration/kueue/v1alpha1/multikueueconfig.go +++ b/client-go/applyconfiguration/kueue/v1alpha1/multikueueconfig.go @@ -23,7 +23,7 @@ import ( v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) -// MultiKueueConfigApplyConfiguration represents an declarative configuration of the MultiKueueConfig type for use +// MultiKueueConfigApplyConfiguration represents a declarative configuration of the MultiKueueConfig type for use // with apply. type MultiKueueConfigApplyConfiguration struct { v1.TypeMetaApplyConfiguration `json:",inline"` @@ -31,7 +31,7 @@ type MultiKueueConfigApplyConfiguration struct { Spec *MultiKueueConfigSpecApplyConfiguration `json:"spec,omitempty"` } -// MultiKueueConfig constructs an declarative configuration of the MultiKueueConfig type for use with +// MultiKueueConfig constructs a declarative configuration of the MultiKueueConfig type for use with // apply. func MultiKueueConfig(name string) *MultiKueueConfigApplyConfiguration { b := &MultiKueueConfigApplyConfiguration{} @@ -206,3 +206,9 @@ func (b *MultiKueueConfigApplyConfiguration) WithSpec(value *MultiKueueConfigSpe b.Spec = value return b } + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *MultiKueueConfigApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.Name +} diff --git a/client-go/applyconfiguration/kueue/v1alpha1/multikueueconfigspec.go b/client-go/applyconfiguration/kueue/v1alpha1/multikueueconfigspec.go index 143954a1c0..413c58cf3a 100644 --- a/client-go/applyconfiguration/kueue/v1alpha1/multikueueconfigspec.go +++ b/client-go/applyconfiguration/kueue/v1alpha1/multikueueconfigspec.go @@ -17,13 +17,13 @@ limitations under the License. package v1alpha1 -// MultiKueueConfigSpecApplyConfiguration represents an declarative configuration of the MultiKueueConfigSpec type for use +// MultiKueueConfigSpecApplyConfiguration represents a declarative configuration of the MultiKueueConfigSpec type for use // with apply. type MultiKueueConfigSpecApplyConfiguration struct { Clusters []string `json:"clusters,omitempty"` } -// MultiKueueConfigSpecApplyConfiguration constructs an declarative configuration of the MultiKueueConfigSpec type for use with +// MultiKueueConfigSpecApplyConfiguration constructs a declarative configuration of the MultiKueueConfigSpec type for use with // apply. func MultiKueueConfigSpec() *MultiKueueConfigSpecApplyConfiguration { return &MultiKueueConfigSpecApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/admission.go b/client-go/applyconfiguration/kueue/v1beta1/admission.go index cba5f90f75..5207421d3a 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/admission.go +++ b/client-go/applyconfiguration/kueue/v1beta1/admission.go @@ -21,14 +21,14 @@ import ( v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" ) -// AdmissionApplyConfiguration represents an declarative configuration of the Admission type for use +// AdmissionApplyConfiguration represents a declarative configuration of the Admission type for use // with apply. type AdmissionApplyConfiguration struct { ClusterQueue *v1beta1.ClusterQueueReference `json:"clusterQueue,omitempty"` PodSetAssignments []PodSetAssignmentApplyConfiguration `json:"podSetAssignments,omitempty"` } -// AdmissionApplyConfiguration constructs an declarative configuration of the Admission type for use with +// AdmissionApplyConfiguration constructs a declarative configuration of the Admission type for use with // apply. func Admission() *AdmissionApplyConfiguration { return &AdmissionApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/admissioncheck.go b/client-go/applyconfiguration/kueue/v1beta1/admissioncheck.go index 7410598b7e..87c5ea07e6 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/admissioncheck.go +++ b/client-go/applyconfiguration/kueue/v1beta1/admissioncheck.go @@ -23,7 +23,7 @@ import ( v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) -// AdmissionCheckApplyConfiguration represents an declarative configuration of the AdmissionCheck type for use +// AdmissionCheckApplyConfiguration represents a declarative configuration of the AdmissionCheck type for use // with apply. type AdmissionCheckApplyConfiguration struct { v1.TypeMetaApplyConfiguration `json:",inline"` @@ -32,7 +32,7 @@ type AdmissionCheckApplyConfiguration struct { Status *AdmissionCheckStatusApplyConfiguration `json:"status,omitempty"` } -// AdmissionCheck constructs an declarative configuration of the AdmissionCheck type for use with +// AdmissionCheck constructs a declarative configuration of the AdmissionCheck type for use with // apply. func AdmissionCheck(name string) *AdmissionCheckApplyConfiguration { b := &AdmissionCheckApplyConfiguration{} @@ -215,3 +215,9 @@ func (b *AdmissionCheckApplyConfiguration) WithStatus(value *AdmissionCheckStatu b.Status = value return b } + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *AdmissionCheckApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.Name +} diff --git a/client-go/applyconfiguration/kueue/v1beta1/admissioncheckparametersreference.go b/client-go/applyconfiguration/kueue/v1beta1/admissioncheckparametersreference.go index 2c9a67c165..eb6dba0410 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/admissioncheckparametersreference.go +++ b/client-go/applyconfiguration/kueue/v1beta1/admissioncheckparametersreference.go @@ -17,7 +17,7 @@ limitations under the License. package v1beta1 -// AdmissionCheckParametersReferenceApplyConfiguration represents an declarative configuration of the AdmissionCheckParametersReference type for use +// AdmissionCheckParametersReferenceApplyConfiguration represents a declarative configuration of the AdmissionCheckParametersReference type for use // with apply. type AdmissionCheckParametersReferenceApplyConfiguration struct { APIGroup *string `json:"apiGroup,omitempty"` @@ -25,7 +25,7 @@ type AdmissionCheckParametersReferenceApplyConfiguration struct { Name *string `json:"name,omitempty"` } -// AdmissionCheckParametersReferenceApplyConfiguration constructs an declarative configuration of the AdmissionCheckParametersReference type for use with +// AdmissionCheckParametersReferenceApplyConfiguration constructs a declarative configuration of the AdmissionCheckParametersReference type for use with // apply. func AdmissionCheckParametersReference() *AdmissionCheckParametersReferenceApplyConfiguration { return &AdmissionCheckParametersReferenceApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/admissioncheckspec.go b/client-go/applyconfiguration/kueue/v1beta1/admissioncheckspec.go index e6c487001f..c45f876180 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/admissioncheckspec.go +++ b/client-go/applyconfiguration/kueue/v1beta1/admissioncheckspec.go @@ -17,7 +17,7 @@ limitations under the License. package v1beta1 -// AdmissionCheckSpecApplyConfiguration represents an declarative configuration of the AdmissionCheckSpec type for use +// AdmissionCheckSpecApplyConfiguration represents a declarative configuration of the AdmissionCheckSpec type for use // with apply. type AdmissionCheckSpecApplyConfiguration struct { ControllerName *string `json:"controllerName,omitempty"` @@ -25,7 +25,7 @@ type AdmissionCheckSpecApplyConfiguration struct { Parameters *AdmissionCheckParametersReferenceApplyConfiguration `json:"parameters,omitempty"` } -// AdmissionCheckSpecApplyConfiguration constructs an declarative configuration of the AdmissionCheckSpec type for use with +// AdmissionCheckSpecApplyConfiguration constructs a declarative configuration of the AdmissionCheckSpec type for use with // apply. func AdmissionCheckSpec() *AdmissionCheckSpecApplyConfiguration { return &AdmissionCheckSpecApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/admissionchecksstrategy.go b/client-go/applyconfiguration/kueue/v1beta1/admissionchecksstrategy.go index fb0c4ce292..7a484792f5 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/admissionchecksstrategy.go +++ b/client-go/applyconfiguration/kueue/v1beta1/admissionchecksstrategy.go @@ -17,13 +17,13 @@ limitations under the License. package v1beta1 -// AdmissionChecksStrategyApplyConfiguration represents an declarative configuration of the AdmissionChecksStrategy type for use +// AdmissionChecksStrategyApplyConfiguration represents a declarative configuration of the AdmissionChecksStrategy type for use // with apply. type AdmissionChecksStrategyApplyConfiguration struct { AdmissionChecks []AdmissionCheckStrategyRuleApplyConfiguration `json:"admissionChecks,omitempty"` } -// AdmissionChecksStrategyApplyConfiguration constructs an declarative configuration of the AdmissionChecksStrategy type for use with +// AdmissionChecksStrategyApplyConfiguration constructs a declarative configuration of the AdmissionChecksStrategy type for use with // apply. func AdmissionChecksStrategy() *AdmissionChecksStrategyApplyConfiguration { return &AdmissionChecksStrategyApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/admissioncheckstate.go b/client-go/applyconfiguration/kueue/v1beta1/admissioncheckstate.go index a065ed0952..a6efbf45d6 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/admissioncheckstate.go +++ b/client-go/applyconfiguration/kueue/v1beta1/admissioncheckstate.go @@ -22,7 +22,7 @@ import ( v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" ) -// AdmissionCheckStateApplyConfiguration represents an declarative configuration of the AdmissionCheckState type for use +// AdmissionCheckStateApplyConfiguration represents a declarative configuration of the AdmissionCheckState type for use // with apply. type AdmissionCheckStateApplyConfiguration struct { Name *string `json:"name,omitempty"` @@ -32,7 +32,7 @@ type AdmissionCheckStateApplyConfiguration struct { PodSetUpdates []PodSetUpdateApplyConfiguration `json:"podSetUpdates,omitempty"` } -// AdmissionCheckStateApplyConfiguration constructs an declarative configuration of the AdmissionCheckState type for use with +// AdmissionCheckStateApplyConfiguration constructs a declarative configuration of the AdmissionCheckState type for use with // apply. func AdmissionCheckState() *AdmissionCheckStateApplyConfiguration { return &AdmissionCheckStateApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/admissioncheckstatus.go b/client-go/applyconfiguration/kueue/v1beta1/admissioncheckstatus.go index 1341cffbce..85a319d110 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/admissioncheckstatus.go +++ b/client-go/applyconfiguration/kueue/v1beta1/admissioncheckstatus.go @@ -18,16 +18,16 @@ limitations under the License. package v1beta1 import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) -// AdmissionCheckStatusApplyConfiguration represents an declarative configuration of the AdmissionCheckStatus type for use +// AdmissionCheckStatusApplyConfiguration represents a declarative configuration of the AdmissionCheckStatus type for use // with apply. type AdmissionCheckStatusApplyConfiguration struct { - Conditions []v1.Condition `json:"conditions,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` } -// AdmissionCheckStatusApplyConfiguration constructs an declarative configuration of the AdmissionCheckStatus type for use with +// AdmissionCheckStatusApplyConfiguration constructs a declarative configuration of the AdmissionCheckStatus type for use with // apply. func AdmissionCheckStatus() *AdmissionCheckStatusApplyConfiguration { return &AdmissionCheckStatusApplyConfiguration{} @@ -36,9 +36,12 @@ func AdmissionCheckStatus() *AdmissionCheckStatusApplyConfiguration { // WithConditions adds the given value to the Conditions field in the declarative configuration // and returns the receiver, so that objects can be build by chaining "With" function invocations. // If called multiple times, values provided by each call will be appended to the Conditions field. -func (b *AdmissionCheckStatusApplyConfiguration) WithConditions(values ...v1.Condition) *AdmissionCheckStatusApplyConfiguration { +func (b *AdmissionCheckStatusApplyConfiguration) WithConditions(values ...*v1.ConditionApplyConfiguration) *AdmissionCheckStatusApplyConfiguration { for i := range values { - b.Conditions = append(b.Conditions, values[i]) + if values[i] == nil { + panic("nil value passed to WithConditions") + } + b.Conditions = append(b.Conditions, *values[i]) } return b } diff --git a/client-go/applyconfiguration/kueue/v1beta1/admissioncheckstrategyrule.go b/client-go/applyconfiguration/kueue/v1beta1/admissioncheckstrategyrule.go index 84a8e6655b..3c747fd556 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/admissioncheckstrategyrule.go +++ b/client-go/applyconfiguration/kueue/v1beta1/admissioncheckstrategyrule.go @@ -21,14 +21,14 @@ import ( v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" ) -// AdmissionCheckStrategyRuleApplyConfiguration represents an declarative configuration of the AdmissionCheckStrategyRule type for use +// AdmissionCheckStrategyRuleApplyConfiguration represents a declarative configuration of the AdmissionCheckStrategyRule type for use // with apply. type AdmissionCheckStrategyRuleApplyConfiguration struct { Name *string `json:"name,omitempty"` OnFlavors []v1beta1.ResourceFlavorReference `json:"onFlavors,omitempty"` } -// AdmissionCheckStrategyRuleApplyConfiguration constructs an declarative configuration of the AdmissionCheckStrategyRule type for use with +// AdmissionCheckStrategyRuleApplyConfiguration constructs a declarative configuration of the AdmissionCheckStrategyRule type for use with // apply. func AdmissionCheckStrategyRule() *AdmissionCheckStrategyRuleApplyConfiguration { return &AdmissionCheckStrategyRuleApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/borrowwithincohort.go b/client-go/applyconfiguration/kueue/v1beta1/borrowwithincohort.go index 85d6fcd11a..49f4be6423 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/borrowwithincohort.go +++ b/client-go/applyconfiguration/kueue/v1beta1/borrowwithincohort.go @@ -21,14 +21,14 @@ import ( v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" ) -// BorrowWithinCohortApplyConfiguration represents an declarative configuration of the BorrowWithinCohort type for use +// BorrowWithinCohortApplyConfiguration represents a declarative configuration of the BorrowWithinCohort type for use // with apply. type BorrowWithinCohortApplyConfiguration struct { Policy *v1beta1.BorrowWithinCohortPolicy `json:"policy,omitempty"` MaxPriorityThreshold *int32 `json:"maxPriorityThreshold,omitempty"` } -// BorrowWithinCohortApplyConfiguration constructs an declarative configuration of the BorrowWithinCohort type for use with +// BorrowWithinCohortApplyConfiguration constructs a declarative configuration of the BorrowWithinCohort type for use with // apply. func BorrowWithinCohort() *BorrowWithinCohortApplyConfiguration { return &BorrowWithinCohortApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/clusterqueue.go b/client-go/applyconfiguration/kueue/v1beta1/clusterqueue.go index 2c3fe3e144..fe5cd79cdc 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/clusterqueue.go +++ b/client-go/applyconfiguration/kueue/v1beta1/clusterqueue.go @@ -23,7 +23,7 @@ import ( v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) -// ClusterQueueApplyConfiguration represents an declarative configuration of the ClusterQueue type for use +// ClusterQueueApplyConfiguration represents a declarative configuration of the ClusterQueue type for use // with apply. type ClusterQueueApplyConfiguration struct { v1.TypeMetaApplyConfiguration `json:",inline"` @@ -32,7 +32,7 @@ type ClusterQueueApplyConfiguration struct { Status *ClusterQueueStatusApplyConfiguration `json:"status,omitempty"` } -// ClusterQueue constructs an declarative configuration of the ClusterQueue type for use with +// ClusterQueue constructs a declarative configuration of the ClusterQueue type for use with // apply. func ClusterQueue(name string) *ClusterQueueApplyConfiguration { b := &ClusterQueueApplyConfiguration{} @@ -215,3 +215,9 @@ func (b *ClusterQueueApplyConfiguration) WithStatus(value *ClusterQueueStatusApp b.Status = value return b } + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *ClusterQueueApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.Name +} diff --git a/client-go/applyconfiguration/kueue/v1beta1/clusterqueuependingworkload.go b/client-go/applyconfiguration/kueue/v1beta1/clusterqueuependingworkload.go index ee2de5bbdf..500fd38a4a 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/clusterqueuependingworkload.go +++ b/client-go/applyconfiguration/kueue/v1beta1/clusterqueuependingworkload.go @@ -17,14 +17,14 @@ limitations under the License. package v1beta1 -// ClusterQueuePendingWorkloadApplyConfiguration represents an declarative configuration of the ClusterQueuePendingWorkload type for use +// ClusterQueuePendingWorkloadApplyConfiguration represents a declarative configuration of the ClusterQueuePendingWorkload type for use // with apply. type ClusterQueuePendingWorkloadApplyConfiguration struct { Name *string `json:"name,omitempty"` Namespace *string `json:"namespace,omitempty"` } -// ClusterQueuePendingWorkloadApplyConfiguration constructs an declarative configuration of the ClusterQueuePendingWorkload type for use with +// ClusterQueuePendingWorkloadApplyConfiguration constructs a declarative configuration of the ClusterQueuePendingWorkload type for use with // apply. func ClusterQueuePendingWorkload() *ClusterQueuePendingWorkloadApplyConfiguration { return &ClusterQueuePendingWorkloadApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/clusterqueuependingworkloadsstatus.go b/client-go/applyconfiguration/kueue/v1beta1/clusterqueuependingworkloadsstatus.go index 11da82f728..c217e77ef4 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/clusterqueuependingworkloadsstatus.go +++ b/client-go/applyconfiguration/kueue/v1beta1/clusterqueuependingworkloadsstatus.go @@ -21,14 +21,14 @@ import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// ClusterQueuePendingWorkloadsStatusApplyConfiguration represents an declarative configuration of the ClusterQueuePendingWorkloadsStatus type for use +// ClusterQueuePendingWorkloadsStatusApplyConfiguration represents a declarative configuration of the ClusterQueuePendingWorkloadsStatus type for use // with apply. type ClusterQueuePendingWorkloadsStatusApplyConfiguration struct { Head []ClusterQueuePendingWorkloadApplyConfiguration `json:"clusterQueuePendingWorkload,omitempty"` LastChangeTime *v1.Time `json:"lastChangeTime,omitempty"` } -// ClusterQueuePendingWorkloadsStatusApplyConfiguration constructs an declarative configuration of the ClusterQueuePendingWorkloadsStatus type for use with +// ClusterQueuePendingWorkloadsStatusApplyConfiguration constructs a declarative configuration of the ClusterQueuePendingWorkloadsStatus type for use with // apply. func ClusterQueuePendingWorkloadsStatus() *ClusterQueuePendingWorkloadsStatusApplyConfiguration { return &ClusterQueuePendingWorkloadsStatusApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/clusterqueuepreemption.go b/client-go/applyconfiguration/kueue/v1beta1/clusterqueuepreemption.go index 7513e90ddc..15e4f566fb 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/clusterqueuepreemption.go +++ b/client-go/applyconfiguration/kueue/v1beta1/clusterqueuepreemption.go @@ -21,7 +21,7 @@ import ( v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" ) -// ClusterQueuePreemptionApplyConfiguration represents an declarative configuration of the ClusterQueuePreemption type for use +// ClusterQueuePreemptionApplyConfiguration represents a declarative configuration of the ClusterQueuePreemption type for use // with apply. type ClusterQueuePreemptionApplyConfiguration struct { ReclaimWithinCohort *v1beta1.PreemptionPolicy `json:"reclaimWithinCohort,omitempty"` @@ -29,7 +29,7 @@ type ClusterQueuePreemptionApplyConfiguration struct { WithinClusterQueue *v1beta1.PreemptionPolicy `json:"withinClusterQueue,omitempty"` } -// ClusterQueuePreemptionApplyConfiguration constructs an declarative configuration of the ClusterQueuePreemption type for use with +// ClusterQueuePreemptionApplyConfiguration constructs a declarative configuration of the ClusterQueuePreemption type for use with // apply. func ClusterQueuePreemption() *ClusterQueuePreemptionApplyConfiguration { return &ClusterQueuePreemptionApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/clusterqueuespec.go b/client-go/applyconfiguration/kueue/v1beta1/clusterqueuespec.go index 1794cea5d0..0c55acf5ce 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/clusterqueuespec.go +++ b/client-go/applyconfiguration/kueue/v1beta1/clusterqueuespec.go @@ -18,17 +18,17 @@ limitations under the License. package v1beta1 import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" kueuev1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" ) -// ClusterQueueSpecApplyConfiguration represents an declarative configuration of the ClusterQueueSpec type for use +// ClusterQueueSpecApplyConfiguration represents a declarative configuration of the ClusterQueueSpec type for use // with apply. type ClusterQueueSpecApplyConfiguration struct { ResourceGroups []ResourceGroupApplyConfiguration `json:"resourceGroups,omitempty"` Cohort *string `json:"cohort,omitempty"` QueueingStrategy *kueuev1beta1.QueueingStrategy `json:"queueingStrategy,omitempty"` - NamespaceSelector *v1.LabelSelector `json:"namespaceSelector,omitempty"` + NamespaceSelector *v1.LabelSelectorApplyConfiguration `json:"namespaceSelector,omitempty"` FlavorFungibility *FlavorFungibilityApplyConfiguration `json:"flavorFungibility,omitempty"` Preemption *ClusterQueuePreemptionApplyConfiguration `json:"preemption,omitempty"` AdmissionChecks []string `json:"admissionChecks,omitempty"` @@ -37,7 +37,7 @@ type ClusterQueueSpecApplyConfiguration struct { FairSharing *FairSharingApplyConfiguration `json:"fairSharing,omitempty"` } -// ClusterQueueSpecApplyConfiguration constructs an declarative configuration of the ClusterQueueSpec type for use with +// ClusterQueueSpecApplyConfiguration constructs a declarative configuration of the ClusterQueueSpec type for use with // apply. func ClusterQueueSpec() *ClusterQueueSpecApplyConfiguration { return &ClusterQueueSpecApplyConfiguration{} @@ -75,8 +75,8 @@ func (b *ClusterQueueSpecApplyConfiguration) WithQueueingStrategy(value kueuev1b // WithNamespaceSelector sets the NamespaceSelector field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the NamespaceSelector field is set to the value of the last call. -func (b *ClusterQueueSpecApplyConfiguration) WithNamespaceSelector(value v1.LabelSelector) *ClusterQueueSpecApplyConfiguration { - b.NamespaceSelector = &value +func (b *ClusterQueueSpecApplyConfiguration) WithNamespaceSelector(value *v1.LabelSelectorApplyConfiguration) *ClusterQueueSpecApplyConfiguration { + b.NamespaceSelector = value return b } diff --git a/client-go/applyconfiguration/kueue/v1beta1/clusterqueuestatus.go b/client-go/applyconfiguration/kueue/v1beta1/clusterqueuestatus.go index 042aedb358..5d3d37b7d2 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/clusterqueuestatus.go +++ b/client-go/applyconfiguration/kueue/v1beta1/clusterqueuestatus.go @@ -18,10 +18,10 @@ limitations under the License. package v1beta1 import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) -// ClusterQueueStatusApplyConfiguration represents an declarative configuration of the ClusterQueueStatus type for use +// ClusterQueueStatusApplyConfiguration represents a declarative configuration of the ClusterQueueStatus type for use // with apply. type ClusterQueueStatusApplyConfiguration struct { FlavorsReservation []FlavorUsageApplyConfiguration `json:"flavorsReservation,omitempty"` @@ -29,12 +29,12 @@ type ClusterQueueStatusApplyConfiguration struct { PendingWorkloads *int32 `json:"pendingWorkloads,omitempty"` ReservingWorkloads *int32 `json:"reservingWorkloads,omitempty"` AdmittedWorkloads *int32 `json:"admittedWorkloads,omitempty"` - Conditions []v1.Condition `json:"conditions,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` PendingWorkloadsStatus *ClusterQueuePendingWorkloadsStatusApplyConfiguration `json:"pendingWorkloadsStatus,omitempty"` FairSharing *FairSharingStatusApplyConfiguration `json:"fairSharing,omitempty"` } -// ClusterQueueStatusApplyConfiguration constructs an declarative configuration of the ClusterQueueStatus type for use with +// ClusterQueueStatusApplyConfiguration constructs a declarative configuration of the ClusterQueueStatus type for use with // apply. func ClusterQueueStatus() *ClusterQueueStatusApplyConfiguration { return &ClusterQueueStatusApplyConfiguration{} @@ -93,9 +93,12 @@ func (b *ClusterQueueStatusApplyConfiguration) WithAdmittedWorkloads(value int32 // WithConditions adds the given value to the Conditions field in the declarative configuration // and returns the receiver, so that objects can be build by chaining "With" function invocations. // If called multiple times, values provided by each call will be appended to the Conditions field. -func (b *ClusterQueueStatusApplyConfiguration) WithConditions(values ...v1.Condition) *ClusterQueueStatusApplyConfiguration { +func (b *ClusterQueueStatusApplyConfiguration) WithConditions(values ...*v1.ConditionApplyConfiguration) *ClusterQueueStatusApplyConfiguration { for i := range values { - b.Conditions = append(b.Conditions, values[i]) + if values[i] == nil { + panic("nil value passed to WithConditions") + } + b.Conditions = append(b.Conditions, *values[i]) } return b } diff --git a/client-go/applyconfiguration/kueue/v1beta1/fairsharing.go b/client-go/applyconfiguration/kueue/v1beta1/fairsharing.go index e5bba5b4ac..5448a8f31b 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/fairsharing.go +++ b/client-go/applyconfiguration/kueue/v1beta1/fairsharing.go @@ -21,13 +21,13 @@ import ( resource "k8s.io/apimachinery/pkg/api/resource" ) -// FairSharingApplyConfiguration represents an declarative configuration of the FairSharing type for use +// FairSharingApplyConfiguration represents a declarative configuration of the FairSharing type for use // with apply. type FairSharingApplyConfiguration struct { Weight *resource.Quantity `json:"weight,omitempty"` } -// FairSharingApplyConfiguration constructs an declarative configuration of the FairSharing type for use with +// FairSharingApplyConfiguration constructs a declarative configuration of the FairSharing type for use with // apply. func FairSharing() *FairSharingApplyConfiguration { return &FairSharingApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/fairsharingstatus.go b/client-go/applyconfiguration/kueue/v1beta1/fairsharingstatus.go index 43853ea968..da3a5b0004 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/fairsharingstatus.go +++ b/client-go/applyconfiguration/kueue/v1beta1/fairsharingstatus.go @@ -17,13 +17,13 @@ limitations under the License. package v1beta1 -// FairSharingStatusApplyConfiguration represents an declarative configuration of the FairSharingStatus type for use +// FairSharingStatusApplyConfiguration represents a declarative configuration of the FairSharingStatus type for use // with apply. type FairSharingStatusApplyConfiguration struct { WeightedShare *int64 `json:"weightedShare,omitempty"` } -// FairSharingStatusApplyConfiguration constructs an declarative configuration of the FairSharingStatus type for use with +// FairSharingStatusApplyConfiguration constructs a declarative configuration of the FairSharingStatus type for use with // apply. func FairSharingStatus() *FairSharingStatusApplyConfiguration { return &FairSharingStatusApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/flavorfungibility.go b/client-go/applyconfiguration/kueue/v1beta1/flavorfungibility.go index 2fae55c58b..be9eabf2d8 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/flavorfungibility.go +++ b/client-go/applyconfiguration/kueue/v1beta1/flavorfungibility.go @@ -21,14 +21,14 @@ import ( v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" ) -// FlavorFungibilityApplyConfiguration represents an declarative configuration of the FlavorFungibility type for use +// FlavorFungibilityApplyConfiguration represents a declarative configuration of the FlavorFungibility type for use // with apply. type FlavorFungibilityApplyConfiguration struct { WhenCanBorrow *v1beta1.FlavorFungibilityPolicy `json:"whenCanBorrow,omitempty"` WhenCanPreempt *v1beta1.FlavorFungibilityPolicy `json:"whenCanPreempt,omitempty"` } -// FlavorFungibilityApplyConfiguration constructs an declarative configuration of the FlavorFungibility type for use with +// FlavorFungibilityApplyConfiguration constructs a declarative configuration of the FlavorFungibility type for use with // apply. func FlavorFungibility() *FlavorFungibilityApplyConfiguration { return &FlavorFungibilityApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/flavorquotas.go b/client-go/applyconfiguration/kueue/v1beta1/flavorquotas.go index db48b16925..89fc99ab55 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/flavorquotas.go +++ b/client-go/applyconfiguration/kueue/v1beta1/flavorquotas.go @@ -21,14 +21,14 @@ import ( v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" ) -// FlavorQuotasApplyConfiguration represents an declarative configuration of the FlavorQuotas type for use +// FlavorQuotasApplyConfiguration represents a declarative configuration of the FlavorQuotas type for use // with apply. type FlavorQuotasApplyConfiguration struct { Name *v1beta1.ResourceFlavorReference `json:"name,omitempty"` Resources []ResourceQuotaApplyConfiguration `json:"resources,omitempty"` } -// FlavorQuotasApplyConfiguration constructs an declarative configuration of the FlavorQuotas type for use with +// FlavorQuotasApplyConfiguration constructs a declarative configuration of the FlavorQuotas type for use with // apply. func FlavorQuotas() *FlavorQuotasApplyConfiguration { return &FlavorQuotasApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/flavorusage.go b/client-go/applyconfiguration/kueue/v1beta1/flavorusage.go index ea4651084c..b89944bd85 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/flavorusage.go +++ b/client-go/applyconfiguration/kueue/v1beta1/flavorusage.go @@ -21,14 +21,14 @@ import ( v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" ) -// FlavorUsageApplyConfiguration represents an declarative configuration of the FlavorUsage type for use +// FlavorUsageApplyConfiguration represents a declarative configuration of the FlavorUsage type for use // with apply. type FlavorUsageApplyConfiguration struct { Name *v1beta1.ResourceFlavorReference `json:"name,omitempty"` Resources []ResourceUsageApplyConfiguration `json:"resources,omitempty"` } -// FlavorUsageApplyConfiguration constructs an declarative configuration of the FlavorUsage type for use with +// FlavorUsageApplyConfiguration constructs a declarative configuration of the FlavorUsage type for use with // apply. func FlavorUsage() *FlavorUsageApplyConfiguration { return &FlavorUsageApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/localqueue.go b/client-go/applyconfiguration/kueue/v1beta1/localqueue.go index c6d1cb7246..33f8c222b4 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/localqueue.go +++ b/client-go/applyconfiguration/kueue/v1beta1/localqueue.go @@ -23,7 +23,7 @@ import ( v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) -// LocalQueueApplyConfiguration represents an declarative configuration of the LocalQueue type for use +// LocalQueueApplyConfiguration represents a declarative configuration of the LocalQueue type for use // with apply. type LocalQueueApplyConfiguration struct { v1.TypeMetaApplyConfiguration `json:",inline"` @@ -32,7 +32,7 @@ type LocalQueueApplyConfiguration struct { Status *LocalQueueStatusApplyConfiguration `json:"status,omitempty"` } -// LocalQueue constructs an declarative configuration of the LocalQueue type for use with +// LocalQueue constructs a declarative configuration of the LocalQueue type for use with // apply. func LocalQueue(name, namespace string) *LocalQueueApplyConfiguration { b := &LocalQueueApplyConfiguration{} @@ -216,3 +216,9 @@ func (b *LocalQueueApplyConfiguration) WithStatus(value *LocalQueueStatusApplyCo b.Status = value return b } + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *LocalQueueApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.Name +} diff --git a/client-go/applyconfiguration/kueue/v1beta1/localqueueflavorusage.go b/client-go/applyconfiguration/kueue/v1beta1/localqueueflavorusage.go index 4d223f969c..7e08ed0991 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/localqueueflavorusage.go +++ b/client-go/applyconfiguration/kueue/v1beta1/localqueueflavorusage.go @@ -21,14 +21,14 @@ import ( v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" ) -// LocalQueueFlavorUsageApplyConfiguration represents an declarative configuration of the LocalQueueFlavorUsage type for use +// LocalQueueFlavorUsageApplyConfiguration represents a declarative configuration of the LocalQueueFlavorUsage type for use // with apply. type LocalQueueFlavorUsageApplyConfiguration struct { Name *v1beta1.ResourceFlavorReference `json:"name,omitempty"` Resources []LocalQueueResourceUsageApplyConfiguration `json:"resources,omitempty"` } -// LocalQueueFlavorUsageApplyConfiguration constructs an declarative configuration of the LocalQueueFlavorUsage type for use with +// LocalQueueFlavorUsageApplyConfiguration constructs a declarative configuration of the LocalQueueFlavorUsage type for use with // apply. func LocalQueueFlavorUsage() *LocalQueueFlavorUsageApplyConfiguration { return &LocalQueueFlavorUsageApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/localqueueresourceusage.go b/client-go/applyconfiguration/kueue/v1beta1/localqueueresourceusage.go index ddcf8a2a00..32cd91339f 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/localqueueresourceusage.go +++ b/client-go/applyconfiguration/kueue/v1beta1/localqueueresourceusage.go @@ -22,14 +22,14 @@ import ( resource "k8s.io/apimachinery/pkg/api/resource" ) -// LocalQueueResourceUsageApplyConfiguration represents an declarative configuration of the LocalQueueResourceUsage type for use +// LocalQueueResourceUsageApplyConfiguration represents a declarative configuration of the LocalQueueResourceUsage type for use // with apply. type LocalQueueResourceUsageApplyConfiguration struct { Name *v1.ResourceName `json:"name,omitempty"` Total *resource.Quantity `json:"total,omitempty"` } -// LocalQueueResourceUsageApplyConfiguration constructs an declarative configuration of the LocalQueueResourceUsage type for use with +// LocalQueueResourceUsageApplyConfiguration constructs a declarative configuration of the LocalQueueResourceUsage type for use with // apply. func LocalQueueResourceUsage() *LocalQueueResourceUsageApplyConfiguration { return &LocalQueueResourceUsageApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/localqueuespec.go b/client-go/applyconfiguration/kueue/v1beta1/localqueuespec.go index 724b31cd3c..f92796ff34 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/localqueuespec.go +++ b/client-go/applyconfiguration/kueue/v1beta1/localqueuespec.go @@ -21,14 +21,14 @@ import ( v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" ) -// LocalQueueSpecApplyConfiguration represents an declarative configuration of the LocalQueueSpec type for use +// LocalQueueSpecApplyConfiguration represents a declarative configuration of the LocalQueueSpec type for use // with apply. type LocalQueueSpecApplyConfiguration struct { ClusterQueue *v1beta1.ClusterQueueReference `json:"clusterQueue,omitempty"` StopPolicy *v1beta1.StopPolicy `json:"stopPolicy,omitempty"` } -// LocalQueueSpecApplyConfiguration constructs an declarative configuration of the LocalQueueSpec type for use with +// LocalQueueSpecApplyConfiguration constructs a declarative configuration of the LocalQueueSpec type for use with // apply. func LocalQueueSpec() *LocalQueueSpecApplyConfiguration { return &LocalQueueSpecApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/localqueuestatus.go b/client-go/applyconfiguration/kueue/v1beta1/localqueuestatus.go index 9b77e15c4f..38ca3bf58a 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/localqueuestatus.go +++ b/client-go/applyconfiguration/kueue/v1beta1/localqueuestatus.go @@ -18,21 +18,21 @@ limitations under the License. package v1beta1 import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) -// LocalQueueStatusApplyConfiguration represents an declarative configuration of the LocalQueueStatus type for use +// LocalQueueStatusApplyConfiguration represents a declarative configuration of the LocalQueueStatus type for use // with apply. type LocalQueueStatusApplyConfiguration struct { PendingWorkloads *int32 `json:"pendingWorkloads,omitempty"` ReservingWorkloads *int32 `json:"reservingWorkloads,omitempty"` AdmittedWorkloads *int32 `json:"admittedWorkloads,omitempty"` - Conditions []v1.Condition `json:"conditions,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` FlavorsReservation []LocalQueueFlavorUsageApplyConfiguration `json:"flavorsReservation,omitempty"` FlavorUsage []LocalQueueFlavorUsageApplyConfiguration `json:"flavorUsage,omitempty"` } -// LocalQueueStatusApplyConfiguration constructs an declarative configuration of the LocalQueueStatus type for use with +// LocalQueueStatusApplyConfiguration constructs a declarative configuration of the LocalQueueStatus type for use with // apply. func LocalQueueStatus() *LocalQueueStatusApplyConfiguration { return &LocalQueueStatusApplyConfiguration{} @@ -65,9 +65,12 @@ func (b *LocalQueueStatusApplyConfiguration) WithAdmittedWorkloads(value int32) // WithConditions adds the given value to the Conditions field in the declarative configuration // and returns the receiver, so that objects can be build by chaining "With" function invocations. // If called multiple times, values provided by each call will be appended to the Conditions field. -func (b *LocalQueueStatusApplyConfiguration) WithConditions(values ...v1.Condition) *LocalQueueStatusApplyConfiguration { +func (b *LocalQueueStatusApplyConfiguration) WithConditions(values ...*v1.ConditionApplyConfiguration) *LocalQueueStatusApplyConfiguration { for i := range values { - b.Conditions = append(b.Conditions, values[i]) + if values[i] == nil { + panic("nil value passed to WithConditions") + } + b.Conditions = append(b.Conditions, *values[i]) } return b } diff --git a/client-go/applyconfiguration/kueue/v1beta1/podset.go b/client-go/applyconfiguration/kueue/v1beta1/podset.go index d05c58dc7e..fc2d1996f4 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/podset.go +++ b/client-go/applyconfiguration/kueue/v1beta1/podset.go @@ -21,7 +21,7 @@ import ( v1 "k8s.io/api/core/v1" ) -// PodSetApplyConfiguration represents an declarative configuration of the PodSet type for use +// PodSetApplyConfiguration represents a declarative configuration of the PodSet type for use // with apply. type PodSetApplyConfiguration struct { Name *string `json:"name,omitempty"` @@ -30,7 +30,7 @@ type PodSetApplyConfiguration struct { MinCount *int32 `json:"minCount,omitempty"` } -// PodSetApplyConfiguration constructs an declarative configuration of the PodSet type for use with +// PodSetApplyConfiguration constructs a declarative configuration of the PodSet type for use with // apply. func PodSet() *PodSetApplyConfiguration { return &PodSetApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/podsetassignment.go b/client-go/applyconfiguration/kueue/v1beta1/podsetassignment.go index 4460c3b08e..d69bdf4b74 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/podsetassignment.go +++ b/client-go/applyconfiguration/kueue/v1beta1/podsetassignment.go @@ -22,7 +22,7 @@ import ( v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" ) -// PodSetAssignmentApplyConfiguration represents an declarative configuration of the PodSetAssignment type for use +// PodSetAssignmentApplyConfiguration represents a declarative configuration of the PodSetAssignment type for use // with apply. type PodSetAssignmentApplyConfiguration struct { Name *string `json:"name,omitempty"` @@ -31,7 +31,7 @@ type PodSetAssignmentApplyConfiguration struct { Count *int32 `json:"count,omitempty"` } -// PodSetAssignmentApplyConfiguration constructs an declarative configuration of the PodSetAssignment type for use with +// PodSetAssignmentApplyConfiguration constructs a declarative configuration of the PodSetAssignment type for use with // apply. func PodSetAssignment() *PodSetAssignmentApplyConfiguration { return &PodSetAssignmentApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/podsetupdate.go b/client-go/applyconfiguration/kueue/v1beta1/podsetupdate.go index ce1e255da9..89b53d3ff5 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/podsetupdate.go +++ b/client-go/applyconfiguration/kueue/v1beta1/podsetupdate.go @@ -21,7 +21,7 @@ import ( v1 "k8s.io/api/core/v1" ) -// PodSetUpdateApplyConfiguration represents an declarative configuration of the PodSetUpdate type for use +// PodSetUpdateApplyConfiguration represents a declarative configuration of the PodSetUpdate type for use // with apply. type PodSetUpdateApplyConfiguration struct { Name *string `json:"name,omitempty"` @@ -31,7 +31,7 @@ type PodSetUpdateApplyConfiguration struct { Tolerations []v1.Toleration `json:"tolerations,omitempty"` } -// PodSetUpdateApplyConfiguration constructs an declarative configuration of the PodSetUpdate type for use with +// PodSetUpdateApplyConfiguration constructs a declarative configuration of the PodSetUpdate type for use with // apply. func PodSetUpdate() *PodSetUpdateApplyConfiguration { return &PodSetUpdateApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/provisioningrequestconfig.go b/client-go/applyconfiguration/kueue/v1beta1/provisioningrequestconfig.go index 18938ee327..99ef28e948 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/provisioningrequestconfig.go +++ b/client-go/applyconfiguration/kueue/v1beta1/provisioningrequestconfig.go @@ -23,7 +23,7 @@ import ( v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) -// ProvisioningRequestConfigApplyConfiguration represents an declarative configuration of the ProvisioningRequestConfig type for use +// ProvisioningRequestConfigApplyConfiguration represents a declarative configuration of the ProvisioningRequestConfig type for use // with apply. type ProvisioningRequestConfigApplyConfiguration struct { v1.TypeMetaApplyConfiguration `json:",inline"` @@ -31,7 +31,7 @@ type ProvisioningRequestConfigApplyConfiguration struct { Spec *ProvisioningRequestConfigSpecApplyConfiguration `json:"spec,omitempty"` } -// ProvisioningRequestConfig constructs an declarative configuration of the ProvisioningRequestConfig type for use with +// ProvisioningRequestConfig constructs a declarative configuration of the ProvisioningRequestConfig type for use with // apply. func ProvisioningRequestConfig(name string) *ProvisioningRequestConfigApplyConfiguration { b := &ProvisioningRequestConfigApplyConfiguration{} @@ -206,3 +206,9 @@ func (b *ProvisioningRequestConfigApplyConfiguration) WithSpec(value *Provisioni b.Spec = value return b } + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *ProvisioningRequestConfigApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.Name +} diff --git a/client-go/applyconfiguration/kueue/v1beta1/provisioningrequestconfigspec.go b/client-go/applyconfiguration/kueue/v1beta1/provisioningrequestconfigspec.go index 88ccf923ba..ce20f9e936 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/provisioningrequestconfigspec.go +++ b/client-go/applyconfiguration/kueue/v1beta1/provisioningrequestconfigspec.go @@ -22,7 +22,7 @@ import ( v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" ) -// ProvisioningRequestConfigSpecApplyConfiguration represents an declarative configuration of the ProvisioningRequestConfigSpec type for use +// ProvisioningRequestConfigSpecApplyConfiguration represents a declarative configuration of the ProvisioningRequestConfigSpec type for use // with apply. type ProvisioningRequestConfigSpecApplyConfiguration struct { ProvisioningClassName *string `json:"provisioningClassName,omitempty"` @@ -30,7 +30,7 @@ type ProvisioningRequestConfigSpecApplyConfiguration struct { ManagedResources []v1.ResourceName `json:"managedResources,omitempty"` } -// ProvisioningRequestConfigSpecApplyConfiguration constructs an declarative configuration of the ProvisioningRequestConfigSpec type for use with +// ProvisioningRequestConfigSpecApplyConfiguration constructs a declarative configuration of the ProvisioningRequestConfigSpec type for use with // apply. func ProvisioningRequestConfigSpec() *ProvisioningRequestConfigSpecApplyConfiguration { return &ProvisioningRequestConfigSpecApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/reclaimablepod.go b/client-go/applyconfiguration/kueue/v1beta1/reclaimablepod.go index b0a9a30cc0..0c61c043ad 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/reclaimablepod.go +++ b/client-go/applyconfiguration/kueue/v1beta1/reclaimablepod.go @@ -17,14 +17,14 @@ limitations under the License. package v1beta1 -// ReclaimablePodApplyConfiguration represents an declarative configuration of the ReclaimablePod type for use +// ReclaimablePodApplyConfiguration represents a declarative configuration of the ReclaimablePod type for use // with apply. type ReclaimablePodApplyConfiguration struct { Name *string `json:"name,omitempty"` Count *int32 `json:"count,omitempty"` } -// ReclaimablePodApplyConfiguration constructs an declarative configuration of the ReclaimablePod type for use with +// ReclaimablePodApplyConfiguration constructs a declarative configuration of the ReclaimablePod type for use with // apply. func ReclaimablePod() *ReclaimablePodApplyConfiguration { return &ReclaimablePodApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/requeuestate.go b/client-go/applyconfiguration/kueue/v1beta1/requeuestate.go index 3123e5a66d..4bc48fb463 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/requeuestate.go +++ b/client-go/applyconfiguration/kueue/v1beta1/requeuestate.go @@ -21,14 +21,14 @@ import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// RequeueStateApplyConfiguration represents an declarative configuration of the RequeueState type for use +// RequeueStateApplyConfiguration represents a declarative configuration of the RequeueState type for use // with apply. type RequeueStateApplyConfiguration struct { Count *int32 `json:"count,omitempty"` RequeueAt *v1.Time `json:"requeueAt,omitempty"` } -// RequeueStateApplyConfiguration constructs an declarative configuration of the RequeueState type for use with +// RequeueStateApplyConfiguration constructs a declarative configuration of the RequeueState type for use with // apply. func RequeueState() *RequeueStateApplyConfiguration { return &RequeueStateApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/resourceflavor.go b/client-go/applyconfiguration/kueue/v1beta1/resourceflavor.go index 5cbc31a754..a312b4050f 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/resourceflavor.go +++ b/client-go/applyconfiguration/kueue/v1beta1/resourceflavor.go @@ -23,7 +23,7 @@ import ( v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) -// ResourceFlavorApplyConfiguration represents an declarative configuration of the ResourceFlavor type for use +// ResourceFlavorApplyConfiguration represents a declarative configuration of the ResourceFlavor type for use // with apply. type ResourceFlavorApplyConfiguration struct { v1.TypeMetaApplyConfiguration `json:",inline"` @@ -31,7 +31,7 @@ type ResourceFlavorApplyConfiguration struct { Spec *ResourceFlavorSpecApplyConfiguration `json:"spec,omitempty"` } -// ResourceFlavor constructs an declarative configuration of the ResourceFlavor type for use with +// ResourceFlavor constructs a declarative configuration of the ResourceFlavor type for use with // apply. func ResourceFlavor(name string) *ResourceFlavorApplyConfiguration { b := &ResourceFlavorApplyConfiguration{} @@ -206,3 +206,9 @@ func (b *ResourceFlavorApplyConfiguration) WithSpec(value *ResourceFlavorSpecApp b.Spec = value return b } + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *ResourceFlavorApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.Name +} diff --git a/client-go/applyconfiguration/kueue/v1beta1/resourceflavorspec.go b/client-go/applyconfiguration/kueue/v1beta1/resourceflavorspec.go index 9c267adcb3..2c4f8d6bc5 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/resourceflavorspec.go +++ b/client-go/applyconfiguration/kueue/v1beta1/resourceflavorspec.go @@ -21,7 +21,7 @@ import ( v1 "k8s.io/api/core/v1" ) -// ResourceFlavorSpecApplyConfiguration represents an declarative configuration of the ResourceFlavorSpec type for use +// ResourceFlavorSpecApplyConfiguration represents a declarative configuration of the ResourceFlavorSpec type for use // with apply. type ResourceFlavorSpecApplyConfiguration struct { NodeLabels map[string]string `json:"nodeLabels,omitempty"` @@ -29,7 +29,7 @@ type ResourceFlavorSpecApplyConfiguration struct { Tolerations []v1.Toleration `json:"tolerations,omitempty"` } -// ResourceFlavorSpecApplyConfiguration constructs an declarative configuration of the ResourceFlavorSpec type for use with +// ResourceFlavorSpecApplyConfiguration constructs a declarative configuration of the ResourceFlavorSpec type for use with // apply. func ResourceFlavorSpec() *ResourceFlavorSpecApplyConfiguration { return &ResourceFlavorSpecApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/resourcegroup.go b/client-go/applyconfiguration/kueue/v1beta1/resourcegroup.go index d53445d5c9..339842f884 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/resourcegroup.go +++ b/client-go/applyconfiguration/kueue/v1beta1/resourcegroup.go @@ -21,14 +21,14 @@ import ( v1 "k8s.io/api/core/v1" ) -// ResourceGroupApplyConfiguration represents an declarative configuration of the ResourceGroup type for use +// ResourceGroupApplyConfiguration represents a declarative configuration of the ResourceGroup type for use // with apply. type ResourceGroupApplyConfiguration struct { CoveredResources []v1.ResourceName `json:"coveredResources,omitempty"` Flavors []FlavorQuotasApplyConfiguration `json:"flavors,omitempty"` } -// ResourceGroupApplyConfiguration constructs an declarative configuration of the ResourceGroup type for use with +// ResourceGroupApplyConfiguration constructs a declarative configuration of the ResourceGroup type for use with // apply. func ResourceGroup() *ResourceGroupApplyConfiguration { return &ResourceGroupApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/resourcequota.go b/client-go/applyconfiguration/kueue/v1beta1/resourcequota.go index 3b68cefba6..8759a2846e 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/resourcequota.go +++ b/client-go/applyconfiguration/kueue/v1beta1/resourcequota.go @@ -22,7 +22,7 @@ import ( resource "k8s.io/apimachinery/pkg/api/resource" ) -// ResourceQuotaApplyConfiguration represents an declarative configuration of the ResourceQuota type for use +// ResourceQuotaApplyConfiguration represents a declarative configuration of the ResourceQuota type for use // with apply. type ResourceQuotaApplyConfiguration struct { Name *v1.ResourceName `json:"name,omitempty"` @@ -31,7 +31,7 @@ type ResourceQuotaApplyConfiguration struct { LendingLimit *resource.Quantity `json:"lendingLimit,omitempty"` } -// ResourceQuotaApplyConfiguration constructs an declarative configuration of the ResourceQuota type for use with +// ResourceQuotaApplyConfiguration constructs a declarative configuration of the ResourceQuota type for use with // apply. func ResourceQuota() *ResourceQuotaApplyConfiguration { return &ResourceQuotaApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/resourceusage.go b/client-go/applyconfiguration/kueue/v1beta1/resourceusage.go index c32a406f26..3c847a2b0f 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/resourceusage.go +++ b/client-go/applyconfiguration/kueue/v1beta1/resourceusage.go @@ -22,7 +22,7 @@ import ( resource "k8s.io/apimachinery/pkg/api/resource" ) -// ResourceUsageApplyConfiguration represents an declarative configuration of the ResourceUsage type for use +// ResourceUsageApplyConfiguration represents a declarative configuration of the ResourceUsage type for use // with apply. type ResourceUsageApplyConfiguration struct { Name *v1.ResourceName `json:"name,omitempty"` @@ -30,7 +30,7 @@ type ResourceUsageApplyConfiguration struct { Borrowed *resource.Quantity `json:"borrowed,omitempty"` } -// ResourceUsageApplyConfiguration constructs an declarative configuration of the ResourceUsage type for use with +// ResourceUsageApplyConfiguration constructs a declarative configuration of the ResourceUsage type for use with // apply. func ResourceUsage() *ResourceUsageApplyConfiguration { return &ResourceUsageApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/workload.go b/client-go/applyconfiguration/kueue/v1beta1/workload.go index 1304ab682b..4cc41d5112 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/workload.go +++ b/client-go/applyconfiguration/kueue/v1beta1/workload.go @@ -23,7 +23,7 @@ import ( v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) -// WorkloadApplyConfiguration represents an declarative configuration of the Workload type for use +// WorkloadApplyConfiguration represents a declarative configuration of the Workload type for use // with apply. type WorkloadApplyConfiguration struct { v1.TypeMetaApplyConfiguration `json:",inline"` @@ -32,7 +32,7 @@ type WorkloadApplyConfiguration struct { Status *WorkloadStatusApplyConfiguration `json:"status,omitempty"` } -// Workload constructs an declarative configuration of the Workload type for use with +// Workload constructs a declarative configuration of the Workload type for use with // apply. func Workload(name, namespace string) *WorkloadApplyConfiguration { b := &WorkloadApplyConfiguration{} @@ -216,3 +216,9 @@ func (b *WorkloadApplyConfiguration) WithStatus(value *WorkloadStatusApplyConfig b.Status = value return b } + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *WorkloadApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.Name +} diff --git a/client-go/applyconfiguration/kueue/v1beta1/workloadpriorityclass.go b/client-go/applyconfiguration/kueue/v1beta1/workloadpriorityclass.go index 322aae8e97..53390cadf5 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/workloadpriorityclass.go +++ b/client-go/applyconfiguration/kueue/v1beta1/workloadpriorityclass.go @@ -23,7 +23,7 @@ import ( v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) -// WorkloadPriorityClassApplyConfiguration represents an declarative configuration of the WorkloadPriorityClass type for use +// WorkloadPriorityClassApplyConfiguration represents a declarative configuration of the WorkloadPriorityClass type for use // with apply. type WorkloadPriorityClassApplyConfiguration struct { v1.TypeMetaApplyConfiguration `json:",inline"` @@ -32,7 +32,7 @@ type WorkloadPriorityClassApplyConfiguration struct { Description *string `json:"description,omitempty"` } -// WorkloadPriorityClass constructs an declarative configuration of the WorkloadPriorityClass type for use with +// WorkloadPriorityClass constructs a declarative configuration of the WorkloadPriorityClass type for use with // apply. func WorkloadPriorityClass(name string) *WorkloadPriorityClassApplyConfiguration { b := &WorkloadPriorityClassApplyConfiguration{} @@ -215,3 +215,9 @@ func (b *WorkloadPriorityClassApplyConfiguration) WithDescription(value string) b.Description = &value return b } + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *WorkloadPriorityClassApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.Name +} diff --git a/client-go/applyconfiguration/kueue/v1beta1/workloadspec.go b/client-go/applyconfiguration/kueue/v1beta1/workloadspec.go index bc20f5edd8..11280bed75 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/workloadspec.go +++ b/client-go/applyconfiguration/kueue/v1beta1/workloadspec.go @@ -17,7 +17,7 @@ limitations under the License. package v1beta1 -// WorkloadSpecApplyConfiguration represents an declarative configuration of the WorkloadSpec type for use +// WorkloadSpecApplyConfiguration represents a declarative configuration of the WorkloadSpec type for use // with apply. type WorkloadSpecApplyConfiguration struct { PodSets []PodSetApplyConfiguration `json:"podSets,omitempty"` @@ -28,7 +28,7 @@ type WorkloadSpecApplyConfiguration struct { Active *bool `json:"active,omitempty"` } -// WorkloadSpecApplyConfiguration constructs an declarative configuration of the WorkloadSpec type for use with +// WorkloadSpecApplyConfiguration constructs a declarative configuration of the WorkloadSpec type for use with // apply. func WorkloadSpec() *WorkloadSpecApplyConfiguration { return &WorkloadSpecApplyConfiguration{} diff --git a/client-go/applyconfiguration/kueue/v1beta1/workloadstatus.go b/client-go/applyconfiguration/kueue/v1beta1/workloadstatus.go index b5c72d11eb..022e37d5e1 100644 --- a/client-go/applyconfiguration/kueue/v1beta1/workloadstatus.go +++ b/client-go/applyconfiguration/kueue/v1beta1/workloadstatus.go @@ -18,20 +18,20 @@ limitations under the License. package v1beta1 import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) -// WorkloadStatusApplyConfiguration represents an declarative configuration of the WorkloadStatus type for use +// WorkloadStatusApplyConfiguration represents a declarative configuration of the WorkloadStatus type for use // with apply. type WorkloadStatusApplyConfiguration struct { Admission *AdmissionApplyConfiguration `json:"admission,omitempty"` RequeueState *RequeueStateApplyConfiguration `json:"requeueState,omitempty"` - Conditions []v1.Condition `json:"conditions,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` ReclaimablePods []ReclaimablePodApplyConfiguration `json:"reclaimablePods,omitempty"` AdmissionChecks []AdmissionCheckStateApplyConfiguration `json:"admissionChecks,omitempty"` } -// WorkloadStatusApplyConfiguration constructs an declarative configuration of the WorkloadStatus type for use with +// WorkloadStatusApplyConfiguration constructs a declarative configuration of the WorkloadStatus type for use with // apply. func WorkloadStatus() *WorkloadStatusApplyConfiguration { return &WorkloadStatusApplyConfiguration{} @@ -56,9 +56,12 @@ func (b *WorkloadStatusApplyConfiguration) WithRequeueState(value *RequeueStateA // WithConditions adds the given value to the Conditions field in the declarative configuration // and returns the receiver, so that objects can be build by chaining "With" function invocations. // If called multiple times, values provided by each call will be appended to the Conditions field. -func (b *WorkloadStatusApplyConfiguration) WithConditions(values ...v1.Condition) *WorkloadStatusApplyConfiguration { +func (b *WorkloadStatusApplyConfiguration) WithConditions(values ...*v1.ConditionApplyConfiguration) *WorkloadStatusApplyConfiguration { for i := range values { - b.Conditions = append(b.Conditions, values[i]) + if values[i] == nil { + panic("nil value passed to WithConditions") + } + b.Conditions = append(b.Conditions, *values[i]) } return b } diff --git a/client-go/applyconfiguration/utils.go b/client-go/applyconfiguration/utils.go index 58c3961c1b..f7457c4086 100644 --- a/client-go/applyconfiguration/utils.go +++ b/client-go/applyconfiguration/utils.go @@ -18,10 +18,13 @@ limitations under the License. package applyconfiguration import ( + runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" + testing "k8s.io/client-go/testing" v1alpha1 "sigs.k8s.io/kueue/apis/kueue/v1alpha1" v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" visibilityv1alpha1 "sigs.k8s.io/kueue/apis/visibility/v1alpha1" + internal "sigs.k8s.io/kueue/client-go/applyconfiguration/internal" kueuev1alpha1 "sigs.k8s.io/kueue/client-go/applyconfiguration/kueue/v1alpha1" kueuev1beta1 "sigs.k8s.io/kueue/client-go/applyconfiguration/kueue/v1beta1" applyconfigurationvisibilityv1alpha1 "sigs.k8s.io/kueue/client-go/applyconfiguration/visibility/v1alpha1" @@ -142,3 +145,7 @@ func ForKind(kind schema.GroupVersionKind) interface{} { } return nil } + +func NewTypeConverter(scheme *runtime.Scheme) *testing.TypeConverter { + return &testing.TypeConverter{Scheme: scheme, TypeResolver: internal.Parser()} +} diff --git a/client-go/applyconfiguration/visibility/v1alpha1/clusterqueue.go b/client-go/applyconfiguration/visibility/v1alpha1/clusterqueue.go index dd6baa3506..997e27fa55 100644 --- a/client-go/applyconfiguration/visibility/v1alpha1/clusterqueue.go +++ b/client-go/applyconfiguration/visibility/v1alpha1/clusterqueue.go @@ -23,7 +23,7 @@ import ( v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) -// ClusterQueueApplyConfiguration represents an declarative configuration of the ClusterQueue type for use +// ClusterQueueApplyConfiguration represents a declarative configuration of the ClusterQueue type for use // with apply. type ClusterQueueApplyConfiguration struct { v1.TypeMetaApplyConfiguration `json:",inline"` @@ -31,7 +31,7 @@ type ClusterQueueApplyConfiguration struct { Summary *PendingWorkloadsSummaryApplyConfiguration `json:"pendingWorkloadsSummary,omitempty"` } -// ClusterQueue constructs an declarative configuration of the ClusterQueue type for use with +// ClusterQueue constructs a declarative configuration of the ClusterQueue type for use with // apply. func ClusterQueue(name string) *ClusterQueueApplyConfiguration { b := &ClusterQueueApplyConfiguration{} @@ -206,3 +206,9 @@ func (b *ClusterQueueApplyConfiguration) WithSummary(value *PendingWorkloadsSumm b.Summary = value return b } + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *ClusterQueueApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.Name +} diff --git a/client-go/applyconfiguration/visibility/v1alpha1/localqueue.go b/client-go/applyconfiguration/visibility/v1alpha1/localqueue.go index bbf7d7ea4c..807e1188cc 100644 --- a/client-go/applyconfiguration/visibility/v1alpha1/localqueue.go +++ b/client-go/applyconfiguration/visibility/v1alpha1/localqueue.go @@ -23,7 +23,7 @@ import ( v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) -// LocalQueueApplyConfiguration represents an declarative configuration of the LocalQueue type for use +// LocalQueueApplyConfiguration represents a declarative configuration of the LocalQueue type for use // with apply. type LocalQueueApplyConfiguration struct { v1.TypeMetaApplyConfiguration `json:",inline"` @@ -31,7 +31,7 @@ type LocalQueueApplyConfiguration struct { Summary *PendingWorkloadsSummaryApplyConfiguration `json:"pendingWorkloadsSummary,omitempty"` } -// LocalQueue constructs an declarative configuration of the LocalQueue type for use with +// LocalQueue constructs a declarative configuration of the LocalQueue type for use with // apply. func LocalQueue(name, namespace string) *LocalQueueApplyConfiguration { b := &LocalQueueApplyConfiguration{} @@ -207,3 +207,9 @@ func (b *LocalQueueApplyConfiguration) WithSummary(value *PendingWorkloadsSummar b.Summary = value return b } + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *LocalQueueApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.Name +} diff --git a/client-go/applyconfiguration/visibility/v1alpha1/pendingworkload.go b/client-go/applyconfiguration/visibility/v1alpha1/pendingworkload.go index 4ec90b4f65..2e7340996b 100644 --- a/client-go/applyconfiguration/visibility/v1alpha1/pendingworkload.go +++ b/client-go/applyconfiguration/visibility/v1alpha1/pendingworkload.go @@ -23,7 +23,7 @@ import ( v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) -// PendingWorkloadApplyConfiguration represents an declarative configuration of the PendingWorkload type for use +// PendingWorkloadApplyConfiguration represents a declarative configuration of the PendingWorkload type for use // with apply. type PendingWorkloadApplyConfiguration struct { *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` @@ -33,7 +33,7 @@ type PendingWorkloadApplyConfiguration struct { PositionInLocalQueue *int32 `json:"positionInLocalQueue,omitempty"` } -// PendingWorkloadApplyConfiguration constructs an declarative configuration of the PendingWorkload type for use with +// PendingWorkloadApplyConfiguration constructs a declarative configuration of the PendingWorkload type for use with // apply. func PendingWorkload() *PendingWorkloadApplyConfiguration { return &PendingWorkloadApplyConfiguration{} @@ -212,3 +212,9 @@ func (b *PendingWorkloadApplyConfiguration) WithPositionInLocalQueue(value int32 b.PositionInLocalQueue = &value return b } + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *PendingWorkloadApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.Name +} diff --git a/client-go/applyconfiguration/visibility/v1alpha1/pendingworkloadssummary.go b/client-go/applyconfiguration/visibility/v1alpha1/pendingworkloadssummary.go index 5fb91bd725..55e8f06ca3 100644 --- a/client-go/applyconfiguration/visibility/v1alpha1/pendingworkloadssummary.go +++ b/client-go/applyconfiguration/visibility/v1alpha1/pendingworkloadssummary.go @@ -23,7 +23,7 @@ import ( v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) -// PendingWorkloadsSummaryApplyConfiguration represents an declarative configuration of the PendingWorkloadsSummary type for use +// PendingWorkloadsSummaryApplyConfiguration represents a declarative configuration of the PendingWorkloadsSummary type for use // with apply. type PendingWorkloadsSummaryApplyConfiguration struct { v1.TypeMetaApplyConfiguration `json:",inline"` @@ -31,7 +31,7 @@ type PendingWorkloadsSummaryApplyConfiguration struct { Items []PendingWorkloadApplyConfiguration `json:"items,omitempty"` } -// PendingWorkloadsSummaryApplyConfiguration constructs an declarative configuration of the PendingWorkloadsSummary type for use with +// PendingWorkloadsSummaryApplyConfiguration constructs a declarative configuration of the PendingWorkloadsSummary type for use with // apply. func PendingWorkloadsSummary() *PendingWorkloadsSummaryApplyConfiguration { b := &PendingWorkloadsSummaryApplyConfiguration{} @@ -210,3 +210,9 @@ func (b *PendingWorkloadsSummaryApplyConfiguration) WithItems(values ...*Pending } return b } + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *PendingWorkloadsSummaryApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.Name +} diff --git a/client-go/clientset/versioned/fake/clientset_generated.go b/client-go/clientset/versioned/fake/clientset_generated.go index 2914c2175b..7a94d3d3ee 100644 --- a/client-go/clientset/versioned/fake/clientset_generated.go +++ b/client-go/clientset/versioned/fake/clientset_generated.go @@ -23,6 +23,7 @@ import ( "k8s.io/client-go/discovery" fakediscovery "k8s.io/client-go/discovery/fake" "k8s.io/client-go/testing" + applyconfiguration "sigs.k8s.io/kueue/client-go/applyconfiguration" clientset "sigs.k8s.io/kueue/client-go/clientset/versioned" kueuev1alpha1 "sigs.k8s.io/kueue/client-go/clientset/versioned/typed/kueue/v1alpha1" fakekueuev1alpha1 "sigs.k8s.io/kueue/client-go/clientset/versioned/typed/kueue/v1alpha1/fake" @@ -34,8 +35,12 @@ import ( // NewSimpleClientset returns a clientset that will respond with the provided objects. // It's backed by a very simple object tracker that processes creates, updates and deletions as-is, -// without applying any validations and/or defaults. It shouldn't be considered a replacement +// without applying any field management, validations and/or defaults. It shouldn't be considered a replacement // for a real clientset and is mostly useful in simple unit tests. +// +// DEPRECATED: NewClientset replaces this with support for field management, which significantly improves +// server side apply testing. NewClientset is only available when apply configurations are generated (e.g. +// via --with-applyconfig). func NewSimpleClientset(objects ...runtime.Object) *Clientset { o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) for _, obj := range objects { @@ -77,6 +82,38 @@ func (c *Clientset) Tracker() testing.ObjectTracker { return c.tracker } +// NewClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +func NewClientset(objects ...runtime.Object) *Clientset { + o := testing.NewFieldManagedObjectTracker( + scheme, + codecs.UniversalDecoder(), + applyconfiguration.NewTypeConverter(scheme), + ) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{tracker: o} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + var ( _ clientset.Interface = &Clientset{} _ testing.FakeClient = &Clientset{} diff --git a/client-go/clientset/versioned/typed/kueue/v1alpha1/fake/fake_multikueuecluster.go b/client-go/clientset/versioned/typed/kueue/v1alpha1/fake/fake_multikueuecluster.go index 70509a5bf9..fabab7c1cb 100644 --- a/client-go/clientset/versioned/typed/kueue/v1alpha1/fake/fake_multikueuecluster.go +++ b/client-go/clientset/versioned/typed/kueue/v1alpha1/fake/fake_multikueuecluster.go @@ -42,20 +42,22 @@ var multikueueclustersKind = v1alpha1.SchemeGroupVersion.WithKind("MultiKueueClu // Get takes name of the multiKueueCluster, and returns the corresponding multiKueueCluster object, and an error if there is any. func (c *FakeMultiKueueClusters) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.MultiKueueCluster, err error) { + emptyResult := &v1alpha1.MultiKueueCluster{} obj, err := c.Fake. - Invokes(testing.NewRootGetAction(multikueueclustersResource, name), &v1alpha1.MultiKueueCluster{}) + Invokes(testing.NewRootGetActionWithOptions(multikueueclustersResource, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.MultiKueueCluster), err } // List takes label and field selectors, and returns the list of MultiKueueClusters that match those selectors. func (c *FakeMultiKueueClusters) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.MultiKueueClusterList, err error) { + emptyResult := &v1alpha1.MultiKueueClusterList{} obj, err := c.Fake. - Invokes(testing.NewRootListAction(multikueueclustersResource, multikueueclustersKind, opts), &v1alpha1.MultiKueueClusterList{}) + Invokes(testing.NewRootListActionWithOptions(multikueueclustersResource, multikueueclustersKind, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -74,36 +76,39 @@ func (c *FakeMultiKueueClusters) List(ctx context.Context, opts v1.ListOptions) // Watch returns a watch.Interface that watches the requested multiKueueClusters. func (c *FakeMultiKueueClusters) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewRootWatchAction(multikueueclustersResource, opts)) + InvokesWatch(testing.NewRootWatchActionWithOptions(multikueueclustersResource, opts)) } // Create takes the representation of a multiKueueCluster and creates it. Returns the server's representation of the multiKueueCluster, and an error, if there is any. func (c *FakeMultiKueueClusters) Create(ctx context.Context, multiKueueCluster *v1alpha1.MultiKueueCluster, opts v1.CreateOptions) (result *v1alpha1.MultiKueueCluster, err error) { + emptyResult := &v1alpha1.MultiKueueCluster{} obj, err := c.Fake. - Invokes(testing.NewRootCreateAction(multikueueclustersResource, multiKueueCluster), &v1alpha1.MultiKueueCluster{}) + Invokes(testing.NewRootCreateActionWithOptions(multikueueclustersResource, multiKueueCluster, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.MultiKueueCluster), err } // Update takes the representation of a multiKueueCluster and updates it. Returns the server's representation of the multiKueueCluster, and an error, if there is any. func (c *FakeMultiKueueClusters) Update(ctx context.Context, multiKueueCluster *v1alpha1.MultiKueueCluster, opts v1.UpdateOptions) (result *v1alpha1.MultiKueueCluster, err error) { + emptyResult := &v1alpha1.MultiKueueCluster{} obj, err := c.Fake. - Invokes(testing.NewRootUpdateAction(multikueueclustersResource, multiKueueCluster), &v1alpha1.MultiKueueCluster{}) + Invokes(testing.NewRootUpdateActionWithOptions(multikueueclustersResource, multiKueueCluster, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.MultiKueueCluster), err } // UpdateStatus was generated because the type contains a Status member. // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeMultiKueueClusters) UpdateStatus(ctx context.Context, multiKueueCluster *v1alpha1.MultiKueueCluster, opts v1.UpdateOptions) (*v1alpha1.MultiKueueCluster, error) { +func (c *FakeMultiKueueClusters) UpdateStatus(ctx context.Context, multiKueueCluster *v1alpha1.MultiKueueCluster, opts v1.UpdateOptions) (result *v1alpha1.MultiKueueCluster, err error) { + emptyResult := &v1alpha1.MultiKueueCluster{} obj, err := c.Fake. - Invokes(testing.NewRootUpdateSubresourceAction(multikueueclustersResource, "status", multiKueueCluster), &v1alpha1.MultiKueueCluster{}) + Invokes(testing.NewRootUpdateSubresourceActionWithOptions(multikueueclustersResource, "status", multiKueueCluster, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.MultiKueueCluster), err } @@ -117,7 +122,7 @@ func (c *FakeMultiKueueClusters) Delete(ctx context.Context, name string, opts v // DeleteCollection deletes a collection of objects. func (c *FakeMultiKueueClusters) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewRootDeleteCollectionAction(multikueueclustersResource, listOpts) + action := testing.NewRootDeleteCollectionActionWithOptions(multikueueclustersResource, opts, listOpts) _, err := c.Fake.Invokes(action, &v1alpha1.MultiKueueClusterList{}) return err @@ -125,10 +130,11 @@ func (c *FakeMultiKueueClusters) DeleteCollection(ctx context.Context, opts v1.D // Patch applies the patch and returns the patched multiKueueCluster. func (c *FakeMultiKueueClusters) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.MultiKueueCluster, err error) { + emptyResult := &v1alpha1.MultiKueueCluster{} obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(multikueueclustersResource, name, pt, data, subresources...), &v1alpha1.MultiKueueCluster{}) + Invokes(testing.NewRootPatchSubresourceActionWithOptions(multikueueclustersResource, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.MultiKueueCluster), err } @@ -146,10 +152,11 @@ func (c *FakeMultiKueueClusters) Apply(ctx context.Context, multiKueueCluster *k if name == nil { return nil, fmt.Errorf("multiKueueCluster.Name must be provided to Apply") } + emptyResult := &v1alpha1.MultiKueueCluster{} obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(multikueueclustersResource, *name, types.ApplyPatchType, data), &v1alpha1.MultiKueueCluster{}) + Invokes(testing.NewRootPatchSubresourceActionWithOptions(multikueueclustersResource, *name, types.ApplyPatchType, data, opts.ToPatchOptions()), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.MultiKueueCluster), err } @@ -168,10 +175,11 @@ func (c *FakeMultiKueueClusters) ApplyStatus(ctx context.Context, multiKueueClus if name == nil { return nil, fmt.Errorf("multiKueueCluster.Name must be provided to Apply") } + emptyResult := &v1alpha1.MultiKueueCluster{} obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(multikueueclustersResource, *name, types.ApplyPatchType, data, "status"), &v1alpha1.MultiKueueCluster{}) + Invokes(testing.NewRootPatchSubresourceActionWithOptions(multikueueclustersResource, *name, types.ApplyPatchType, data, opts.ToPatchOptions(), "status"), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.MultiKueueCluster), err } diff --git a/client-go/clientset/versioned/typed/kueue/v1alpha1/fake/fake_multikueueconfig.go b/client-go/clientset/versioned/typed/kueue/v1alpha1/fake/fake_multikueueconfig.go index 4a256e025b..e47906f270 100644 --- a/client-go/clientset/versioned/typed/kueue/v1alpha1/fake/fake_multikueueconfig.go +++ b/client-go/clientset/versioned/typed/kueue/v1alpha1/fake/fake_multikueueconfig.go @@ -42,20 +42,22 @@ var multikueueconfigsKind = v1alpha1.SchemeGroupVersion.WithKind("MultiKueueConf // Get takes name of the multiKueueConfig, and returns the corresponding multiKueueConfig object, and an error if there is any. func (c *FakeMultiKueueConfigs) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.MultiKueueConfig, err error) { + emptyResult := &v1alpha1.MultiKueueConfig{} obj, err := c.Fake. - Invokes(testing.NewRootGetAction(multikueueconfigsResource, name), &v1alpha1.MultiKueueConfig{}) + Invokes(testing.NewRootGetActionWithOptions(multikueueconfigsResource, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.MultiKueueConfig), err } // List takes label and field selectors, and returns the list of MultiKueueConfigs that match those selectors. func (c *FakeMultiKueueConfigs) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.MultiKueueConfigList, err error) { + emptyResult := &v1alpha1.MultiKueueConfigList{} obj, err := c.Fake. - Invokes(testing.NewRootListAction(multikueueconfigsResource, multikueueconfigsKind, opts), &v1alpha1.MultiKueueConfigList{}) + Invokes(testing.NewRootListActionWithOptions(multikueueconfigsResource, multikueueconfigsKind, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -74,25 +76,27 @@ func (c *FakeMultiKueueConfigs) List(ctx context.Context, opts v1.ListOptions) ( // Watch returns a watch.Interface that watches the requested multiKueueConfigs. func (c *FakeMultiKueueConfigs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewRootWatchAction(multikueueconfigsResource, opts)) + InvokesWatch(testing.NewRootWatchActionWithOptions(multikueueconfigsResource, opts)) } // Create takes the representation of a multiKueueConfig and creates it. Returns the server's representation of the multiKueueConfig, and an error, if there is any. func (c *FakeMultiKueueConfigs) Create(ctx context.Context, multiKueueConfig *v1alpha1.MultiKueueConfig, opts v1.CreateOptions) (result *v1alpha1.MultiKueueConfig, err error) { + emptyResult := &v1alpha1.MultiKueueConfig{} obj, err := c.Fake. - Invokes(testing.NewRootCreateAction(multikueueconfigsResource, multiKueueConfig), &v1alpha1.MultiKueueConfig{}) + Invokes(testing.NewRootCreateActionWithOptions(multikueueconfigsResource, multiKueueConfig, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.MultiKueueConfig), err } // Update takes the representation of a multiKueueConfig and updates it. Returns the server's representation of the multiKueueConfig, and an error, if there is any. func (c *FakeMultiKueueConfigs) Update(ctx context.Context, multiKueueConfig *v1alpha1.MultiKueueConfig, opts v1.UpdateOptions) (result *v1alpha1.MultiKueueConfig, err error) { + emptyResult := &v1alpha1.MultiKueueConfig{} obj, err := c.Fake. - Invokes(testing.NewRootUpdateAction(multikueueconfigsResource, multiKueueConfig), &v1alpha1.MultiKueueConfig{}) + Invokes(testing.NewRootUpdateActionWithOptions(multikueueconfigsResource, multiKueueConfig, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.MultiKueueConfig), err } @@ -106,7 +110,7 @@ func (c *FakeMultiKueueConfigs) Delete(ctx context.Context, name string, opts v1 // DeleteCollection deletes a collection of objects. func (c *FakeMultiKueueConfigs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewRootDeleteCollectionAction(multikueueconfigsResource, listOpts) + action := testing.NewRootDeleteCollectionActionWithOptions(multikueueconfigsResource, opts, listOpts) _, err := c.Fake.Invokes(action, &v1alpha1.MultiKueueConfigList{}) return err @@ -114,10 +118,11 @@ func (c *FakeMultiKueueConfigs) DeleteCollection(ctx context.Context, opts v1.De // Patch applies the patch and returns the patched multiKueueConfig. func (c *FakeMultiKueueConfigs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.MultiKueueConfig, err error) { + emptyResult := &v1alpha1.MultiKueueConfig{} obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(multikueueconfigsResource, name, pt, data, subresources...), &v1alpha1.MultiKueueConfig{}) + Invokes(testing.NewRootPatchSubresourceActionWithOptions(multikueueconfigsResource, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.MultiKueueConfig), err } @@ -135,10 +140,11 @@ func (c *FakeMultiKueueConfigs) Apply(ctx context.Context, multiKueueConfig *kue if name == nil { return nil, fmt.Errorf("multiKueueConfig.Name must be provided to Apply") } + emptyResult := &v1alpha1.MultiKueueConfig{} obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(multikueueconfigsResource, *name, types.ApplyPatchType, data), &v1alpha1.MultiKueueConfig{}) + Invokes(testing.NewRootPatchSubresourceActionWithOptions(multikueueconfigsResource, *name, types.ApplyPatchType, data, opts.ToPatchOptions()), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.MultiKueueConfig), err } diff --git a/client-go/clientset/versioned/typed/kueue/v1alpha1/multikueuecluster.go b/client-go/clientset/versioned/typed/kueue/v1alpha1/multikueuecluster.go index 9851c39d41..ccd051c7b9 100644 --- a/client-go/clientset/versioned/typed/kueue/v1alpha1/multikueuecluster.go +++ b/client-go/clientset/versioned/typed/kueue/v1alpha1/multikueuecluster.go @@ -19,14 +19,11 @@ package v1alpha1 import ( "context" - json "encoding/json" - "fmt" - "time" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" v1alpha1 "sigs.k8s.io/kueue/apis/kueue/v1alpha1" kueuev1alpha1 "sigs.k8s.io/kueue/client-go/applyconfiguration/kueue/v1alpha1" scheme "sigs.k8s.io/kueue/client-go/clientset/versioned/scheme" @@ -42,6 +39,7 @@ type MultiKueueClustersGetter interface { type MultiKueueClusterInterface interface { Create(ctx context.Context, multiKueueCluster *v1alpha1.MultiKueueCluster, opts v1.CreateOptions) (*v1alpha1.MultiKueueCluster, error) Update(ctx context.Context, multiKueueCluster *v1alpha1.MultiKueueCluster, opts v1.UpdateOptions) (*v1alpha1.MultiKueueCluster, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). UpdateStatus(ctx context.Context, multiKueueCluster *v1alpha1.MultiKueueCluster, opts v1.UpdateOptions) (*v1alpha1.MultiKueueCluster, error) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error @@ -50,193 +48,25 @@ type MultiKueueClusterInterface interface { Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.MultiKueueCluster, err error) Apply(ctx context.Context, multiKueueCluster *kueuev1alpha1.MultiKueueClusterApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.MultiKueueCluster, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). ApplyStatus(ctx context.Context, multiKueueCluster *kueuev1alpha1.MultiKueueClusterApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.MultiKueueCluster, err error) MultiKueueClusterExpansion } // multiKueueClusters implements MultiKueueClusterInterface type multiKueueClusters struct { - client rest.Interface + *gentype.ClientWithListAndApply[*v1alpha1.MultiKueueCluster, *v1alpha1.MultiKueueClusterList, *kueuev1alpha1.MultiKueueClusterApplyConfiguration] } // newMultiKueueClusters returns a MultiKueueClusters func newMultiKueueClusters(c *KueueV1alpha1Client) *multiKueueClusters { return &multiKueueClusters{ - client: c.RESTClient(), + gentype.NewClientWithListAndApply[*v1alpha1.MultiKueueCluster, *v1alpha1.MultiKueueClusterList, *kueuev1alpha1.MultiKueueClusterApplyConfiguration]( + "multikueueclusters", + c.RESTClient(), + scheme.ParameterCodec, + "", + func() *v1alpha1.MultiKueueCluster { return &v1alpha1.MultiKueueCluster{} }, + func() *v1alpha1.MultiKueueClusterList { return &v1alpha1.MultiKueueClusterList{} }), } } - -// Get takes name of the multiKueueCluster, and returns the corresponding multiKueueCluster object, and an error if there is any. -func (c *multiKueueClusters) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.MultiKueueCluster, err error) { - result = &v1alpha1.MultiKueueCluster{} - err = c.client.Get(). - Resource("multikueueclusters"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of MultiKueueClusters that match those selectors. -func (c *multiKueueClusters) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.MultiKueueClusterList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.MultiKueueClusterList{} - err = c.client.Get(). - Resource("multikueueclusters"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested multiKueueClusters. -func (c *multiKueueClusters) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Resource("multikueueclusters"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a multiKueueCluster and creates it. Returns the server's representation of the multiKueueCluster, and an error, if there is any. -func (c *multiKueueClusters) Create(ctx context.Context, multiKueueCluster *v1alpha1.MultiKueueCluster, opts v1.CreateOptions) (result *v1alpha1.MultiKueueCluster, err error) { - result = &v1alpha1.MultiKueueCluster{} - err = c.client.Post(). - Resource("multikueueclusters"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(multiKueueCluster). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a multiKueueCluster and updates it. Returns the server's representation of the multiKueueCluster, and an error, if there is any. -func (c *multiKueueClusters) Update(ctx context.Context, multiKueueCluster *v1alpha1.MultiKueueCluster, opts v1.UpdateOptions) (result *v1alpha1.MultiKueueCluster, err error) { - result = &v1alpha1.MultiKueueCluster{} - err = c.client.Put(). - Resource("multikueueclusters"). - Name(multiKueueCluster.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(multiKueueCluster). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *multiKueueClusters) UpdateStatus(ctx context.Context, multiKueueCluster *v1alpha1.MultiKueueCluster, opts v1.UpdateOptions) (result *v1alpha1.MultiKueueCluster, err error) { - result = &v1alpha1.MultiKueueCluster{} - err = c.client.Put(). - Resource("multikueueclusters"). - Name(multiKueueCluster.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(multiKueueCluster). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the multiKueueCluster and deletes it. Returns an error if one occurs. -func (c *multiKueueClusters) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Resource("multikueueclusters"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *multiKueueClusters) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Resource("multikueueclusters"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched multiKueueCluster. -func (c *multiKueueClusters) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.MultiKueueCluster, err error) { - result = &v1alpha1.MultiKueueCluster{} - err = c.client.Patch(pt). - Resource("multikueueclusters"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} - -// Apply takes the given apply declarative configuration, applies it and returns the applied multiKueueCluster. -func (c *multiKueueClusters) Apply(ctx context.Context, multiKueueCluster *kueuev1alpha1.MultiKueueClusterApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.MultiKueueCluster, err error) { - if multiKueueCluster == nil { - return nil, fmt.Errorf("multiKueueCluster provided to Apply must not be nil") - } - patchOpts := opts.ToPatchOptions() - data, err := json.Marshal(multiKueueCluster) - if err != nil { - return nil, err - } - name := multiKueueCluster.Name - if name == nil { - return nil, fmt.Errorf("multiKueueCluster.Name must be provided to Apply") - } - result = &v1alpha1.MultiKueueCluster{} - err = c.client.Patch(types.ApplyPatchType). - Resource("multikueueclusters"). - Name(*name). - VersionedParams(&patchOpts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} - -// ApplyStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). -func (c *multiKueueClusters) ApplyStatus(ctx context.Context, multiKueueCluster *kueuev1alpha1.MultiKueueClusterApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.MultiKueueCluster, err error) { - if multiKueueCluster == nil { - return nil, fmt.Errorf("multiKueueCluster provided to Apply must not be nil") - } - patchOpts := opts.ToPatchOptions() - data, err := json.Marshal(multiKueueCluster) - if err != nil { - return nil, err - } - - name := multiKueueCluster.Name - if name == nil { - return nil, fmt.Errorf("multiKueueCluster.Name must be provided to Apply") - } - - result = &v1alpha1.MultiKueueCluster{} - err = c.client.Patch(types.ApplyPatchType). - Resource("multikueueclusters"). - Name(*name). - SubResource("status"). - VersionedParams(&patchOpts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/client-go/clientset/versioned/typed/kueue/v1alpha1/multikueueconfig.go b/client-go/clientset/versioned/typed/kueue/v1alpha1/multikueueconfig.go index 0e093892f7..d5927a5a89 100644 --- a/client-go/clientset/versioned/typed/kueue/v1alpha1/multikueueconfig.go +++ b/client-go/clientset/versioned/typed/kueue/v1alpha1/multikueueconfig.go @@ -19,14 +19,11 @@ package v1alpha1 import ( "context" - json "encoding/json" - "fmt" - "time" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" v1alpha1 "sigs.k8s.io/kueue/apis/kueue/v1alpha1" kueuev1alpha1 "sigs.k8s.io/kueue/client-go/applyconfiguration/kueue/v1alpha1" scheme "sigs.k8s.io/kueue/client-go/clientset/versioned/scheme" @@ -54,143 +51,18 @@ type MultiKueueConfigInterface interface { // multiKueueConfigs implements MultiKueueConfigInterface type multiKueueConfigs struct { - client rest.Interface + *gentype.ClientWithListAndApply[*v1alpha1.MultiKueueConfig, *v1alpha1.MultiKueueConfigList, *kueuev1alpha1.MultiKueueConfigApplyConfiguration] } // newMultiKueueConfigs returns a MultiKueueConfigs func newMultiKueueConfigs(c *KueueV1alpha1Client) *multiKueueConfigs { return &multiKueueConfigs{ - client: c.RESTClient(), + gentype.NewClientWithListAndApply[*v1alpha1.MultiKueueConfig, *v1alpha1.MultiKueueConfigList, *kueuev1alpha1.MultiKueueConfigApplyConfiguration]( + "multikueueconfigs", + c.RESTClient(), + scheme.ParameterCodec, + "", + func() *v1alpha1.MultiKueueConfig { return &v1alpha1.MultiKueueConfig{} }, + func() *v1alpha1.MultiKueueConfigList { return &v1alpha1.MultiKueueConfigList{} }), } } - -// Get takes name of the multiKueueConfig, and returns the corresponding multiKueueConfig object, and an error if there is any. -func (c *multiKueueConfigs) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.MultiKueueConfig, err error) { - result = &v1alpha1.MultiKueueConfig{} - err = c.client.Get(). - Resource("multikueueconfigs"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of MultiKueueConfigs that match those selectors. -func (c *multiKueueConfigs) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.MultiKueueConfigList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.MultiKueueConfigList{} - err = c.client.Get(). - Resource("multikueueconfigs"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested multiKueueConfigs. -func (c *multiKueueConfigs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Resource("multikueueconfigs"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a multiKueueConfig and creates it. Returns the server's representation of the multiKueueConfig, and an error, if there is any. -func (c *multiKueueConfigs) Create(ctx context.Context, multiKueueConfig *v1alpha1.MultiKueueConfig, opts v1.CreateOptions) (result *v1alpha1.MultiKueueConfig, err error) { - result = &v1alpha1.MultiKueueConfig{} - err = c.client.Post(). - Resource("multikueueconfigs"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(multiKueueConfig). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a multiKueueConfig and updates it. Returns the server's representation of the multiKueueConfig, and an error, if there is any. -func (c *multiKueueConfigs) Update(ctx context.Context, multiKueueConfig *v1alpha1.MultiKueueConfig, opts v1.UpdateOptions) (result *v1alpha1.MultiKueueConfig, err error) { - result = &v1alpha1.MultiKueueConfig{} - err = c.client.Put(). - Resource("multikueueconfigs"). - Name(multiKueueConfig.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(multiKueueConfig). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the multiKueueConfig and deletes it. Returns an error if one occurs. -func (c *multiKueueConfigs) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Resource("multikueueconfigs"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *multiKueueConfigs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Resource("multikueueconfigs"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched multiKueueConfig. -func (c *multiKueueConfigs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.MultiKueueConfig, err error) { - result = &v1alpha1.MultiKueueConfig{} - err = c.client.Patch(pt). - Resource("multikueueconfigs"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} - -// Apply takes the given apply declarative configuration, applies it and returns the applied multiKueueConfig. -func (c *multiKueueConfigs) Apply(ctx context.Context, multiKueueConfig *kueuev1alpha1.MultiKueueConfigApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.MultiKueueConfig, err error) { - if multiKueueConfig == nil { - return nil, fmt.Errorf("multiKueueConfig provided to Apply must not be nil") - } - patchOpts := opts.ToPatchOptions() - data, err := json.Marshal(multiKueueConfig) - if err != nil { - return nil, err - } - name := multiKueueConfig.Name - if name == nil { - return nil, fmt.Errorf("multiKueueConfig.Name must be provided to Apply") - } - result = &v1alpha1.MultiKueueConfig{} - err = c.client.Patch(types.ApplyPatchType). - Resource("multikueueconfigs"). - Name(*name). - VersionedParams(&patchOpts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/client-go/clientset/versioned/typed/kueue/v1beta1/admissioncheck.go b/client-go/clientset/versioned/typed/kueue/v1beta1/admissioncheck.go index e0dd0ced46..9f110e4bcc 100644 --- a/client-go/clientset/versioned/typed/kueue/v1beta1/admissioncheck.go +++ b/client-go/clientset/versioned/typed/kueue/v1beta1/admissioncheck.go @@ -19,14 +19,11 @@ package v1beta1 import ( "context" - json "encoding/json" - "fmt" - "time" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" kueuev1beta1 "sigs.k8s.io/kueue/client-go/applyconfiguration/kueue/v1beta1" scheme "sigs.k8s.io/kueue/client-go/clientset/versioned/scheme" @@ -42,6 +39,7 @@ type AdmissionChecksGetter interface { type AdmissionCheckInterface interface { Create(ctx context.Context, admissionCheck *v1beta1.AdmissionCheck, opts v1.CreateOptions) (*v1beta1.AdmissionCheck, error) Update(ctx context.Context, admissionCheck *v1beta1.AdmissionCheck, opts v1.UpdateOptions) (*v1beta1.AdmissionCheck, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). UpdateStatus(ctx context.Context, admissionCheck *v1beta1.AdmissionCheck, opts v1.UpdateOptions) (*v1beta1.AdmissionCheck, error) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error @@ -50,193 +48,25 @@ type AdmissionCheckInterface interface { Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.AdmissionCheck, err error) Apply(ctx context.Context, admissionCheck *kueuev1beta1.AdmissionCheckApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.AdmissionCheck, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). ApplyStatus(ctx context.Context, admissionCheck *kueuev1beta1.AdmissionCheckApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.AdmissionCheck, err error) AdmissionCheckExpansion } // admissionChecks implements AdmissionCheckInterface type admissionChecks struct { - client rest.Interface + *gentype.ClientWithListAndApply[*v1beta1.AdmissionCheck, *v1beta1.AdmissionCheckList, *kueuev1beta1.AdmissionCheckApplyConfiguration] } // newAdmissionChecks returns a AdmissionChecks func newAdmissionChecks(c *KueueV1beta1Client) *admissionChecks { return &admissionChecks{ - client: c.RESTClient(), + gentype.NewClientWithListAndApply[*v1beta1.AdmissionCheck, *v1beta1.AdmissionCheckList, *kueuev1beta1.AdmissionCheckApplyConfiguration]( + "admissionchecks", + c.RESTClient(), + scheme.ParameterCodec, + "", + func() *v1beta1.AdmissionCheck { return &v1beta1.AdmissionCheck{} }, + func() *v1beta1.AdmissionCheckList { return &v1beta1.AdmissionCheckList{} }), } } - -// Get takes name of the admissionCheck, and returns the corresponding admissionCheck object, and an error if there is any. -func (c *admissionChecks) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.AdmissionCheck, err error) { - result = &v1beta1.AdmissionCheck{} - err = c.client.Get(). - Resource("admissionchecks"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of AdmissionChecks that match those selectors. -func (c *admissionChecks) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.AdmissionCheckList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1beta1.AdmissionCheckList{} - err = c.client.Get(). - Resource("admissionchecks"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested admissionChecks. -func (c *admissionChecks) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Resource("admissionchecks"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a admissionCheck and creates it. Returns the server's representation of the admissionCheck, and an error, if there is any. -func (c *admissionChecks) Create(ctx context.Context, admissionCheck *v1beta1.AdmissionCheck, opts v1.CreateOptions) (result *v1beta1.AdmissionCheck, err error) { - result = &v1beta1.AdmissionCheck{} - err = c.client.Post(). - Resource("admissionchecks"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(admissionCheck). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a admissionCheck and updates it. Returns the server's representation of the admissionCheck, and an error, if there is any. -func (c *admissionChecks) Update(ctx context.Context, admissionCheck *v1beta1.AdmissionCheck, opts v1.UpdateOptions) (result *v1beta1.AdmissionCheck, err error) { - result = &v1beta1.AdmissionCheck{} - err = c.client.Put(). - Resource("admissionchecks"). - Name(admissionCheck.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(admissionCheck). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *admissionChecks) UpdateStatus(ctx context.Context, admissionCheck *v1beta1.AdmissionCheck, opts v1.UpdateOptions) (result *v1beta1.AdmissionCheck, err error) { - result = &v1beta1.AdmissionCheck{} - err = c.client.Put(). - Resource("admissionchecks"). - Name(admissionCheck.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(admissionCheck). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the admissionCheck and deletes it. Returns an error if one occurs. -func (c *admissionChecks) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Resource("admissionchecks"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *admissionChecks) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Resource("admissionchecks"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched admissionCheck. -func (c *admissionChecks) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.AdmissionCheck, err error) { - result = &v1beta1.AdmissionCheck{} - err = c.client.Patch(pt). - Resource("admissionchecks"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} - -// Apply takes the given apply declarative configuration, applies it and returns the applied admissionCheck. -func (c *admissionChecks) Apply(ctx context.Context, admissionCheck *kueuev1beta1.AdmissionCheckApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.AdmissionCheck, err error) { - if admissionCheck == nil { - return nil, fmt.Errorf("admissionCheck provided to Apply must not be nil") - } - patchOpts := opts.ToPatchOptions() - data, err := json.Marshal(admissionCheck) - if err != nil { - return nil, err - } - name := admissionCheck.Name - if name == nil { - return nil, fmt.Errorf("admissionCheck.Name must be provided to Apply") - } - result = &v1beta1.AdmissionCheck{} - err = c.client.Patch(types.ApplyPatchType). - Resource("admissionchecks"). - Name(*name). - VersionedParams(&patchOpts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} - -// ApplyStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). -func (c *admissionChecks) ApplyStatus(ctx context.Context, admissionCheck *kueuev1beta1.AdmissionCheckApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.AdmissionCheck, err error) { - if admissionCheck == nil { - return nil, fmt.Errorf("admissionCheck provided to Apply must not be nil") - } - patchOpts := opts.ToPatchOptions() - data, err := json.Marshal(admissionCheck) - if err != nil { - return nil, err - } - - name := admissionCheck.Name - if name == nil { - return nil, fmt.Errorf("admissionCheck.Name must be provided to Apply") - } - - result = &v1beta1.AdmissionCheck{} - err = c.client.Patch(types.ApplyPatchType). - Resource("admissionchecks"). - Name(*name). - SubResource("status"). - VersionedParams(&patchOpts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/client-go/clientset/versioned/typed/kueue/v1beta1/clusterqueue.go b/client-go/clientset/versioned/typed/kueue/v1beta1/clusterqueue.go index 8cb404bbae..200c0f940e 100644 --- a/client-go/clientset/versioned/typed/kueue/v1beta1/clusterqueue.go +++ b/client-go/clientset/versioned/typed/kueue/v1beta1/clusterqueue.go @@ -19,14 +19,11 @@ package v1beta1 import ( "context" - json "encoding/json" - "fmt" - "time" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" kueuev1beta1 "sigs.k8s.io/kueue/client-go/applyconfiguration/kueue/v1beta1" scheme "sigs.k8s.io/kueue/client-go/clientset/versioned/scheme" @@ -42,6 +39,7 @@ type ClusterQueuesGetter interface { type ClusterQueueInterface interface { Create(ctx context.Context, clusterQueue *v1beta1.ClusterQueue, opts v1.CreateOptions) (*v1beta1.ClusterQueue, error) Update(ctx context.Context, clusterQueue *v1beta1.ClusterQueue, opts v1.UpdateOptions) (*v1beta1.ClusterQueue, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). UpdateStatus(ctx context.Context, clusterQueue *v1beta1.ClusterQueue, opts v1.UpdateOptions) (*v1beta1.ClusterQueue, error) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error @@ -50,193 +48,25 @@ type ClusterQueueInterface interface { Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.ClusterQueue, err error) Apply(ctx context.Context, clusterQueue *kueuev1beta1.ClusterQueueApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.ClusterQueue, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). ApplyStatus(ctx context.Context, clusterQueue *kueuev1beta1.ClusterQueueApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.ClusterQueue, err error) ClusterQueueExpansion } // clusterQueues implements ClusterQueueInterface type clusterQueues struct { - client rest.Interface + *gentype.ClientWithListAndApply[*v1beta1.ClusterQueue, *v1beta1.ClusterQueueList, *kueuev1beta1.ClusterQueueApplyConfiguration] } // newClusterQueues returns a ClusterQueues func newClusterQueues(c *KueueV1beta1Client) *clusterQueues { return &clusterQueues{ - client: c.RESTClient(), + gentype.NewClientWithListAndApply[*v1beta1.ClusterQueue, *v1beta1.ClusterQueueList, *kueuev1beta1.ClusterQueueApplyConfiguration]( + "clusterqueues", + c.RESTClient(), + scheme.ParameterCodec, + "", + func() *v1beta1.ClusterQueue { return &v1beta1.ClusterQueue{} }, + func() *v1beta1.ClusterQueueList { return &v1beta1.ClusterQueueList{} }), } } - -// Get takes name of the clusterQueue, and returns the corresponding clusterQueue object, and an error if there is any. -func (c *clusterQueues) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.ClusterQueue, err error) { - result = &v1beta1.ClusterQueue{} - err = c.client.Get(). - Resource("clusterqueues"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of ClusterQueues that match those selectors. -func (c *clusterQueues) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.ClusterQueueList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1beta1.ClusterQueueList{} - err = c.client.Get(). - Resource("clusterqueues"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested clusterQueues. -func (c *clusterQueues) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Resource("clusterqueues"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a clusterQueue and creates it. Returns the server's representation of the clusterQueue, and an error, if there is any. -func (c *clusterQueues) Create(ctx context.Context, clusterQueue *v1beta1.ClusterQueue, opts v1.CreateOptions) (result *v1beta1.ClusterQueue, err error) { - result = &v1beta1.ClusterQueue{} - err = c.client.Post(). - Resource("clusterqueues"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(clusterQueue). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a clusterQueue and updates it. Returns the server's representation of the clusterQueue, and an error, if there is any. -func (c *clusterQueues) Update(ctx context.Context, clusterQueue *v1beta1.ClusterQueue, opts v1.UpdateOptions) (result *v1beta1.ClusterQueue, err error) { - result = &v1beta1.ClusterQueue{} - err = c.client.Put(). - Resource("clusterqueues"). - Name(clusterQueue.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(clusterQueue). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *clusterQueues) UpdateStatus(ctx context.Context, clusterQueue *v1beta1.ClusterQueue, opts v1.UpdateOptions) (result *v1beta1.ClusterQueue, err error) { - result = &v1beta1.ClusterQueue{} - err = c.client.Put(). - Resource("clusterqueues"). - Name(clusterQueue.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(clusterQueue). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the clusterQueue and deletes it. Returns an error if one occurs. -func (c *clusterQueues) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Resource("clusterqueues"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *clusterQueues) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Resource("clusterqueues"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched clusterQueue. -func (c *clusterQueues) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.ClusterQueue, err error) { - result = &v1beta1.ClusterQueue{} - err = c.client.Patch(pt). - Resource("clusterqueues"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} - -// Apply takes the given apply declarative configuration, applies it and returns the applied clusterQueue. -func (c *clusterQueues) Apply(ctx context.Context, clusterQueue *kueuev1beta1.ClusterQueueApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.ClusterQueue, err error) { - if clusterQueue == nil { - return nil, fmt.Errorf("clusterQueue provided to Apply must not be nil") - } - patchOpts := opts.ToPatchOptions() - data, err := json.Marshal(clusterQueue) - if err != nil { - return nil, err - } - name := clusterQueue.Name - if name == nil { - return nil, fmt.Errorf("clusterQueue.Name must be provided to Apply") - } - result = &v1beta1.ClusterQueue{} - err = c.client.Patch(types.ApplyPatchType). - Resource("clusterqueues"). - Name(*name). - VersionedParams(&patchOpts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} - -// ApplyStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). -func (c *clusterQueues) ApplyStatus(ctx context.Context, clusterQueue *kueuev1beta1.ClusterQueueApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.ClusterQueue, err error) { - if clusterQueue == nil { - return nil, fmt.Errorf("clusterQueue provided to Apply must not be nil") - } - patchOpts := opts.ToPatchOptions() - data, err := json.Marshal(clusterQueue) - if err != nil { - return nil, err - } - - name := clusterQueue.Name - if name == nil { - return nil, fmt.Errorf("clusterQueue.Name must be provided to Apply") - } - - result = &v1beta1.ClusterQueue{} - err = c.client.Patch(types.ApplyPatchType). - Resource("clusterqueues"). - Name(*name). - SubResource("status"). - VersionedParams(&patchOpts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_admissioncheck.go b/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_admissioncheck.go index a31dfa301e..aeea11a5d1 100644 --- a/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_admissioncheck.go +++ b/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_admissioncheck.go @@ -42,20 +42,22 @@ var admissionchecksKind = v1beta1.SchemeGroupVersion.WithKind("AdmissionCheck") // Get takes name of the admissionCheck, and returns the corresponding admissionCheck object, and an error if there is any. func (c *FakeAdmissionChecks) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.AdmissionCheck, err error) { + emptyResult := &v1beta1.AdmissionCheck{} obj, err := c.Fake. - Invokes(testing.NewRootGetAction(admissionchecksResource, name), &v1beta1.AdmissionCheck{}) + Invokes(testing.NewRootGetActionWithOptions(admissionchecksResource, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.AdmissionCheck), err } // List takes label and field selectors, and returns the list of AdmissionChecks that match those selectors. func (c *FakeAdmissionChecks) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.AdmissionCheckList, err error) { + emptyResult := &v1beta1.AdmissionCheckList{} obj, err := c.Fake. - Invokes(testing.NewRootListAction(admissionchecksResource, admissionchecksKind, opts), &v1beta1.AdmissionCheckList{}) + Invokes(testing.NewRootListActionWithOptions(admissionchecksResource, admissionchecksKind, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -74,36 +76,39 @@ func (c *FakeAdmissionChecks) List(ctx context.Context, opts v1.ListOptions) (re // Watch returns a watch.Interface that watches the requested admissionChecks. func (c *FakeAdmissionChecks) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewRootWatchAction(admissionchecksResource, opts)) + InvokesWatch(testing.NewRootWatchActionWithOptions(admissionchecksResource, opts)) } // Create takes the representation of a admissionCheck and creates it. Returns the server's representation of the admissionCheck, and an error, if there is any. func (c *FakeAdmissionChecks) Create(ctx context.Context, admissionCheck *v1beta1.AdmissionCheck, opts v1.CreateOptions) (result *v1beta1.AdmissionCheck, err error) { + emptyResult := &v1beta1.AdmissionCheck{} obj, err := c.Fake. - Invokes(testing.NewRootCreateAction(admissionchecksResource, admissionCheck), &v1beta1.AdmissionCheck{}) + Invokes(testing.NewRootCreateActionWithOptions(admissionchecksResource, admissionCheck, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.AdmissionCheck), err } // Update takes the representation of a admissionCheck and updates it. Returns the server's representation of the admissionCheck, and an error, if there is any. func (c *FakeAdmissionChecks) Update(ctx context.Context, admissionCheck *v1beta1.AdmissionCheck, opts v1.UpdateOptions) (result *v1beta1.AdmissionCheck, err error) { + emptyResult := &v1beta1.AdmissionCheck{} obj, err := c.Fake. - Invokes(testing.NewRootUpdateAction(admissionchecksResource, admissionCheck), &v1beta1.AdmissionCheck{}) + Invokes(testing.NewRootUpdateActionWithOptions(admissionchecksResource, admissionCheck, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.AdmissionCheck), err } // UpdateStatus was generated because the type contains a Status member. // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeAdmissionChecks) UpdateStatus(ctx context.Context, admissionCheck *v1beta1.AdmissionCheck, opts v1.UpdateOptions) (*v1beta1.AdmissionCheck, error) { +func (c *FakeAdmissionChecks) UpdateStatus(ctx context.Context, admissionCheck *v1beta1.AdmissionCheck, opts v1.UpdateOptions) (result *v1beta1.AdmissionCheck, err error) { + emptyResult := &v1beta1.AdmissionCheck{} obj, err := c.Fake. - Invokes(testing.NewRootUpdateSubresourceAction(admissionchecksResource, "status", admissionCheck), &v1beta1.AdmissionCheck{}) + Invokes(testing.NewRootUpdateSubresourceActionWithOptions(admissionchecksResource, "status", admissionCheck, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.AdmissionCheck), err } @@ -117,7 +122,7 @@ func (c *FakeAdmissionChecks) Delete(ctx context.Context, name string, opts v1.D // DeleteCollection deletes a collection of objects. func (c *FakeAdmissionChecks) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewRootDeleteCollectionAction(admissionchecksResource, listOpts) + action := testing.NewRootDeleteCollectionActionWithOptions(admissionchecksResource, opts, listOpts) _, err := c.Fake.Invokes(action, &v1beta1.AdmissionCheckList{}) return err @@ -125,10 +130,11 @@ func (c *FakeAdmissionChecks) DeleteCollection(ctx context.Context, opts v1.Dele // Patch applies the patch and returns the patched admissionCheck. func (c *FakeAdmissionChecks) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.AdmissionCheck, err error) { + emptyResult := &v1beta1.AdmissionCheck{} obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(admissionchecksResource, name, pt, data, subresources...), &v1beta1.AdmissionCheck{}) + Invokes(testing.NewRootPatchSubresourceActionWithOptions(admissionchecksResource, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.AdmissionCheck), err } @@ -146,10 +152,11 @@ func (c *FakeAdmissionChecks) Apply(ctx context.Context, admissionCheck *kueuev1 if name == nil { return nil, fmt.Errorf("admissionCheck.Name must be provided to Apply") } + emptyResult := &v1beta1.AdmissionCheck{} obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(admissionchecksResource, *name, types.ApplyPatchType, data), &v1beta1.AdmissionCheck{}) + Invokes(testing.NewRootPatchSubresourceActionWithOptions(admissionchecksResource, *name, types.ApplyPatchType, data, opts.ToPatchOptions()), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.AdmissionCheck), err } @@ -168,10 +175,11 @@ func (c *FakeAdmissionChecks) ApplyStatus(ctx context.Context, admissionCheck *k if name == nil { return nil, fmt.Errorf("admissionCheck.Name must be provided to Apply") } + emptyResult := &v1beta1.AdmissionCheck{} obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(admissionchecksResource, *name, types.ApplyPatchType, data, "status"), &v1beta1.AdmissionCheck{}) + Invokes(testing.NewRootPatchSubresourceActionWithOptions(admissionchecksResource, *name, types.ApplyPatchType, data, opts.ToPatchOptions(), "status"), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.AdmissionCheck), err } diff --git a/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_clusterqueue.go b/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_clusterqueue.go index 8205ce4036..3492096ba4 100644 --- a/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_clusterqueue.go +++ b/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_clusterqueue.go @@ -42,20 +42,22 @@ var clusterqueuesKind = v1beta1.SchemeGroupVersion.WithKind("ClusterQueue") // Get takes name of the clusterQueue, and returns the corresponding clusterQueue object, and an error if there is any. func (c *FakeClusterQueues) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.ClusterQueue, err error) { + emptyResult := &v1beta1.ClusterQueue{} obj, err := c.Fake. - Invokes(testing.NewRootGetAction(clusterqueuesResource, name), &v1beta1.ClusterQueue{}) + Invokes(testing.NewRootGetActionWithOptions(clusterqueuesResource, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.ClusterQueue), err } // List takes label and field selectors, and returns the list of ClusterQueues that match those selectors. func (c *FakeClusterQueues) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.ClusterQueueList, err error) { + emptyResult := &v1beta1.ClusterQueueList{} obj, err := c.Fake. - Invokes(testing.NewRootListAction(clusterqueuesResource, clusterqueuesKind, opts), &v1beta1.ClusterQueueList{}) + Invokes(testing.NewRootListActionWithOptions(clusterqueuesResource, clusterqueuesKind, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -74,36 +76,39 @@ func (c *FakeClusterQueues) List(ctx context.Context, opts v1.ListOptions) (resu // Watch returns a watch.Interface that watches the requested clusterQueues. func (c *FakeClusterQueues) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewRootWatchAction(clusterqueuesResource, opts)) + InvokesWatch(testing.NewRootWatchActionWithOptions(clusterqueuesResource, opts)) } // Create takes the representation of a clusterQueue and creates it. Returns the server's representation of the clusterQueue, and an error, if there is any. func (c *FakeClusterQueues) Create(ctx context.Context, clusterQueue *v1beta1.ClusterQueue, opts v1.CreateOptions) (result *v1beta1.ClusterQueue, err error) { + emptyResult := &v1beta1.ClusterQueue{} obj, err := c.Fake. - Invokes(testing.NewRootCreateAction(clusterqueuesResource, clusterQueue), &v1beta1.ClusterQueue{}) + Invokes(testing.NewRootCreateActionWithOptions(clusterqueuesResource, clusterQueue, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.ClusterQueue), err } // Update takes the representation of a clusterQueue and updates it. Returns the server's representation of the clusterQueue, and an error, if there is any. func (c *FakeClusterQueues) Update(ctx context.Context, clusterQueue *v1beta1.ClusterQueue, opts v1.UpdateOptions) (result *v1beta1.ClusterQueue, err error) { + emptyResult := &v1beta1.ClusterQueue{} obj, err := c.Fake. - Invokes(testing.NewRootUpdateAction(clusterqueuesResource, clusterQueue), &v1beta1.ClusterQueue{}) + Invokes(testing.NewRootUpdateActionWithOptions(clusterqueuesResource, clusterQueue, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.ClusterQueue), err } // UpdateStatus was generated because the type contains a Status member. // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeClusterQueues) UpdateStatus(ctx context.Context, clusterQueue *v1beta1.ClusterQueue, opts v1.UpdateOptions) (*v1beta1.ClusterQueue, error) { +func (c *FakeClusterQueues) UpdateStatus(ctx context.Context, clusterQueue *v1beta1.ClusterQueue, opts v1.UpdateOptions) (result *v1beta1.ClusterQueue, err error) { + emptyResult := &v1beta1.ClusterQueue{} obj, err := c.Fake. - Invokes(testing.NewRootUpdateSubresourceAction(clusterqueuesResource, "status", clusterQueue), &v1beta1.ClusterQueue{}) + Invokes(testing.NewRootUpdateSubresourceActionWithOptions(clusterqueuesResource, "status", clusterQueue, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.ClusterQueue), err } @@ -117,7 +122,7 @@ func (c *FakeClusterQueues) Delete(ctx context.Context, name string, opts v1.Del // DeleteCollection deletes a collection of objects. func (c *FakeClusterQueues) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewRootDeleteCollectionAction(clusterqueuesResource, listOpts) + action := testing.NewRootDeleteCollectionActionWithOptions(clusterqueuesResource, opts, listOpts) _, err := c.Fake.Invokes(action, &v1beta1.ClusterQueueList{}) return err @@ -125,10 +130,11 @@ func (c *FakeClusterQueues) DeleteCollection(ctx context.Context, opts v1.Delete // Patch applies the patch and returns the patched clusterQueue. func (c *FakeClusterQueues) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.ClusterQueue, err error) { + emptyResult := &v1beta1.ClusterQueue{} obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(clusterqueuesResource, name, pt, data, subresources...), &v1beta1.ClusterQueue{}) + Invokes(testing.NewRootPatchSubresourceActionWithOptions(clusterqueuesResource, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.ClusterQueue), err } @@ -146,10 +152,11 @@ func (c *FakeClusterQueues) Apply(ctx context.Context, clusterQueue *kueuev1beta if name == nil { return nil, fmt.Errorf("clusterQueue.Name must be provided to Apply") } + emptyResult := &v1beta1.ClusterQueue{} obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(clusterqueuesResource, *name, types.ApplyPatchType, data), &v1beta1.ClusterQueue{}) + Invokes(testing.NewRootPatchSubresourceActionWithOptions(clusterqueuesResource, *name, types.ApplyPatchType, data, opts.ToPatchOptions()), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.ClusterQueue), err } @@ -168,10 +175,11 @@ func (c *FakeClusterQueues) ApplyStatus(ctx context.Context, clusterQueue *kueue if name == nil { return nil, fmt.Errorf("clusterQueue.Name must be provided to Apply") } + emptyResult := &v1beta1.ClusterQueue{} obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(clusterqueuesResource, *name, types.ApplyPatchType, data, "status"), &v1beta1.ClusterQueue{}) + Invokes(testing.NewRootPatchSubresourceActionWithOptions(clusterqueuesResource, *name, types.ApplyPatchType, data, opts.ToPatchOptions(), "status"), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.ClusterQueue), err } diff --git a/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_localqueue.go b/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_localqueue.go index 65db9ec7a4..dea18a40bf 100644 --- a/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_localqueue.go +++ b/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_localqueue.go @@ -43,22 +43,24 @@ var localqueuesKind = v1beta1.SchemeGroupVersion.WithKind("LocalQueue") // Get takes name of the localQueue, and returns the corresponding localQueue object, and an error if there is any. func (c *FakeLocalQueues) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.LocalQueue, err error) { + emptyResult := &v1beta1.LocalQueue{} obj, err := c.Fake. - Invokes(testing.NewGetAction(localqueuesResource, c.ns, name), &v1beta1.LocalQueue{}) + Invokes(testing.NewGetActionWithOptions(localqueuesResource, c.ns, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.LocalQueue), err } // List takes label and field selectors, and returns the list of LocalQueues that match those selectors. func (c *FakeLocalQueues) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.LocalQueueList, err error) { + emptyResult := &v1beta1.LocalQueueList{} obj, err := c.Fake. - Invokes(testing.NewListAction(localqueuesResource, localqueuesKind, c.ns, opts), &v1beta1.LocalQueueList{}) + Invokes(testing.NewListActionWithOptions(localqueuesResource, localqueuesKind, c.ns, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -77,40 +79,43 @@ func (c *FakeLocalQueues) List(ctx context.Context, opts v1.ListOptions) (result // Watch returns a watch.Interface that watches the requested localQueues. func (c *FakeLocalQueues) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewWatchAction(localqueuesResource, c.ns, opts)) + InvokesWatch(testing.NewWatchActionWithOptions(localqueuesResource, c.ns, opts)) } // Create takes the representation of a localQueue and creates it. Returns the server's representation of the localQueue, and an error, if there is any. func (c *FakeLocalQueues) Create(ctx context.Context, localQueue *v1beta1.LocalQueue, opts v1.CreateOptions) (result *v1beta1.LocalQueue, err error) { + emptyResult := &v1beta1.LocalQueue{} obj, err := c.Fake. - Invokes(testing.NewCreateAction(localqueuesResource, c.ns, localQueue), &v1beta1.LocalQueue{}) + Invokes(testing.NewCreateActionWithOptions(localqueuesResource, c.ns, localQueue, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.LocalQueue), err } // Update takes the representation of a localQueue and updates it. Returns the server's representation of the localQueue, and an error, if there is any. func (c *FakeLocalQueues) Update(ctx context.Context, localQueue *v1beta1.LocalQueue, opts v1.UpdateOptions) (result *v1beta1.LocalQueue, err error) { + emptyResult := &v1beta1.LocalQueue{} obj, err := c.Fake. - Invokes(testing.NewUpdateAction(localqueuesResource, c.ns, localQueue), &v1beta1.LocalQueue{}) + Invokes(testing.NewUpdateActionWithOptions(localqueuesResource, c.ns, localQueue, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.LocalQueue), err } // UpdateStatus was generated because the type contains a Status member. // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeLocalQueues) UpdateStatus(ctx context.Context, localQueue *v1beta1.LocalQueue, opts v1.UpdateOptions) (*v1beta1.LocalQueue, error) { +func (c *FakeLocalQueues) UpdateStatus(ctx context.Context, localQueue *v1beta1.LocalQueue, opts v1.UpdateOptions) (result *v1beta1.LocalQueue, err error) { + emptyResult := &v1beta1.LocalQueue{} obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(localqueuesResource, "status", c.ns, localQueue), &v1beta1.LocalQueue{}) + Invokes(testing.NewUpdateSubresourceActionWithOptions(localqueuesResource, "status", c.ns, localQueue, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.LocalQueue), err } @@ -125,7 +130,7 @@ func (c *FakeLocalQueues) Delete(ctx context.Context, name string, opts v1.Delet // DeleteCollection deletes a collection of objects. func (c *FakeLocalQueues) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(localqueuesResource, c.ns, listOpts) + action := testing.NewDeleteCollectionActionWithOptions(localqueuesResource, c.ns, opts, listOpts) _, err := c.Fake.Invokes(action, &v1beta1.LocalQueueList{}) return err @@ -133,11 +138,12 @@ func (c *FakeLocalQueues) DeleteCollection(ctx context.Context, opts v1.DeleteOp // Patch applies the patch and returns the patched localQueue. func (c *FakeLocalQueues) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.LocalQueue, err error) { + emptyResult := &v1beta1.LocalQueue{} obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(localqueuesResource, c.ns, name, pt, data, subresources...), &v1beta1.LocalQueue{}) + Invokes(testing.NewPatchSubresourceActionWithOptions(localqueuesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.LocalQueue), err } @@ -155,11 +161,12 @@ func (c *FakeLocalQueues) Apply(ctx context.Context, localQueue *kueuev1beta1.Lo if name == nil { return nil, fmt.Errorf("localQueue.Name must be provided to Apply") } + emptyResult := &v1beta1.LocalQueue{} obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(localqueuesResource, c.ns, *name, types.ApplyPatchType, data), &v1beta1.LocalQueue{}) + Invokes(testing.NewPatchSubresourceActionWithOptions(localqueuesResource, c.ns, *name, types.ApplyPatchType, data, opts.ToPatchOptions()), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.LocalQueue), err } @@ -178,11 +185,12 @@ func (c *FakeLocalQueues) ApplyStatus(ctx context.Context, localQueue *kueuev1be if name == nil { return nil, fmt.Errorf("localQueue.Name must be provided to Apply") } + emptyResult := &v1beta1.LocalQueue{} obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(localqueuesResource, c.ns, *name, types.ApplyPatchType, data, "status"), &v1beta1.LocalQueue{}) + Invokes(testing.NewPatchSubresourceActionWithOptions(localqueuesResource, c.ns, *name, types.ApplyPatchType, data, opts.ToPatchOptions(), "status"), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.LocalQueue), err } diff --git a/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_provisioningrequestconfig.go b/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_provisioningrequestconfig.go index 0947cd1081..ab3507d645 100644 --- a/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_provisioningrequestconfig.go +++ b/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_provisioningrequestconfig.go @@ -42,20 +42,22 @@ var provisioningrequestconfigsKind = v1beta1.SchemeGroupVersion.WithKind("Provis // Get takes name of the provisioningRequestConfig, and returns the corresponding provisioningRequestConfig object, and an error if there is any. func (c *FakeProvisioningRequestConfigs) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.ProvisioningRequestConfig, err error) { + emptyResult := &v1beta1.ProvisioningRequestConfig{} obj, err := c.Fake. - Invokes(testing.NewRootGetAction(provisioningrequestconfigsResource, name), &v1beta1.ProvisioningRequestConfig{}) + Invokes(testing.NewRootGetActionWithOptions(provisioningrequestconfigsResource, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.ProvisioningRequestConfig), err } // List takes label and field selectors, and returns the list of ProvisioningRequestConfigs that match those selectors. func (c *FakeProvisioningRequestConfigs) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.ProvisioningRequestConfigList, err error) { + emptyResult := &v1beta1.ProvisioningRequestConfigList{} obj, err := c.Fake. - Invokes(testing.NewRootListAction(provisioningrequestconfigsResource, provisioningrequestconfigsKind, opts), &v1beta1.ProvisioningRequestConfigList{}) + Invokes(testing.NewRootListActionWithOptions(provisioningrequestconfigsResource, provisioningrequestconfigsKind, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -74,25 +76,27 @@ func (c *FakeProvisioningRequestConfigs) List(ctx context.Context, opts v1.ListO // Watch returns a watch.Interface that watches the requested provisioningRequestConfigs. func (c *FakeProvisioningRequestConfigs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewRootWatchAction(provisioningrequestconfigsResource, opts)) + InvokesWatch(testing.NewRootWatchActionWithOptions(provisioningrequestconfigsResource, opts)) } // Create takes the representation of a provisioningRequestConfig and creates it. Returns the server's representation of the provisioningRequestConfig, and an error, if there is any. func (c *FakeProvisioningRequestConfigs) Create(ctx context.Context, provisioningRequestConfig *v1beta1.ProvisioningRequestConfig, opts v1.CreateOptions) (result *v1beta1.ProvisioningRequestConfig, err error) { + emptyResult := &v1beta1.ProvisioningRequestConfig{} obj, err := c.Fake. - Invokes(testing.NewRootCreateAction(provisioningrequestconfigsResource, provisioningRequestConfig), &v1beta1.ProvisioningRequestConfig{}) + Invokes(testing.NewRootCreateActionWithOptions(provisioningrequestconfigsResource, provisioningRequestConfig, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.ProvisioningRequestConfig), err } // Update takes the representation of a provisioningRequestConfig and updates it. Returns the server's representation of the provisioningRequestConfig, and an error, if there is any. func (c *FakeProvisioningRequestConfigs) Update(ctx context.Context, provisioningRequestConfig *v1beta1.ProvisioningRequestConfig, opts v1.UpdateOptions) (result *v1beta1.ProvisioningRequestConfig, err error) { + emptyResult := &v1beta1.ProvisioningRequestConfig{} obj, err := c.Fake. - Invokes(testing.NewRootUpdateAction(provisioningrequestconfigsResource, provisioningRequestConfig), &v1beta1.ProvisioningRequestConfig{}) + Invokes(testing.NewRootUpdateActionWithOptions(provisioningrequestconfigsResource, provisioningRequestConfig, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.ProvisioningRequestConfig), err } @@ -106,7 +110,7 @@ func (c *FakeProvisioningRequestConfigs) Delete(ctx context.Context, name string // DeleteCollection deletes a collection of objects. func (c *FakeProvisioningRequestConfigs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewRootDeleteCollectionAction(provisioningrequestconfigsResource, listOpts) + action := testing.NewRootDeleteCollectionActionWithOptions(provisioningrequestconfigsResource, opts, listOpts) _, err := c.Fake.Invokes(action, &v1beta1.ProvisioningRequestConfigList{}) return err @@ -114,10 +118,11 @@ func (c *FakeProvisioningRequestConfigs) DeleteCollection(ctx context.Context, o // Patch applies the patch and returns the patched provisioningRequestConfig. func (c *FakeProvisioningRequestConfigs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.ProvisioningRequestConfig, err error) { + emptyResult := &v1beta1.ProvisioningRequestConfig{} obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(provisioningrequestconfigsResource, name, pt, data, subresources...), &v1beta1.ProvisioningRequestConfig{}) + Invokes(testing.NewRootPatchSubresourceActionWithOptions(provisioningrequestconfigsResource, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.ProvisioningRequestConfig), err } @@ -135,10 +140,11 @@ func (c *FakeProvisioningRequestConfigs) Apply(ctx context.Context, provisioning if name == nil { return nil, fmt.Errorf("provisioningRequestConfig.Name must be provided to Apply") } + emptyResult := &v1beta1.ProvisioningRequestConfig{} obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(provisioningrequestconfigsResource, *name, types.ApplyPatchType, data), &v1beta1.ProvisioningRequestConfig{}) + Invokes(testing.NewRootPatchSubresourceActionWithOptions(provisioningrequestconfigsResource, *name, types.ApplyPatchType, data, opts.ToPatchOptions()), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.ProvisioningRequestConfig), err } diff --git a/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_resourceflavor.go b/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_resourceflavor.go index 1803c75a28..55acf482dd 100644 --- a/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_resourceflavor.go +++ b/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_resourceflavor.go @@ -42,20 +42,22 @@ var resourceflavorsKind = v1beta1.SchemeGroupVersion.WithKind("ResourceFlavor") // Get takes name of the resourceFlavor, and returns the corresponding resourceFlavor object, and an error if there is any. func (c *FakeResourceFlavors) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.ResourceFlavor, err error) { + emptyResult := &v1beta1.ResourceFlavor{} obj, err := c.Fake. - Invokes(testing.NewRootGetAction(resourceflavorsResource, name), &v1beta1.ResourceFlavor{}) + Invokes(testing.NewRootGetActionWithOptions(resourceflavorsResource, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.ResourceFlavor), err } // List takes label and field selectors, and returns the list of ResourceFlavors that match those selectors. func (c *FakeResourceFlavors) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.ResourceFlavorList, err error) { + emptyResult := &v1beta1.ResourceFlavorList{} obj, err := c.Fake. - Invokes(testing.NewRootListAction(resourceflavorsResource, resourceflavorsKind, opts), &v1beta1.ResourceFlavorList{}) + Invokes(testing.NewRootListActionWithOptions(resourceflavorsResource, resourceflavorsKind, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -74,25 +76,27 @@ func (c *FakeResourceFlavors) List(ctx context.Context, opts v1.ListOptions) (re // Watch returns a watch.Interface that watches the requested resourceFlavors. func (c *FakeResourceFlavors) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewRootWatchAction(resourceflavorsResource, opts)) + InvokesWatch(testing.NewRootWatchActionWithOptions(resourceflavorsResource, opts)) } // Create takes the representation of a resourceFlavor and creates it. Returns the server's representation of the resourceFlavor, and an error, if there is any. func (c *FakeResourceFlavors) Create(ctx context.Context, resourceFlavor *v1beta1.ResourceFlavor, opts v1.CreateOptions) (result *v1beta1.ResourceFlavor, err error) { + emptyResult := &v1beta1.ResourceFlavor{} obj, err := c.Fake. - Invokes(testing.NewRootCreateAction(resourceflavorsResource, resourceFlavor), &v1beta1.ResourceFlavor{}) + Invokes(testing.NewRootCreateActionWithOptions(resourceflavorsResource, resourceFlavor, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.ResourceFlavor), err } // Update takes the representation of a resourceFlavor and updates it. Returns the server's representation of the resourceFlavor, and an error, if there is any. func (c *FakeResourceFlavors) Update(ctx context.Context, resourceFlavor *v1beta1.ResourceFlavor, opts v1.UpdateOptions) (result *v1beta1.ResourceFlavor, err error) { + emptyResult := &v1beta1.ResourceFlavor{} obj, err := c.Fake. - Invokes(testing.NewRootUpdateAction(resourceflavorsResource, resourceFlavor), &v1beta1.ResourceFlavor{}) + Invokes(testing.NewRootUpdateActionWithOptions(resourceflavorsResource, resourceFlavor, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.ResourceFlavor), err } @@ -106,7 +110,7 @@ func (c *FakeResourceFlavors) Delete(ctx context.Context, name string, opts v1.D // DeleteCollection deletes a collection of objects. func (c *FakeResourceFlavors) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewRootDeleteCollectionAction(resourceflavorsResource, listOpts) + action := testing.NewRootDeleteCollectionActionWithOptions(resourceflavorsResource, opts, listOpts) _, err := c.Fake.Invokes(action, &v1beta1.ResourceFlavorList{}) return err @@ -114,10 +118,11 @@ func (c *FakeResourceFlavors) DeleteCollection(ctx context.Context, opts v1.Dele // Patch applies the patch and returns the patched resourceFlavor. func (c *FakeResourceFlavors) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.ResourceFlavor, err error) { + emptyResult := &v1beta1.ResourceFlavor{} obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(resourceflavorsResource, name, pt, data, subresources...), &v1beta1.ResourceFlavor{}) + Invokes(testing.NewRootPatchSubresourceActionWithOptions(resourceflavorsResource, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.ResourceFlavor), err } @@ -135,10 +140,11 @@ func (c *FakeResourceFlavors) Apply(ctx context.Context, resourceFlavor *kueuev1 if name == nil { return nil, fmt.Errorf("resourceFlavor.Name must be provided to Apply") } + emptyResult := &v1beta1.ResourceFlavor{} obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(resourceflavorsResource, *name, types.ApplyPatchType, data), &v1beta1.ResourceFlavor{}) + Invokes(testing.NewRootPatchSubresourceActionWithOptions(resourceflavorsResource, *name, types.ApplyPatchType, data, opts.ToPatchOptions()), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.ResourceFlavor), err } diff --git a/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_workload.go b/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_workload.go index 7e797ae411..c2fdbd764f 100644 --- a/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_workload.go +++ b/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_workload.go @@ -43,22 +43,24 @@ var workloadsKind = v1beta1.SchemeGroupVersion.WithKind("Workload") // Get takes name of the workload, and returns the corresponding workload object, and an error if there is any. func (c *FakeWorkloads) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.Workload, err error) { + emptyResult := &v1beta1.Workload{} obj, err := c.Fake. - Invokes(testing.NewGetAction(workloadsResource, c.ns, name), &v1beta1.Workload{}) + Invokes(testing.NewGetActionWithOptions(workloadsResource, c.ns, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.Workload), err } // List takes label and field selectors, and returns the list of Workloads that match those selectors. func (c *FakeWorkloads) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.WorkloadList, err error) { + emptyResult := &v1beta1.WorkloadList{} obj, err := c.Fake. - Invokes(testing.NewListAction(workloadsResource, workloadsKind, c.ns, opts), &v1beta1.WorkloadList{}) + Invokes(testing.NewListActionWithOptions(workloadsResource, workloadsKind, c.ns, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -77,40 +79,43 @@ func (c *FakeWorkloads) List(ctx context.Context, opts v1.ListOptions) (result * // Watch returns a watch.Interface that watches the requested workloads. func (c *FakeWorkloads) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewWatchAction(workloadsResource, c.ns, opts)) + InvokesWatch(testing.NewWatchActionWithOptions(workloadsResource, c.ns, opts)) } // Create takes the representation of a workload and creates it. Returns the server's representation of the workload, and an error, if there is any. func (c *FakeWorkloads) Create(ctx context.Context, workload *v1beta1.Workload, opts v1.CreateOptions) (result *v1beta1.Workload, err error) { + emptyResult := &v1beta1.Workload{} obj, err := c.Fake. - Invokes(testing.NewCreateAction(workloadsResource, c.ns, workload), &v1beta1.Workload{}) + Invokes(testing.NewCreateActionWithOptions(workloadsResource, c.ns, workload, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.Workload), err } // Update takes the representation of a workload and updates it. Returns the server's representation of the workload, and an error, if there is any. func (c *FakeWorkloads) Update(ctx context.Context, workload *v1beta1.Workload, opts v1.UpdateOptions) (result *v1beta1.Workload, err error) { + emptyResult := &v1beta1.Workload{} obj, err := c.Fake. - Invokes(testing.NewUpdateAction(workloadsResource, c.ns, workload), &v1beta1.Workload{}) + Invokes(testing.NewUpdateActionWithOptions(workloadsResource, c.ns, workload, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.Workload), err } // UpdateStatus was generated because the type contains a Status member. // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeWorkloads) UpdateStatus(ctx context.Context, workload *v1beta1.Workload, opts v1.UpdateOptions) (*v1beta1.Workload, error) { +func (c *FakeWorkloads) UpdateStatus(ctx context.Context, workload *v1beta1.Workload, opts v1.UpdateOptions) (result *v1beta1.Workload, err error) { + emptyResult := &v1beta1.Workload{} obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(workloadsResource, "status", c.ns, workload), &v1beta1.Workload{}) + Invokes(testing.NewUpdateSubresourceActionWithOptions(workloadsResource, "status", c.ns, workload, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.Workload), err } @@ -125,7 +130,7 @@ func (c *FakeWorkloads) Delete(ctx context.Context, name string, opts v1.DeleteO // DeleteCollection deletes a collection of objects. func (c *FakeWorkloads) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(workloadsResource, c.ns, listOpts) + action := testing.NewDeleteCollectionActionWithOptions(workloadsResource, c.ns, opts, listOpts) _, err := c.Fake.Invokes(action, &v1beta1.WorkloadList{}) return err @@ -133,11 +138,12 @@ func (c *FakeWorkloads) DeleteCollection(ctx context.Context, opts v1.DeleteOpti // Patch applies the patch and returns the patched workload. func (c *FakeWorkloads) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Workload, err error) { + emptyResult := &v1beta1.Workload{} obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(workloadsResource, c.ns, name, pt, data, subresources...), &v1beta1.Workload{}) + Invokes(testing.NewPatchSubresourceActionWithOptions(workloadsResource, c.ns, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.Workload), err } @@ -155,11 +161,12 @@ func (c *FakeWorkloads) Apply(ctx context.Context, workload *kueuev1beta1.Worklo if name == nil { return nil, fmt.Errorf("workload.Name must be provided to Apply") } + emptyResult := &v1beta1.Workload{} obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(workloadsResource, c.ns, *name, types.ApplyPatchType, data), &v1beta1.Workload{}) + Invokes(testing.NewPatchSubresourceActionWithOptions(workloadsResource, c.ns, *name, types.ApplyPatchType, data, opts.ToPatchOptions()), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.Workload), err } @@ -178,11 +185,12 @@ func (c *FakeWorkloads) ApplyStatus(ctx context.Context, workload *kueuev1beta1. if name == nil { return nil, fmt.Errorf("workload.Name must be provided to Apply") } + emptyResult := &v1beta1.Workload{} obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(workloadsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &v1beta1.Workload{}) + Invokes(testing.NewPatchSubresourceActionWithOptions(workloadsResource, c.ns, *name, types.ApplyPatchType, data, opts.ToPatchOptions(), "status"), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.Workload), err } diff --git a/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_workloadpriorityclass.go b/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_workloadpriorityclass.go index 5f954a9235..fa76fd4ce2 100644 --- a/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_workloadpriorityclass.go +++ b/client-go/clientset/versioned/typed/kueue/v1beta1/fake/fake_workloadpriorityclass.go @@ -42,20 +42,22 @@ var workloadpriorityclassesKind = v1beta1.SchemeGroupVersion.WithKind("WorkloadP // Get takes name of the workloadPriorityClass, and returns the corresponding workloadPriorityClass object, and an error if there is any. func (c *FakeWorkloadPriorityClasses) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.WorkloadPriorityClass, err error) { + emptyResult := &v1beta1.WorkloadPriorityClass{} obj, err := c.Fake. - Invokes(testing.NewRootGetAction(workloadpriorityclassesResource, name), &v1beta1.WorkloadPriorityClass{}) + Invokes(testing.NewRootGetActionWithOptions(workloadpriorityclassesResource, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.WorkloadPriorityClass), err } // List takes label and field selectors, and returns the list of WorkloadPriorityClasses that match those selectors. func (c *FakeWorkloadPriorityClasses) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.WorkloadPriorityClassList, err error) { + emptyResult := &v1beta1.WorkloadPriorityClassList{} obj, err := c.Fake. - Invokes(testing.NewRootListAction(workloadpriorityclassesResource, workloadpriorityclassesKind, opts), &v1beta1.WorkloadPriorityClassList{}) + Invokes(testing.NewRootListActionWithOptions(workloadpriorityclassesResource, workloadpriorityclassesKind, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -74,25 +76,27 @@ func (c *FakeWorkloadPriorityClasses) List(ctx context.Context, opts v1.ListOpti // Watch returns a watch.Interface that watches the requested workloadPriorityClasses. func (c *FakeWorkloadPriorityClasses) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewRootWatchAction(workloadpriorityclassesResource, opts)) + InvokesWatch(testing.NewRootWatchActionWithOptions(workloadpriorityclassesResource, opts)) } // Create takes the representation of a workloadPriorityClass and creates it. Returns the server's representation of the workloadPriorityClass, and an error, if there is any. func (c *FakeWorkloadPriorityClasses) Create(ctx context.Context, workloadPriorityClass *v1beta1.WorkloadPriorityClass, opts v1.CreateOptions) (result *v1beta1.WorkloadPriorityClass, err error) { + emptyResult := &v1beta1.WorkloadPriorityClass{} obj, err := c.Fake. - Invokes(testing.NewRootCreateAction(workloadpriorityclassesResource, workloadPriorityClass), &v1beta1.WorkloadPriorityClass{}) + Invokes(testing.NewRootCreateActionWithOptions(workloadpriorityclassesResource, workloadPriorityClass, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.WorkloadPriorityClass), err } // Update takes the representation of a workloadPriorityClass and updates it. Returns the server's representation of the workloadPriorityClass, and an error, if there is any. func (c *FakeWorkloadPriorityClasses) Update(ctx context.Context, workloadPriorityClass *v1beta1.WorkloadPriorityClass, opts v1.UpdateOptions) (result *v1beta1.WorkloadPriorityClass, err error) { + emptyResult := &v1beta1.WorkloadPriorityClass{} obj, err := c.Fake. - Invokes(testing.NewRootUpdateAction(workloadpriorityclassesResource, workloadPriorityClass), &v1beta1.WorkloadPriorityClass{}) + Invokes(testing.NewRootUpdateActionWithOptions(workloadpriorityclassesResource, workloadPriorityClass, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.WorkloadPriorityClass), err } @@ -106,7 +110,7 @@ func (c *FakeWorkloadPriorityClasses) Delete(ctx context.Context, name string, o // DeleteCollection deletes a collection of objects. func (c *FakeWorkloadPriorityClasses) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewRootDeleteCollectionAction(workloadpriorityclassesResource, listOpts) + action := testing.NewRootDeleteCollectionActionWithOptions(workloadpriorityclassesResource, opts, listOpts) _, err := c.Fake.Invokes(action, &v1beta1.WorkloadPriorityClassList{}) return err @@ -114,10 +118,11 @@ func (c *FakeWorkloadPriorityClasses) DeleteCollection(ctx context.Context, opts // Patch applies the patch and returns the patched workloadPriorityClass. func (c *FakeWorkloadPriorityClasses) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.WorkloadPriorityClass, err error) { + emptyResult := &v1beta1.WorkloadPriorityClass{} obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(workloadpriorityclassesResource, name, pt, data, subresources...), &v1beta1.WorkloadPriorityClass{}) + Invokes(testing.NewRootPatchSubresourceActionWithOptions(workloadpriorityclassesResource, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.WorkloadPriorityClass), err } @@ -135,10 +140,11 @@ func (c *FakeWorkloadPriorityClasses) Apply(ctx context.Context, workloadPriorit if name == nil { return nil, fmt.Errorf("workloadPriorityClass.Name must be provided to Apply") } + emptyResult := &v1beta1.WorkloadPriorityClass{} obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(workloadpriorityclassesResource, *name, types.ApplyPatchType, data), &v1beta1.WorkloadPriorityClass{}) + Invokes(testing.NewRootPatchSubresourceActionWithOptions(workloadpriorityclassesResource, *name, types.ApplyPatchType, data, opts.ToPatchOptions()), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1beta1.WorkloadPriorityClass), err } diff --git a/client-go/clientset/versioned/typed/kueue/v1beta1/localqueue.go b/client-go/clientset/versioned/typed/kueue/v1beta1/localqueue.go index ad802f5215..2a3a862bec 100644 --- a/client-go/clientset/versioned/typed/kueue/v1beta1/localqueue.go +++ b/client-go/clientset/versioned/typed/kueue/v1beta1/localqueue.go @@ -19,14 +19,11 @@ package v1beta1 import ( "context" - json "encoding/json" - "fmt" - "time" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" kueuev1beta1 "sigs.k8s.io/kueue/client-go/applyconfiguration/kueue/v1beta1" scheme "sigs.k8s.io/kueue/client-go/clientset/versioned/scheme" @@ -42,6 +39,7 @@ type LocalQueuesGetter interface { type LocalQueueInterface interface { Create(ctx context.Context, localQueue *v1beta1.LocalQueue, opts v1.CreateOptions) (*v1beta1.LocalQueue, error) Update(ctx context.Context, localQueue *v1beta1.LocalQueue, opts v1.UpdateOptions) (*v1beta1.LocalQueue, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). UpdateStatus(ctx context.Context, localQueue *v1beta1.LocalQueue, opts v1.UpdateOptions) (*v1beta1.LocalQueue, error) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error @@ -50,206 +48,25 @@ type LocalQueueInterface interface { Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.LocalQueue, err error) Apply(ctx context.Context, localQueue *kueuev1beta1.LocalQueueApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.LocalQueue, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). ApplyStatus(ctx context.Context, localQueue *kueuev1beta1.LocalQueueApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.LocalQueue, err error) LocalQueueExpansion } // localQueues implements LocalQueueInterface type localQueues struct { - client rest.Interface - ns string + *gentype.ClientWithListAndApply[*v1beta1.LocalQueue, *v1beta1.LocalQueueList, *kueuev1beta1.LocalQueueApplyConfiguration] } // newLocalQueues returns a LocalQueues func newLocalQueues(c *KueueV1beta1Client, namespace string) *localQueues { return &localQueues{ - client: c.RESTClient(), - ns: namespace, + gentype.NewClientWithListAndApply[*v1beta1.LocalQueue, *v1beta1.LocalQueueList, *kueuev1beta1.LocalQueueApplyConfiguration]( + "localqueues", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *v1beta1.LocalQueue { return &v1beta1.LocalQueue{} }, + func() *v1beta1.LocalQueueList { return &v1beta1.LocalQueueList{} }), } } - -// Get takes name of the localQueue, and returns the corresponding localQueue object, and an error if there is any. -func (c *localQueues) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.LocalQueue, err error) { - result = &v1beta1.LocalQueue{} - err = c.client.Get(). - Namespace(c.ns). - Resource("localqueues"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of LocalQueues that match those selectors. -func (c *localQueues) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.LocalQueueList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1beta1.LocalQueueList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("localqueues"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested localQueues. -func (c *localQueues) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("localqueues"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a localQueue and creates it. Returns the server's representation of the localQueue, and an error, if there is any. -func (c *localQueues) Create(ctx context.Context, localQueue *v1beta1.LocalQueue, opts v1.CreateOptions) (result *v1beta1.LocalQueue, err error) { - result = &v1beta1.LocalQueue{} - err = c.client.Post(). - Namespace(c.ns). - Resource("localqueues"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(localQueue). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a localQueue and updates it. Returns the server's representation of the localQueue, and an error, if there is any. -func (c *localQueues) Update(ctx context.Context, localQueue *v1beta1.LocalQueue, opts v1.UpdateOptions) (result *v1beta1.LocalQueue, err error) { - result = &v1beta1.LocalQueue{} - err = c.client.Put(). - Namespace(c.ns). - Resource("localqueues"). - Name(localQueue.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(localQueue). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *localQueues) UpdateStatus(ctx context.Context, localQueue *v1beta1.LocalQueue, opts v1.UpdateOptions) (result *v1beta1.LocalQueue, err error) { - result = &v1beta1.LocalQueue{} - err = c.client.Put(). - Namespace(c.ns). - Resource("localqueues"). - Name(localQueue.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(localQueue). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the localQueue and deletes it. Returns an error if one occurs. -func (c *localQueues) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("localqueues"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *localQueues) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("localqueues"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched localQueue. -func (c *localQueues) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.LocalQueue, err error) { - result = &v1beta1.LocalQueue{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("localqueues"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} - -// Apply takes the given apply declarative configuration, applies it and returns the applied localQueue. -func (c *localQueues) Apply(ctx context.Context, localQueue *kueuev1beta1.LocalQueueApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.LocalQueue, err error) { - if localQueue == nil { - return nil, fmt.Errorf("localQueue provided to Apply must not be nil") - } - patchOpts := opts.ToPatchOptions() - data, err := json.Marshal(localQueue) - if err != nil { - return nil, err - } - name := localQueue.Name - if name == nil { - return nil, fmt.Errorf("localQueue.Name must be provided to Apply") - } - result = &v1beta1.LocalQueue{} - err = c.client.Patch(types.ApplyPatchType). - Namespace(c.ns). - Resource("localqueues"). - Name(*name). - VersionedParams(&patchOpts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} - -// ApplyStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). -func (c *localQueues) ApplyStatus(ctx context.Context, localQueue *kueuev1beta1.LocalQueueApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.LocalQueue, err error) { - if localQueue == nil { - return nil, fmt.Errorf("localQueue provided to Apply must not be nil") - } - patchOpts := opts.ToPatchOptions() - data, err := json.Marshal(localQueue) - if err != nil { - return nil, err - } - - name := localQueue.Name - if name == nil { - return nil, fmt.Errorf("localQueue.Name must be provided to Apply") - } - - result = &v1beta1.LocalQueue{} - err = c.client.Patch(types.ApplyPatchType). - Namespace(c.ns). - Resource("localqueues"). - Name(*name). - SubResource("status"). - VersionedParams(&patchOpts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/client-go/clientset/versioned/typed/kueue/v1beta1/provisioningrequestconfig.go b/client-go/clientset/versioned/typed/kueue/v1beta1/provisioningrequestconfig.go index d6a3eecc5a..0517574631 100644 --- a/client-go/clientset/versioned/typed/kueue/v1beta1/provisioningrequestconfig.go +++ b/client-go/clientset/versioned/typed/kueue/v1beta1/provisioningrequestconfig.go @@ -19,14 +19,11 @@ package v1beta1 import ( "context" - json "encoding/json" - "fmt" - "time" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" kueuev1beta1 "sigs.k8s.io/kueue/client-go/applyconfiguration/kueue/v1beta1" scheme "sigs.k8s.io/kueue/client-go/clientset/versioned/scheme" @@ -54,143 +51,18 @@ type ProvisioningRequestConfigInterface interface { // provisioningRequestConfigs implements ProvisioningRequestConfigInterface type provisioningRequestConfigs struct { - client rest.Interface + *gentype.ClientWithListAndApply[*v1beta1.ProvisioningRequestConfig, *v1beta1.ProvisioningRequestConfigList, *kueuev1beta1.ProvisioningRequestConfigApplyConfiguration] } // newProvisioningRequestConfigs returns a ProvisioningRequestConfigs func newProvisioningRequestConfigs(c *KueueV1beta1Client) *provisioningRequestConfigs { return &provisioningRequestConfigs{ - client: c.RESTClient(), + gentype.NewClientWithListAndApply[*v1beta1.ProvisioningRequestConfig, *v1beta1.ProvisioningRequestConfigList, *kueuev1beta1.ProvisioningRequestConfigApplyConfiguration]( + "provisioningrequestconfigs", + c.RESTClient(), + scheme.ParameterCodec, + "", + func() *v1beta1.ProvisioningRequestConfig { return &v1beta1.ProvisioningRequestConfig{} }, + func() *v1beta1.ProvisioningRequestConfigList { return &v1beta1.ProvisioningRequestConfigList{} }), } } - -// Get takes name of the provisioningRequestConfig, and returns the corresponding provisioningRequestConfig object, and an error if there is any. -func (c *provisioningRequestConfigs) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.ProvisioningRequestConfig, err error) { - result = &v1beta1.ProvisioningRequestConfig{} - err = c.client.Get(). - Resource("provisioningrequestconfigs"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of ProvisioningRequestConfigs that match those selectors. -func (c *provisioningRequestConfigs) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.ProvisioningRequestConfigList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1beta1.ProvisioningRequestConfigList{} - err = c.client.Get(). - Resource("provisioningrequestconfigs"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested provisioningRequestConfigs. -func (c *provisioningRequestConfigs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Resource("provisioningrequestconfigs"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a provisioningRequestConfig and creates it. Returns the server's representation of the provisioningRequestConfig, and an error, if there is any. -func (c *provisioningRequestConfigs) Create(ctx context.Context, provisioningRequestConfig *v1beta1.ProvisioningRequestConfig, opts v1.CreateOptions) (result *v1beta1.ProvisioningRequestConfig, err error) { - result = &v1beta1.ProvisioningRequestConfig{} - err = c.client.Post(). - Resource("provisioningrequestconfigs"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(provisioningRequestConfig). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a provisioningRequestConfig and updates it. Returns the server's representation of the provisioningRequestConfig, and an error, if there is any. -func (c *provisioningRequestConfigs) Update(ctx context.Context, provisioningRequestConfig *v1beta1.ProvisioningRequestConfig, opts v1.UpdateOptions) (result *v1beta1.ProvisioningRequestConfig, err error) { - result = &v1beta1.ProvisioningRequestConfig{} - err = c.client.Put(). - Resource("provisioningrequestconfigs"). - Name(provisioningRequestConfig.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(provisioningRequestConfig). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the provisioningRequestConfig and deletes it. Returns an error if one occurs. -func (c *provisioningRequestConfigs) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Resource("provisioningrequestconfigs"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *provisioningRequestConfigs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Resource("provisioningrequestconfigs"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched provisioningRequestConfig. -func (c *provisioningRequestConfigs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.ProvisioningRequestConfig, err error) { - result = &v1beta1.ProvisioningRequestConfig{} - err = c.client.Patch(pt). - Resource("provisioningrequestconfigs"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} - -// Apply takes the given apply declarative configuration, applies it and returns the applied provisioningRequestConfig. -func (c *provisioningRequestConfigs) Apply(ctx context.Context, provisioningRequestConfig *kueuev1beta1.ProvisioningRequestConfigApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.ProvisioningRequestConfig, err error) { - if provisioningRequestConfig == nil { - return nil, fmt.Errorf("provisioningRequestConfig provided to Apply must not be nil") - } - patchOpts := opts.ToPatchOptions() - data, err := json.Marshal(provisioningRequestConfig) - if err != nil { - return nil, err - } - name := provisioningRequestConfig.Name - if name == nil { - return nil, fmt.Errorf("provisioningRequestConfig.Name must be provided to Apply") - } - result = &v1beta1.ProvisioningRequestConfig{} - err = c.client.Patch(types.ApplyPatchType). - Resource("provisioningrequestconfigs"). - Name(*name). - VersionedParams(&patchOpts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/client-go/clientset/versioned/typed/kueue/v1beta1/resourceflavor.go b/client-go/clientset/versioned/typed/kueue/v1beta1/resourceflavor.go index bf91717350..cac2f656e1 100644 --- a/client-go/clientset/versioned/typed/kueue/v1beta1/resourceflavor.go +++ b/client-go/clientset/versioned/typed/kueue/v1beta1/resourceflavor.go @@ -19,14 +19,11 @@ package v1beta1 import ( "context" - json "encoding/json" - "fmt" - "time" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" kueuev1beta1 "sigs.k8s.io/kueue/client-go/applyconfiguration/kueue/v1beta1" scheme "sigs.k8s.io/kueue/client-go/clientset/versioned/scheme" @@ -54,143 +51,18 @@ type ResourceFlavorInterface interface { // resourceFlavors implements ResourceFlavorInterface type resourceFlavors struct { - client rest.Interface + *gentype.ClientWithListAndApply[*v1beta1.ResourceFlavor, *v1beta1.ResourceFlavorList, *kueuev1beta1.ResourceFlavorApplyConfiguration] } // newResourceFlavors returns a ResourceFlavors func newResourceFlavors(c *KueueV1beta1Client) *resourceFlavors { return &resourceFlavors{ - client: c.RESTClient(), + gentype.NewClientWithListAndApply[*v1beta1.ResourceFlavor, *v1beta1.ResourceFlavorList, *kueuev1beta1.ResourceFlavorApplyConfiguration]( + "resourceflavors", + c.RESTClient(), + scheme.ParameterCodec, + "", + func() *v1beta1.ResourceFlavor { return &v1beta1.ResourceFlavor{} }, + func() *v1beta1.ResourceFlavorList { return &v1beta1.ResourceFlavorList{} }), } } - -// Get takes name of the resourceFlavor, and returns the corresponding resourceFlavor object, and an error if there is any. -func (c *resourceFlavors) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.ResourceFlavor, err error) { - result = &v1beta1.ResourceFlavor{} - err = c.client.Get(). - Resource("resourceflavors"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of ResourceFlavors that match those selectors. -func (c *resourceFlavors) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.ResourceFlavorList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1beta1.ResourceFlavorList{} - err = c.client.Get(). - Resource("resourceflavors"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested resourceFlavors. -func (c *resourceFlavors) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Resource("resourceflavors"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a resourceFlavor and creates it. Returns the server's representation of the resourceFlavor, and an error, if there is any. -func (c *resourceFlavors) Create(ctx context.Context, resourceFlavor *v1beta1.ResourceFlavor, opts v1.CreateOptions) (result *v1beta1.ResourceFlavor, err error) { - result = &v1beta1.ResourceFlavor{} - err = c.client.Post(). - Resource("resourceflavors"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(resourceFlavor). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a resourceFlavor and updates it. Returns the server's representation of the resourceFlavor, and an error, if there is any. -func (c *resourceFlavors) Update(ctx context.Context, resourceFlavor *v1beta1.ResourceFlavor, opts v1.UpdateOptions) (result *v1beta1.ResourceFlavor, err error) { - result = &v1beta1.ResourceFlavor{} - err = c.client.Put(). - Resource("resourceflavors"). - Name(resourceFlavor.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(resourceFlavor). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the resourceFlavor and deletes it. Returns an error if one occurs. -func (c *resourceFlavors) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Resource("resourceflavors"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *resourceFlavors) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Resource("resourceflavors"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched resourceFlavor. -func (c *resourceFlavors) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.ResourceFlavor, err error) { - result = &v1beta1.ResourceFlavor{} - err = c.client.Patch(pt). - Resource("resourceflavors"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} - -// Apply takes the given apply declarative configuration, applies it and returns the applied resourceFlavor. -func (c *resourceFlavors) Apply(ctx context.Context, resourceFlavor *kueuev1beta1.ResourceFlavorApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.ResourceFlavor, err error) { - if resourceFlavor == nil { - return nil, fmt.Errorf("resourceFlavor provided to Apply must not be nil") - } - patchOpts := opts.ToPatchOptions() - data, err := json.Marshal(resourceFlavor) - if err != nil { - return nil, err - } - name := resourceFlavor.Name - if name == nil { - return nil, fmt.Errorf("resourceFlavor.Name must be provided to Apply") - } - result = &v1beta1.ResourceFlavor{} - err = c.client.Patch(types.ApplyPatchType). - Resource("resourceflavors"). - Name(*name). - VersionedParams(&patchOpts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/client-go/clientset/versioned/typed/kueue/v1beta1/workload.go b/client-go/clientset/versioned/typed/kueue/v1beta1/workload.go index 9ac4425396..25a0e54b12 100644 --- a/client-go/clientset/versioned/typed/kueue/v1beta1/workload.go +++ b/client-go/clientset/versioned/typed/kueue/v1beta1/workload.go @@ -19,14 +19,11 @@ package v1beta1 import ( "context" - json "encoding/json" - "fmt" - "time" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" kueuev1beta1 "sigs.k8s.io/kueue/client-go/applyconfiguration/kueue/v1beta1" scheme "sigs.k8s.io/kueue/client-go/clientset/versioned/scheme" @@ -42,6 +39,7 @@ type WorkloadsGetter interface { type WorkloadInterface interface { Create(ctx context.Context, workload *v1beta1.Workload, opts v1.CreateOptions) (*v1beta1.Workload, error) Update(ctx context.Context, workload *v1beta1.Workload, opts v1.UpdateOptions) (*v1beta1.Workload, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). UpdateStatus(ctx context.Context, workload *v1beta1.Workload, opts v1.UpdateOptions) (*v1beta1.Workload, error) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error @@ -50,206 +48,25 @@ type WorkloadInterface interface { Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Workload, err error) Apply(ctx context.Context, workload *kueuev1beta1.WorkloadApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.Workload, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). ApplyStatus(ctx context.Context, workload *kueuev1beta1.WorkloadApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.Workload, err error) WorkloadExpansion } // workloads implements WorkloadInterface type workloads struct { - client rest.Interface - ns string + *gentype.ClientWithListAndApply[*v1beta1.Workload, *v1beta1.WorkloadList, *kueuev1beta1.WorkloadApplyConfiguration] } // newWorkloads returns a Workloads func newWorkloads(c *KueueV1beta1Client, namespace string) *workloads { return &workloads{ - client: c.RESTClient(), - ns: namespace, + gentype.NewClientWithListAndApply[*v1beta1.Workload, *v1beta1.WorkloadList, *kueuev1beta1.WorkloadApplyConfiguration]( + "workloads", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *v1beta1.Workload { return &v1beta1.Workload{} }, + func() *v1beta1.WorkloadList { return &v1beta1.WorkloadList{} }), } } - -// Get takes name of the workload, and returns the corresponding workload object, and an error if there is any. -func (c *workloads) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.Workload, err error) { - result = &v1beta1.Workload{} - err = c.client.Get(). - Namespace(c.ns). - Resource("workloads"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of Workloads that match those selectors. -func (c *workloads) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.WorkloadList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1beta1.WorkloadList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("workloads"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested workloads. -func (c *workloads) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("workloads"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a workload and creates it. Returns the server's representation of the workload, and an error, if there is any. -func (c *workloads) Create(ctx context.Context, workload *v1beta1.Workload, opts v1.CreateOptions) (result *v1beta1.Workload, err error) { - result = &v1beta1.Workload{} - err = c.client.Post(). - Namespace(c.ns). - Resource("workloads"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(workload). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a workload and updates it. Returns the server's representation of the workload, and an error, if there is any. -func (c *workloads) Update(ctx context.Context, workload *v1beta1.Workload, opts v1.UpdateOptions) (result *v1beta1.Workload, err error) { - result = &v1beta1.Workload{} - err = c.client.Put(). - Namespace(c.ns). - Resource("workloads"). - Name(workload.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(workload). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *workloads) UpdateStatus(ctx context.Context, workload *v1beta1.Workload, opts v1.UpdateOptions) (result *v1beta1.Workload, err error) { - result = &v1beta1.Workload{} - err = c.client.Put(). - Namespace(c.ns). - Resource("workloads"). - Name(workload.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(workload). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the workload and deletes it. Returns an error if one occurs. -func (c *workloads) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("workloads"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *workloads) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("workloads"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched workload. -func (c *workloads) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Workload, err error) { - result = &v1beta1.Workload{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("workloads"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} - -// Apply takes the given apply declarative configuration, applies it and returns the applied workload. -func (c *workloads) Apply(ctx context.Context, workload *kueuev1beta1.WorkloadApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.Workload, err error) { - if workload == nil { - return nil, fmt.Errorf("workload provided to Apply must not be nil") - } - patchOpts := opts.ToPatchOptions() - data, err := json.Marshal(workload) - if err != nil { - return nil, err - } - name := workload.Name - if name == nil { - return nil, fmt.Errorf("workload.Name must be provided to Apply") - } - result = &v1beta1.Workload{} - err = c.client.Patch(types.ApplyPatchType). - Namespace(c.ns). - Resource("workloads"). - Name(*name). - VersionedParams(&patchOpts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} - -// ApplyStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). -func (c *workloads) ApplyStatus(ctx context.Context, workload *kueuev1beta1.WorkloadApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.Workload, err error) { - if workload == nil { - return nil, fmt.Errorf("workload provided to Apply must not be nil") - } - patchOpts := opts.ToPatchOptions() - data, err := json.Marshal(workload) - if err != nil { - return nil, err - } - - name := workload.Name - if name == nil { - return nil, fmt.Errorf("workload.Name must be provided to Apply") - } - - result = &v1beta1.Workload{} - err = c.client.Patch(types.ApplyPatchType). - Namespace(c.ns). - Resource("workloads"). - Name(*name). - SubResource("status"). - VersionedParams(&patchOpts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/client-go/clientset/versioned/typed/kueue/v1beta1/workloadpriorityclass.go b/client-go/clientset/versioned/typed/kueue/v1beta1/workloadpriorityclass.go index daf6da61d4..3e349c5804 100644 --- a/client-go/clientset/versioned/typed/kueue/v1beta1/workloadpriorityclass.go +++ b/client-go/clientset/versioned/typed/kueue/v1beta1/workloadpriorityclass.go @@ -19,14 +19,11 @@ package v1beta1 import ( "context" - json "encoding/json" - "fmt" - "time" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" kueuev1beta1 "sigs.k8s.io/kueue/client-go/applyconfiguration/kueue/v1beta1" scheme "sigs.k8s.io/kueue/client-go/clientset/versioned/scheme" @@ -54,143 +51,18 @@ type WorkloadPriorityClassInterface interface { // workloadPriorityClasses implements WorkloadPriorityClassInterface type workloadPriorityClasses struct { - client rest.Interface + *gentype.ClientWithListAndApply[*v1beta1.WorkloadPriorityClass, *v1beta1.WorkloadPriorityClassList, *kueuev1beta1.WorkloadPriorityClassApplyConfiguration] } // newWorkloadPriorityClasses returns a WorkloadPriorityClasses func newWorkloadPriorityClasses(c *KueueV1beta1Client) *workloadPriorityClasses { return &workloadPriorityClasses{ - client: c.RESTClient(), + gentype.NewClientWithListAndApply[*v1beta1.WorkloadPriorityClass, *v1beta1.WorkloadPriorityClassList, *kueuev1beta1.WorkloadPriorityClassApplyConfiguration]( + "workloadpriorityclasses", + c.RESTClient(), + scheme.ParameterCodec, + "", + func() *v1beta1.WorkloadPriorityClass { return &v1beta1.WorkloadPriorityClass{} }, + func() *v1beta1.WorkloadPriorityClassList { return &v1beta1.WorkloadPriorityClassList{} }), } } - -// Get takes name of the workloadPriorityClass, and returns the corresponding workloadPriorityClass object, and an error if there is any. -func (c *workloadPriorityClasses) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.WorkloadPriorityClass, err error) { - result = &v1beta1.WorkloadPriorityClass{} - err = c.client.Get(). - Resource("workloadpriorityclasses"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of WorkloadPriorityClasses that match those selectors. -func (c *workloadPriorityClasses) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.WorkloadPriorityClassList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1beta1.WorkloadPriorityClassList{} - err = c.client.Get(). - Resource("workloadpriorityclasses"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested workloadPriorityClasses. -func (c *workloadPriorityClasses) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Resource("workloadpriorityclasses"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a workloadPriorityClass and creates it. Returns the server's representation of the workloadPriorityClass, and an error, if there is any. -func (c *workloadPriorityClasses) Create(ctx context.Context, workloadPriorityClass *v1beta1.WorkloadPriorityClass, opts v1.CreateOptions) (result *v1beta1.WorkloadPriorityClass, err error) { - result = &v1beta1.WorkloadPriorityClass{} - err = c.client.Post(). - Resource("workloadpriorityclasses"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(workloadPriorityClass). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a workloadPriorityClass and updates it. Returns the server's representation of the workloadPriorityClass, and an error, if there is any. -func (c *workloadPriorityClasses) Update(ctx context.Context, workloadPriorityClass *v1beta1.WorkloadPriorityClass, opts v1.UpdateOptions) (result *v1beta1.WorkloadPriorityClass, err error) { - result = &v1beta1.WorkloadPriorityClass{} - err = c.client.Put(). - Resource("workloadpriorityclasses"). - Name(workloadPriorityClass.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(workloadPriorityClass). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the workloadPriorityClass and deletes it. Returns an error if one occurs. -func (c *workloadPriorityClasses) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Resource("workloadpriorityclasses"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *workloadPriorityClasses) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Resource("workloadpriorityclasses"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched workloadPriorityClass. -func (c *workloadPriorityClasses) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.WorkloadPriorityClass, err error) { - result = &v1beta1.WorkloadPriorityClass{} - err = c.client.Patch(pt). - Resource("workloadpriorityclasses"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} - -// Apply takes the given apply declarative configuration, applies it and returns the applied workloadPriorityClass. -func (c *workloadPriorityClasses) Apply(ctx context.Context, workloadPriorityClass *kueuev1beta1.WorkloadPriorityClassApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.WorkloadPriorityClass, err error) { - if workloadPriorityClass == nil { - return nil, fmt.Errorf("workloadPriorityClass provided to Apply must not be nil") - } - patchOpts := opts.ToPatchOptions() - data, err := json.Marshal(workloadPriorityClass) - if err != nil { - return nil, err - } - name := workloadPriorityClass.Name - if name == nil { - return nil, fmt.Errorf("workloadPriorityClass.Name must be provided to Apply") - } - result = &v1beta1.WorkloadPriorityClass{} - err = c.client.Patch(types.ApplyPatchType). - Resource("workloadpriorityclasses"). - Name(*name). - VersionedParams(&patchOpts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/client-go/clientset/versioned/typed/visibility/v1alpha1/clusterqueue.go b/client-go/clientset/versioned/typed/visibility/v1alpha1/clusterqueue.go index a4b6fcbf52..cf3a95be1d 100644 --- a/client-go/clientset/versioned/typed/visibility/v1alpha1/clusterqueue.go +++ b/client-go/clientset/versioned/typed/visibility/v1alpha1/clusterqueue.go @@ -19,14 +19,11 @@ package v1alpha1 import ( "context" - json "encoding/json" - "fmt" - "time" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" v1alpha1 "sigs.k8s.io/kueue/apis/visibility/v1alpha1" visibilityv1alpha1 "sigs.k8s.io/kueue/client-go/applyconfiguration/visibility/v1alpha1" scheme "sigs.k8s.io/kueue/client-go/clientset/versioned/scheme" @@ -56,151 +53,26 @@ type ClusterQueueInterface interface { // clusterQueues implements ClusterQueueInterface type clusterQueues struct { - client rest.Interface + *gentype.ClientWithListAndApply[*v1alpha1.ClusterQueue, *v1alpha1.ClusterQueueList, *visibilityv1alpha1.ClusterQueueApplyConfiguration] } // newClusterQueues returns a ClusterQueues func newClusterQueues(c *VisibilityV1alpha1Client) *clusterQueues { return &clusterQueues{ - client: c.RESTClient(), + gentype.NewClientWithListAndApply[*v1alpha1.ClusterQueue, *v1alpha1.ClusterQueueList, *visibilityv1alpha1.ClusterQueueApplyConfiguration]( + "clusterqueues", + c.RESTClient(), + scheme.ParameterCodec, + "", + func() *v1alpha1.ClusterQueue { return &v1alpha1.ClusterQueue{} }, + func() *v1alpha1.ClusterQueueList { return &v1alpha1.ClusterQueueList{} }), } } -// Get takes name of the clusterQueue, and returns the corresponding clusterQueue object, and an error if there is any. -func (c *clusterQueues) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ClusterQueue, err error) { - result = &v1alpha1.ClusterQueue{} - err = c.client.Get(). - Resource("clusterqueues"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of ClusterQueues that match those selectors. -func (c *clusterQueues) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ClusterQueueList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.ClusterQueueList{} - err = c.client.Get(). - Resource("clusterqueues"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested clusterQueues. -func (c *clusterQueues) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Resource("clusterqueues"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a clusterQueue and creates it. Returns the server's representation of the clusterQueue, and an error, if there is any. -func (c *clusterQueues) Create(ctx context.Context, clusterQueue *v1alpha1.ClusterQueue, opts v1.CreateOptions) (result *v1alpha1.ClusterQueue, err error) { - result = &v1alpha1.ClusterQueue{} - err = c.client.Post(). - Resource("clusterqueues"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(clusterQueue). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a clusterQueue and updates it. Returns the server's representation of the clusterQueue, and an error, if there is any. -func (c *clusterQueues) Update(ctx context.Context, clusterQueue *v1alpha1.ClusterQueue, opts v1.UpdateOptions) (result *v1alpha1.ClusterQueue, err error) { - result = &v1alpha1.ClusterQueue{} - err = c.client.Put(). - Resource("clusterqueues"). - Name(clusterQueue.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(clusterQueue). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the clusterQueue and deletes it. Returns an error if one occurs. -func (c *clusterQueues) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Resource("clusterqueues"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *clusterQueues) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Resource("clusterqueues"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched clusterQueue. -func (c *clusterQueues) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ClusterQueue, err error) { - result = &v1alpha1.ClusterQueue{} - err = c.client.Patch(pt). - Resource("clusterqueues"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} - -// Apply takes the given apply declarative configuration, applies it and returns the applied clusterQueue. -func (c *clusterQueues) Apply(ctx context.Context, clusterQueue *visibilityv1alpha1.ClusterQueueApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.ClusterQueue, err error) { - if clusterQueue == nil { - return nil, fmt.Errorf("clusterQueue provided to Apply must not be nil") - } - patchOpts := opts.ToPatchOptions() - data, err := json.Marshal(clusterQueue) - if err != nil { - return nil, err - } - name := clusterQueue.Name - if name == nil { - return nil, fmt.Errorf("clusterQueue.Name must be provided to Apply") - } - result = &v1alpha1.ClusterQueue{} - err = c.client.Patch(types.ApplyPatchType). - Resource("clusterqueues"). - Name(*name). - VersionedParams(&patchOpts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} - // GetPendingWorkloadsSummary takes name of the clusterQueue, and returns the corresponding v1alpha1.PendingWorkloadsSummary object, and an error if there is any. func (c *clusterQueues) GetPendingWorkloadsSummary(ctx context.Context, clusterQueueName string, options v1.GetOptions) (result *v1alpha1.PendingWorkloadsSummary, err error) { result = &v1alpha1.PendingWorkloadsSummary{} - err = c.client.Get(). + err = c.GetClient().Get(). Resource("clusterqueues"). Name(clusterQueueName). SubResource("pendingworkloads"). diff --git a/client-go/clientset/versioned/typed/visibility/v1alpha1/fake/fake_clusterqueue.go b/client-go/clientset/versioned/typed/visibility/v1alpha1/fake/fake_clusterqueue.go index d0cc7fa7d7..573e8e910f 100644 --- a/client-go/clientset/versioned/typed/visibility/v1alpha1/fake/fake_clusterqueue.go +++ b/client-go/clientset/versioned/typed/visibility/v1alpha1/fake/fake_clusterqueue.go @@ -42,20 +42,22 @@ var clusterqueuesKind = v1alpha1.SchemeGroupVersion.WithKind("ClusterQueue") // Get takes name of the clusterQueue, and returns the corresponding clusterQueue object, and an error if there is any. func (c *FakeClusterQueues) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ClusterQueue, err error) { + emptyResult := &v1alpha1.ClusterQueue{} obj, err := c.Fake. - Invokes(testing.NewRootGetAction(clusterqueuesResource, name), &v1alpha1.ClusterQueue{}) + Invokes(testing.NewRootGetActionWithOptions(clusterqueuesResource, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.ClusterQueue), err } // List takes label and field selectors, and returns the list of ClusterQueues that match those selectors. func (c *FakeClusterQueues) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ClusterQueueList, err error) { + emptyResult := &v1alpha1.ClusterQueueList{} obj, err := c.Fake. - Invokes(testing.NewRootListAction(clusterqueuesResource, clusterqueuesKind, opts), &v1alpha1.ClusterQueueList{}) + Invokes(testing.NewRootListActionWithOptions(clusterqueuesResource, clusterqueuesKind, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -74,25 +76,27 @@ func (c *FakeClusterQueues) List(ctx context.Context, opts v1.ListOptions) (resu // Watch returns a watch.Interface that watches the requested clusterQueues. func (c *FakeClusterQueues) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewRootWatchAction(clusterqueuesResource, opts)) + InvokesWatch(testing.NewRootWatchActionWithOptions(clusterqueuesResource, opts)) } // Create takes the representation of a clusterQueue and creates it. Returns the server's representation of the clusterQueue, and an error, if there is any. func (c *FakeClusterQueues) Create(ctx context.Context, clusterQueue *v1alpha1.ClusterQueue, opts v1.CreateOptions) (result *v1alpha1.ClusterQueue, err error) { + emptyResult := &v1alpha1.ClusterQueue{} obj, err := c.Fake. - Invokes(testing.NewRootCreateAction(clusterqueuesResource, clusterQueue), &v1alpha1.ClusterQueue{}) + Invokes(testing.NewRootCreateActionWithOptions(clusterqueuesResource, clusterQueue, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.ClusterQueue), err } // Update takes the representation of a clusterQueue and updates it. Returns the server's representation of the clusterQueue, and an error, if there is any. func (c *FakeClusterQueues) Update(ctx context.Context, clusterQueue *v1alpha1.ClusterQueue, opts v1.UpdateOptions) (result *v1alpha1.ClusterQueue, err error) { + emptyResult := &v1alpha1.ClusterQueue{} obj, err := c.Fake. - Invokes(testing.NewRootUpdateAction(clusterqueuesResource, clusterQueue), &v1alpha1.ClusterQueue{}) + Invokes(testing.NewRootUpdateActionWithOptions(clusterqueuesResource, clusterQueue, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.ClusterQueue), err } @@ -106,7 +110,7 @@ func (c *FakeClusterQueues) Delete(ctx context.Context, name string, opts v1.Del // DeleteCollection deletes a collection of objects. func (c *FakeClusterQueues) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewRootDeleteCollectionAction(clusterqueuesResource, listOpts) + action := testing.NewRootDeleteCollectionActionWithOptions(clusterqueuesResource, opts, listOpts) _, err := c.Fake.Invokes(action, &v1alpha1.ClusterQueueList{}) return err @@ -114,10 +118,11 @@ func (c *FakeClusterQueues) DeleteCollection(ctx context.Context, opts v1.Delete // Patch applies the patch and returns the patched clusterQueue. func (c *FakeClusterQueues) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ClusterQueue, err error) { + emptyResult := &v1alpha1.ClusterQueue{} obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(clusterqueuesResource, name, pt, data, subresources...), &v1alpha1.ClusterQueue{}) + Invokes(testing.NewRootPatchSubresourceActionWithOptions(clusterqueuesResource, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.ClusterQueue), err } @@ -135,20 +140,22 @@ func (c *FakeClusterQueues) Apply(ctx context.Context, clusterQueue *visibilityv if name == nil { return nil, fmt.Errorf("clusterQueue.Name must be provided to Apply") } + emptyResult := &v1alpha1.ClusterQueue{} obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(clusterqueuesResource, *name, types.ApplyPatchType, data), &v1alpha1.ClusterQueue{}) + Invokes(testing.NewRootPatchSubresourceActionWithOptions(clusterqueuesResource, *name, types.ApplyPatchType, data, opts.ToPatchOptions()), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.ClusterQueue), err } // GetPendingWorkloadsSummary takes name of the clusterQueue, and returns the corresponding pendingWorkloadsSummary object, and an error if there is any. func (c *FakeClusterQueues) GetPendingWorkloadsSummary(ctx context.Context, clusterQueueName string, options v1.GetOptions) (result *v1alpha1.PendingWorkloadsSummary, err error) { + emptyResult := &v1alpha1.PendingWorkloadsSummary{} obj, err := c.Fake. - Invokes(testing.NewRootGetSubresourceAction(clusterqueuesResource, "pendingworkloads", clusterQueueName), &v1alpha1.PendingWorkloadsSummary{}) + Invokes(testing.NewRootGetSubresourceActionWithOptions(clusterqueuesResource, "pendingworkloads", clusterQueueName, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.PendingWorkloadsSummary), err } diff --git a/client-go/clientset/versioned/typed/visibility/v1alpha1/fake/fake_localqueue.go b/client-go/clientset/versioned/typed/visibility/v1alpha1/fake/fake_localqueue.go index bbf264db06..f874f8f615 100644 --- a/client-go/clientset/versioned/typed/visibility/v1alpha1/fake/fake_localqueue.go +++ b/client-go/clientset/versioned/typed/visibility/v1alpha1/fake/fake_localqueue.go @@ -43,22 +43,24 @@ var localqueuesKind = v1alpha1.SchemeGroupVersion.WithKind("LocalQueue") // Get takes name of the localQueue, and returns the corresponding localQueue object, and an error if there is any. func (c *FakeLocalQueues) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.LocalQueue, err error) { + emptyResult := &v1alpha1.LocalQueue{} obj, err := c.Fake. - Invokes(testing.NewGetAction(localqueuesResource, c.ns, name), &v1alpha1.LocalQueue{}) + Invokes(testing.NewGetActionWithOptions(localqueuesResource, c.ns, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.LocalQueue), err } // List takes label and field selectors, and returns the list of LocalQueues that match those selectors. func (c *FakeLocalQueues) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.LocalQueueList, err error) { + emptyResult := &v1alpha1.LocalQueueList{} obj, err := c.Fake. - Invokes(testing.NewListAction(localqueuesResource, localqueuesKind, c.ns, opts), &v1alpha1.LocalQueueList{}) + Invokes(testing.NewListActionWithOptions(localqueuesResource, localqueuesKind, c.ns, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -77,28 +79,30 @@ func (c *FakeLocalQueues) List(ctx context.Context, opts v1.ListOptions) (result // Watch returns a watch.Interface that watches the requested localQueues. func (c *FakeLocalQueues) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewWatchAction(localqueuesResource, c.ns, opts)) + InvokesWatch(testing.NewWatchActionWithOptions(localqueuesResource, c.ns, opts)) } // Create takes the representation of a localQueue and creates it. Returns the server's representation of the localQueue, and an error, if there is any. func (c *FakeLocalQueues) Create(ctx context.Context, localQueue *v1alpha1.LocalQueue, opts v1.CreateOptions) (result *v1alpha1.LocalQueue, err error) { + emptyResult := &v1alpha1.LocalQueue{} obj, err := c.Fake. - Invokes(testing.NewCreateAction(localqueuesResource, c.ns, localQueue), &v1alpha1.LocalQueue{}) + Invokes(testing.NewCreateActionWithOptions(localqueuesResource, c.ns, localQueue, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.LocalQueue), err } // Update takes the representation of a localQueue and updates it. Returns the server's representation of the localQueue, and an error, if there is any. func (c *FakeLocalQueues) Update(ctx context.Context, localQueue *v1alpha1.LocalQueue, opts v1.UpdateOptions) (result *v1alpha1.LocalQueue, err error) { + emptyResult := &v1alpha1.LocalQueue{} obj, err := c.Fake. - Invokes(testing.NewUpdateAction(localqueuesResource, c.ns, localQueue), &v1alpha1.LocalQueue{}) + Invokes(testing.NewUpdateActionWithOptions(localqueuesResource, c.ns, localQueue, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.LocalQueue), err } @@ -113,7 +117,7 @@ func (c *FakeLocalQueues) Delete(ctx context.Context, name string, opts v1.Delet // DeleteCollection deletes a collection of objects. func (c *FakeLocalQueues) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(localqueuesResource, c.ns, listOpts) + action := testing.NewDeleteCollectionActionWithOptions(localqueuesResource, c.ns, opts, listOpts) _, err := c.Fake.Invokes(action, &v1alpha1.LocalQueueList{}) return err @@ -121,11 +125,12 @@ func (c *FakeLocalQueues) DeleteCollection(ctx context.Context, opts v1.DeleteOp // Patch applies the patch and returns the patched localQueue. func (c *FakeLocalQueues) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.LocalQueue, err error) { + emptyResult := &v1alpha1.LocalQueue{} obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(localqueuesResource, c.ns, name, pt, data, subresources...), &v1alpha1.LocalQueue{}) + Invokes(testing.NewPatchSubresourceActionWithOptions(localqueuesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.LocalQueue), err } @@ -143,22 +148,24 @@ func (c *FakeLocalQueues) Apply(ctx context.Context, localQueue *visibilityv1alp if name == nil { return nil, fmt.Errorf("localQueue.Name must be provided to Apply") } + emptyResult := &v1alpha1.LocalQueue{} obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(localqueuesResource, c.ns, *name, types.ApplyPatchType, data), &v1alpha1.LocalQueue{}) + Invokes(testing.NewPatchSubresourceActionWithOptions(localqueuesResource, c.ns, *name, types.ApplyPatchType, data, opts.ToPatchOptions()), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.LocalQueue), err } // GetPendingWorkloadsSummary takes name of the localQueue, and returns the corresponding pendingWorkloadsSummary object, and an error if there is any. func (c *FakeLocalQueues) GetPendingWorkloadsSummary(ctx context.Context, localQueueName string, options v1.GetOptions) (result *v1alpha1.PendingWorkloadsSummary, err error) { + emptyResult := &v1alpha1.PendingWorkloadsSummary{} obj, err := c.Fake. - Invokes(testing.NewGetSubresourceAction(localqueuesResource, c.ns, "pendingworkloads", localQueueName), &v1alpha1.PendingWorkloadsSummary{}) + Invokes(testing.NewGetSubresourceActionWithOptions(localqueuesResource, c.ns, "pendingworkloads", localQueueName, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.PendingWorkloadsSummary), err } diff --git a/client-go/clientset/versioned/typed/visibility/v1alpha1/localqueue.go b/client-go/clientset/versioned/typed/visibility/v1alpha1/localqueue.go index 2a8e8f59ec..42c37acd9e 100644 --- a/client-go/clientset/versioned/typed/visibility/v1alpha1/localqueue.go +++ b/client-go/clientset/versioned/typed/visibility/v1alpha1/localqueue.go @@ -19,14 +19,11 @@ package v1alpha1 import ( "context" - json "encoding/json" - "fmt" - "time" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" v1alpha1 "sigs.k8s.io/kueue/apis/visibility/v1alpha1" visibilityv1alpha1 "sigs.k8s.io/kueue/client-go/applyconfiguration/visibility/v1alpha1" scheme "sigs.k8s.io/kueue/client-go/clientset/versioned/scheme" @@ -56,163 +53,27 @@ type LocalQueueInterface interface { // localQueues implements LocalQueueInterface type localQueues struct { - client rest.Interface - ns string + *gentype.ClientWithListAndApply[*v1alpha1.LocalQueue, *v1alpha1.LocalQueueList, *visibilityv1alpha1.LocalQueueApplyConfiguration] } // newLocalQueues returns a LocalQueues func newLocalQueues(c *VisibilityV1alpha1Client, namespace string) *localQueues { return &localQueues{ - client: c.RESTClient(), - ns: namespace, + gentype.NewClientWithListAndApply[*v1alpha1.LocalQueue, *v1alpha1.LocalQueueList, *visibilityv1alpha1.LocalQueueApplyConfiguration]( + "localqueues", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *v1alpha1.LocalQueue { return &v1alpha1.LocalQueue{} }, + func() *v1alpha1.LocalQueueList { return &v1alpha1.LocalQueueList{} }), } } -// Get takes name of the localQueue, and returns the corresponding localQueue object, and an error if there is any. -func (c *localQueues) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.LocalQueue, err error) { - result = &v1alpha1.LocalQueue{} - err = c.client.Get(). - Namespace(c.ns). - Resource("localqueues"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of LocalQueues that match those selectors. -func (c *localQueues) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.LocalQueueList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.LocalQueueList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("localqueues"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested localQueues. -func (c *localQueues) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("localqueues"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a localQueue and creates it. Returns the server's representation of the localQueue, and an error, if there is any. -func (c *localQueues) Create(ctx context.Context, localQueue *v1alpha1.LocalQueue, opts v1.CreateOptions) (result *v1alpha1.LocalQueue, err error) { - result = &v1alpha1.LocalQueue{} - err = c.client.Post(). - Namespace(c.ns). - Resource("localqueues"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(localQueue). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a localQueue and updates it. Returns the server's representation of the localQueue, and an error, if there is any. -func (c *localQueues) Update(ctx context.Context, localQueue *v1alpha1.LocalQueue, opts v1.UpdateOptions) (result *v1alpha1.LocalQueue, err error) { - result = &v1alpha1.LocalQueue{} - err = c.client.Put(). - Namespace(c.ns). - Resource("localqueues"). - Name(localQueue.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(localQueue). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the localQueue and deletes it. Returns an error if one occurs. -func (c *localQueues) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("localqueues"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *localQueues) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("localqueues"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched localQueue. -func (c *localQueues) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.LocalQueue, err error) { - result = &v1alpha1.LocalQueue{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("localqueues"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} - -// Apply takes the given apply declarative configuration, applies it and returns the applied localQueue. -func (c *localQueues) Apply(ctx context.Context, localQueue *visibilityv1alpha1.LocalQueueApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.LocalQueue, err error) { - if localQueue == nil { - return nil, fmt.Errorf("localQueue provided to Apply must not be nil") - } - patchOpts := opts.ToPatchOptions() - data, err := json.Marshal(localQueue) - if err != nil { - return nil, err - } - name := localQueue.Name - if name == nil { - return nil, fmt.Errorf("localQueue.Name must be provided to Apply") - } - result = &v1alpha1.LocalQueue{} - err = c.client.Patch(types.ApplyPatchType). - Namespace(c.ns). - Resource("localqueues"). - Name(*name). - VersionedParams(&patchOpts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} - // GetPendingWorkloadsSummary takes name of the localQueue, and returns the corresponding v1alpha1.PendingWorkloadsSummary object, and an error if there is any. func (c *localQueues) GetPendingWorkloadsSummary(ctx context.Context, localQueueName string, options v1.GetOptions) (result *v1alpha1.PendingWorkloadsSummary, err error) { result = &v1alpha1.PendingWorkloadsSummary{} - err = c.client.Get(). - Namespace(c.ns). + err = c.GetClient().Get(). + Namespace(c.GetNamespace()). Resource("localqueues"). Name(localQueueName). SubResource("pendingworkloads"). diff --git a/client-go/informers/externalversions/factory.go b/client-go/informers/externalversions/factory.go index 1088f13f8d..e254a034bb 100644 --- a/client-go/informers/externalversions/factory.go +++ b/client-go/informers/externalversions/factory.go @@ -228,6 +228,7 @@ type SharedInformerFactory interface { // Start initializes all requested informers. They are handled in goroutines // which run until the stop channel gets closed. + // Warning: Start does not block. When run in a go-routine, it will race with a later WaitForCacheSync. Start(stopCh <-chan struct{}) // Shutdown marks a factory as shutting down. At that point no new diff --git a/client-go/listers/kueue/v1alpha1/multikueuecluster.go b/client-go/listers/kueue/v1alpha1/multikueuecluster.go index 1d129d4aa7..f793c330b8 100644 --- a/client-go/listers/kueue/v1alpha1/multikueuecluster.go +++ b/client-go/listers/kueue/v1alpha1/multikueuecluster.go @@ -18,8 +18,8 @@ limitations under the License. package v1alpha1 import ( - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/listers" "k8s.io/client-go/tools/cache" v1alpha1 "sigs.k8s.io/kueue/apis/kueue/v1alpha1" ) @@ -38,30 +38,10 @@ type MultiKueueClusterLister interface { // multiKueueClusterLister implements the MultiKueueClusterLister interface. type multiKueueClusterLister struct { - indexer cache.Indexer + listers.ResourceIndexer[*v1alpha1.MultiKueueCluster] } // NewMultiKueueClusterLister returns a new MultiKueueClusterLister. func NewMultiKueueClusterLister(indexer cache.Indexer) MultiKueueClusterLister { - return &multiKueueClusterLister{indexer: indexer} -} - -// List lists all MultiKueueClusters in the indexer. -func (s *multiKueueClusterLister) List(selector labels.Selector) (ret []*v1alpha1.MultiKueueCluster, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.MultiKueueCluster)) - }) - return ret, err -} - -// Get retrieves the MultiKueueCluster from the index for a given name. -func (s *multiKueueClusterLister) Get(name string) (*v1alpha1.MultiKueueCluster, error) { - obj, exists, err := s.indexer.GetByKey(name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1alpha1.Resource("multikueuecluster"), name) - } - return obj.(*v1alpha1.MultiKueueCluster), nil + return &multiKueueClusterLister{listers.New[*v1alpha1.MultiKueueCluster](indexer, v1alpha1.Resource("multikueuecluster"))} } diff --git a/client-go/listers/kueue/v1alpha1/multikueueconfig.go b/client-go/listers/kueue/v1alpha1/multikueueconfig.go index b38713c2f2..8c4b2e1ee8 100644 --- a/client-go/listers/kueue/v1alpha1/multikueueconfig.go +++ b/client-go/listers/kueue/v1alpha1/multikueueconfig.go @@ -18,8 +18,8 @@ limitations under the License. package v1alpha1 import ( - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/listers" "k8s.io/client-go/tools/cache" v1alpha1 "sigs.k8s.io/kueue/apis/kueue/v1alpha1" ) @@ -38,30 +38,10 @@ type MultiKueueConfigLister interface { // multiKueueConfigLister implements the MultiKueueConfigLister interface. type multiKueueConfigLister struct { - indexer cache.Indexer + listers.ResourceIndexer[*v1alpha1.MultiKueueConfig] } // NewMultiKueueConfigLister returns a new MultiKueueConfigLister. func NewMultiKueueConfigLister(indexer cache.Indexer) MultiKueueConfigLister { - return &multiKueueConfigLister{indexer: indexer} -} - -// List lists all MultiKueueConfigs in the indexer. -func (s *multiKueueConfigLister) List(selector labels.Selector) (ret []*v1alpha1.MultiKueueConfig, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.MultiKueueConfig)) - }) - return ret, err -} - -// Get retrieves the MultiKueueConfig from the index for a given name. -func (s *multiKueueConfigLister) Get(name string) (*v1alpha1.MultiKueueConfig, error) { - obj, exists, err := s.indexer.GetByKey(name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1alpha1.Resource("multikueueconfig"), name) - } - return obj.(*v1alpha1.MultiKueueConfig), nil + return &multiKueueConfigLister{listers.New[*v1alpha1.MultiKueueConfig](indexer, v1alpha1.Resource("multikueueconfig"))} } diff --git a/client-go/listers/kueue/v1beta1/admissioncheck.go b/client-go/listers/kueue/v1beta1/admissioncheck.go index 43b7b33e1f..57b8797b5e 100644 --- a/client-go/listers/kueue/v1beta1/admissioncheck.go +++ b/client-go/listers/kueue/v1beta1/admissioncheck.go @@ -18,8 +18,8 @@ limitations under the License. package v1beta1 import ( - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/listers" "k8s.io/client-go/tools/cache" v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" ) @@ -38,30 +38,10 @@ type AdmissionCheckLister interface { // admissionCheckLister implements the AdmissionCheckLister interface. type admissionCheckLister struct { - indexer cache.Indexer + listers.ResourceIndexer[*v1beta1.AdmissionCheck] } // NewAdmissionCheckLister returns a new AdmissionCheckLister. func NewAdmissionCheckLister(indexer cache.Indexer) AdmissionCheckLister { - return &admissionCheckLister{indexer: indexer} -} - -// List lists all AdmissionChecks in the indexer. -func (s *admissionCheckLister) List(selector labels.Selector) (ret []*v1beta1.AdmissionCheck, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1beta1.AdmissionCheck)) - }) - return ret, err -} - -// Get retrieves the AdmissionCheck from the index for a given name. -func (s *admissionCheckLister) Get(name string) (*v1beta1.AdmissionCheck, error) { - obj, exists, err := s.indexer.GetByKey(name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1beta1.Resource("admissioncheck"), name) - } - return obj.(*v1beta1.AdmissionCheck), nil + return &admissionCheckLister{listers.New[*v1beta1.AdmissionCheck](indexer, v1beta1.Resource("admissioncheck"))} } diff --git a/client-go/listers/kueue/v1beta1/clusterqueue.go b/client-go/listers/kueue/v1beta1/clusterqueue.go index 8ee08815b9..8473554d62 100644 --- a/client-go/listers/kueue/v1beta1/clusterqueue.go +++ b/client-go/listers/kueue/v1beta1/clusterqueue.go @@ -18,8 +18,8 @@ limitations under the License. package v1beta1 import ( - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/listers" "k8s.io/client-go/tools/cache" v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" ) @@ -38,30 +38,10 @@ type ClusterQueueLister interface { // clusterQueueLister implements the ClusterQueueLister interface. type clusterQueueLister struct { - indexer cache.Indexer + listers.ResourceIndexer[*v1beta1.ClusterQueue] } // NewClusterQueueLister returns a new ClusterQueueLister. func NewClusterQueueLister(indexer cache.Indexer) ClusterQueueLister { - return &clusterQueueLister{indexer: indexer} -} - -// List lists all ClusterQueues in the indexer. -func (s *clusterQueueLister) List(selector labels.Selector) (ret []*v1beta1.ClusterQueue, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1beta1.ClusterQueue)) - }) - return ret, err -} - -// Get retrieves the ClusterQueue from the index for a given name. -func (s *clusterQueueLister) Get(name string) (*v1beta1.ClusterQueue, error) { - obj, exists, err := s.indexer.GetByKey(name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1beta1.Resource("clusterqueue"), name) - } - return obj.(*v1beta1.ClusterQueue), nil + return &clusterQueueLister{listers.New[*v1beta1.ClusterQueue](indexer, v1beta1.Resource("clusterqueue"))} } diff --git a/client-go/listers/kueue/v1beta1/localqueue.go b/client-go/listers/kueue/v1beta1/localqueue.go index a333e26984..38629840ba 100644 --- a/client-go/listers/kueue/v1beta1/localqueue.go +++ b/client-go/listers/kueue/v1beta1/localqueue.go @@ -18,8 +18,8 @@ limitations under the License. package v1beta1 import ( - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/listers" "k8s.io/client-go/tools/cache" v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" ) @@ -37,25 +37,17 @@ type LocalQueueLister interface { // localQueueLister implements the LocalQueueLister interface. type localQueueLister struct { - indexer cache.Indexer + listers.ResourceIndexer[*v1beta1.LocalQueue] } // NewLocalQueueLister returns a new LocalQueueLister. func NewLocalQueueLister(indexer cache.Indexer) LocalQueueLister { - return &localQueueLister{indexer: indexer} -} - -// List lists all LocalQueues in the indexer. -func (s *localQueueLister) List(selector labels.Selector) (ret []*v1beta1.LocalQueue, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1beta1.LocalQueue)) - }) - return ret, err + return &localQueueLister{listers.New[*v1beta1.LocalQueue](indexer, v1beta1.Resource("localqueue"))} } // LocalQueues returns an object that can list and get LocalQueues. func (s *localQueueLister) LocalQueues(namespace string) LocalQueueNamespaceLister { - return localQueueNamespaceLister{indexer: s.indexer, namespace: namespace} + return localQueueNamespaceLister{listers.NewNamespaced[*v1beta1.LocalQueue](s.ResourceIndexer, namespace)} } // LocalQueueNamespaceLister helps list and get LocalQueues. @@ -73,26 +65,5 @@ type LocalQueueNamespaceLister interface { // localQueueNamespaceLister implements the LocalQueueNamespaceLister // interface. type localQueueNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all LocalQueues in the indexer for a given namespace. -func (s localQueueNamespaceLister) List(selector labels.Selector) (ret []*v1beta1.LocalQueue, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1beta1.LocalQueue)) - }) - return ret, err -} - -// Get retrieves the LocalQueue from the indexer for a given namespace and name. -func (s localQueueNamespaceLister) Get(name string) (*v1beta1.LocalQueue, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1beta1.Resource("localqueue"), name) - } - return obj.(*v1beta1.LocalQueue), nil + listers.ResourceIndexer[*v1beta1.LocalQueue] } diff --git a/client-go/listers/kueue/v1beta1/provisioningrequestconfig.go b/client-go/listers/kueue/v1beta1/provisioningrequestconfig.go index 8fff3cd047..a8666e1af7 100644 --- a/client-go/listers/kueue/v1beta1/provisioningrequestconfig.go +++ b/client-go/listers/kueue/v1beta1/provisioningrequestconfig.go @@ -18,8 +18,8 @@ limitations under the License. package v1beta1 import ( - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/listers" "k8s.io/client-go/tools/cache" v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" ) @@ -38,30 +38,10 @@ type ProvisioningRequestConfigLister interface { // provisioningRequestConfigLister implements the ProvisioningRequestConfigLister interface. type provisioningRequestConfigLister struct { - indexer cache.Indexer + listers.ResourceIndexer[*v1beta1.ProvisioningRequestConfig] } // NewProvisioningRequestConfigLister returns a new ProvisioningRequestConfigLister. func NewProvisioningRequestConfigLister(indexer cache.Indexer) ProvisioningRequestConfigLister { - return &provisioningRequestConfigLister{indexer: indexer} -} - -// List lists all ProvisioningRequestConfigs in the indexer. -func (s *provisioningRequestConfigLister) List(selector labels.Selector) (ret []*v1beta1.ProvisioningRequestConfig, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1beta1.ProvisioningRequestConfig)) - }) - return ret, err -} - -// Get retrieves the ProvisioningRequestConfig from the index for a given name. -func (s *provisioningRequestConfigLister) Get(name string) (*v1beta1.ProvisioningRequestConfig, error) { - obj, exists, err := s.indexer.GetByKey(name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1beta1.Resource("provisioningrequestconfig"), name) - } - return obj.(*v1beta1.ProvisioningRequestConfig), nil + return &provisioningRequestConfigLister{listers.New[*v1beta1.ProvisioningRequestConfig](indexer, v1beta1.Resource("provisioningrequestconfig"))} } diff --git a/client-go/listers/kueue/v1beta1/resourceflavor.go b/client-go/listers/kueue/v1beta1/resourceflavor.go index 18b00b4701..ef06f693ff 100644 --- a/client-go/listers/kueue/v1beta1/resourceflavor.go +++ b/client-go/listers/kueue/v1beta1/resourceflavor.go @@ -18,8 +18,8 @@ limitations under the License. package v1beta1 import ( - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/listers" "k8s.io/client-go/tools/cache" v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" ) @@ -38,30 +38,10 @@ type ResourceFlavorLister interface { // resourceFlavorLister implements the ResourceFlavorLister interface. type resourceFlavorLister struct { - indexer cache.Indexer + listers.ResourceIndexer[*v1beta1.ResourceFlavor] } // NewResourceFlavorLister returns a new ResourceFlavorLister. func NewResourceFlavorLister(indexer cache.Indexer) ResourceFlavorLister { - return &resourceFlavorLister{indexer: indexer} -} - -// List lists all ResourceFlavors in the indexer. -func (s *resourceFlavorLister) List(selector labels.Selector) (ret []*v1beta1.ResourceFlavor, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1beta1.ResourceFlavor)) - }) - return ret, err -} - -// Get retrieves the ResourceFlavor from the index for a given name. -func (s *resourceFlavorLister) Get(name string) (*v1beta1.ResourceFlavor, error) { - obj, exists, err := s.indexer.GetByKey(name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1beta1.Resource("resourceflavor"), name) - } - return obj.(*v1beta1.ResourceFlavor), nil + return &resourceFlavorLister{listers.New[*v1beta1.ResourceFlavor](indexer, v1beta1.Resource("resourceflavor"))} } diff --git a/client-go/listers/kueue/v1beta1/workload.go b/client-go/listers/kueue/v1beta1/workload.go index 599fce25f1..e13aa153d2 100644 --- a/client-go/listers/kueue/v1beta1/workload.go +++ b/client-go/listers/kueue/v1beta1/workload.go @@ -18,8 +18,8 @@ limitations under the License. package v1beta1 import ( - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/listers" "k8s.io/client-go/tools/cache" v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" ) @@ -37,25 +37,17 @@ type WorkloadLister interface { // workloadLister implements the WorkloadLister interface. type workloadLister struct { - indexer cache.Indexer + listers.ResourceIndexer[*v1beta1.Workload] } // NewWorkloadLister returns a new WorkloadLister. func NewWorkloadLister(indexer cache.Indexer) WorkloadLister { - return &workloadLister{indexer: indexer} -} - -// List lists all Workloads in the indexer. -func (s *workloadLister) List(selector labels.Selector) (ret []*v1beta1.Workload, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1beta1.Workload)) - }) - return ret, err + return &workloadLister{listers.New[*v1beta1.Workload](indexer, v1beta1.Resource("workload"))} } // Workloads returns an object that can list and get Workloads. func (s *workloadLister) Workloads(namespace string) WorkloadNamespaceLister { - return workloadNamespaceLister{indexer: s.indexer, namespace: namespace} + return workloadNamespaceLister{listers.NewNamespaced[*v1beta1.Workload](s.ResourceIndexer, namespace)} } // WorkloadNamespaceLister helps list and get Workloads. @@ -73,26 +65,5 @@ type WorkloadNamespaceLister interface { // workloadNamespaceLister implements the WorkloadNamespaceLister // interface. type workloadNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all Workloads in the indexer for a given namespace. -func (s workloadNamespaceLister) List(selector labels.Selector) (ret []*v1beta1.Workload, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1beta1.Workload)) - }) - return ret, err -} - -// Get retrieves the Workload from the indexer for a given namespace and name. -func (s workloadNamespaceLister) Get(name string) (*v1beta1.Workload, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1beta1.Resource("workload"), name) - } - return obj.(*v1beta1.Workload), nil + listers.ResourceIndexer[*v1beta1.Workload] } diff --git a/client-go/listers/kueue/v1beta1/workloadpriorityclass.go b/client-go/listers/kueue/v1beta1/workloadpriorityclass.go index 7037ad9469..71b9611ab9 100644 --- a/client-go/listers/kueue/v1beta1/workloadpriorityclass.go +++ b/client-go/listers/kueue/v1beta1/workloadpriorityclass.go @@ -18,8 +18,8 @@ limitations under the License. package v1beta1 import ( - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/listers" "k8s.io/client-go/tools/cache" v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" ) @@ -38,30 +38,10 @@ type WorkloadPriorityClassLister interface { // workloadPriorityClassLister implements the WorkloadPriorityClassLister interface. type workloadPriorityClassLister struct { - indexer cache.Indexer + listers.ResourceIndexer[*v1beta1.WorkloadPriorityClass] } // NewWorkloadPriorityClassLister returns a new WorkloadPriorityClassLister. func NewWorkloadPriorityClassLister(indexer cache.Indexer) WorkloadPriorityClassLister { - return &workloadPriorityClassLister{indexer: indexer} -} - -// List lists all WorkloadPriorityClasses in the indexer. -func (s *workloadPriorityClassLister) List(selector labels.Selector) (ret []*v1beta1.WorkloadPriorityClass, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1beta1.WorkloadPriorityClass)) - }) - return ret, err -} - -// Get retrieves the WorkloadPriorityClass from the index for a given name. -func (s *workloadPriorityClassLister) Get(name string) (*v1beta1.WorkloadPriorityClass, error) { - obj, exists, err := s.indexer.GetByKey(name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1beta1.Resource("workloadpriorityclass"), name) - } - return obj.(*v1beta1.WorkloadPriorityClass), nil + return &workloadPriorityClassLister{listers.New[*v1beta1.WorkloadPriorityClass](indexer, v1beta1.Resource("workloadpriorityclass"))} } diff --git a/client-go/listers/visibility/v1alpha1/clusterqueue.go b/client-go/listers/visibility/v1alpha1/clusterqueue.go index 20b0ceb1e0..d4e9d6705b 100644 --- a/client-go/listers/visibility/v1alpha1/clusterqueue.go +++ b/client-go/listers/visibility/v1alpha1/clusterqueue.go @@ -18,8 +18,8 @@ limitations under the License. package v1alpha1 import ( - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/listers" "k8s.io/client-go/tools/cache" v1alpha1 "sigs.k8s.io/kueue/apis/visibility/v1alpha1" ) @@ -38,30 +38,10 @@ type ClusterQueueLister interface { // clusterQueueLister implements the ClusterQueueLister interface. type clusterQueueLister struct { - indexer cache.Indexer + listers.ResourceIndexer[*v1alpha1.ClusterQueue] } // NewClusterQueueLister returns a new ClusterQueueLister. func NewClusterQueueLister(indexer cache.Indexer) ClusterQueueLister { - return &clusterQueueLister{indexer: indexer} -} - -// List lists all ClusterQueues in the indexer. -func (s *clusterQueueLister) List(selector labels.Selector) (ret []*v1alpha1.ClusterQueue, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.ClusterQueue)) - }) - return ret, err -} - -// Get retrieves the ClusterQueue from the index for a given name. -func (s *clusterQueueLister) Get(name string) (*v1alpha1.ClusterQueue, error) { - obj, exists, err := s.indexer.GetByKey(name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1alpha1.Resource("clusterqueue"), name) - } - return obj.(*v1alpha1.ClusterQueue), nil + return &clusterQueueLister{listers.New[*v1alpha1.ClusterQueue](indexer, v1alpha1.Resource("clusterqueue"))} } diff --git a/client-go/listers/visibility/v1alpha1/localqueue.go b/client-go/listers/visibility/v1alpha1/localqueue.go index 18838e4058..1b55b25d8c 100644 --- a/client-go/listers/visibility/v1alpha1/localqueue.go +++ b/client-go/listers/visibility/v1alpha1/localqueue.go @@ -18,8 +18,8 @@ limitations under the License. package v1alpha1 import ( - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/listers" "k8s.io/client-go/tools/cache" v1alpha1 "sigs.k8s.io/kueue/apis/visibility/v1alpha1" ) @@ -37,25 +37,17 @@ type LocalQueueLister interface { // localQueueLister implements the LocalQueueLister interface. type localQueueLister struct { - indexer cache.Indexer + listers.ResourceIndexer[*v1alpha1.LocalQueue] } // NewLocalQueueLister returns a new LocalQueueLister. func NewLocalQueueLister(indexer cache.Indexer) LocalQueueLister { - return &localQueueLister{indexer: indexer} -} - -// List lists all LocalQueues in the indexer. -func (s *localQueueLister) List(selector labels.Selector) (ret []*v1alpha1.LocalQueue, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.LocalQueue)) - }) - return ret, err + return &localQueueLister{listers.New[*v1alpha1.LocalQueue](indexer, v1alpha1.Resource("localqueue"))} } // LocalQueues returns an object that can list and get LocalQueues. func (s *localQueueLister) LocalQueues(namespace string) LocalQueueNamespaceLister { - return localQueueNamespaceLister{indexer: s.indexer, namespace: namespace} + return localQueueNamespaceLister{listers.NewNamespaced[*v1alpha1.LocalQueue](s.ResourceIndexer, namespace)} } // LocalQueueNamespaceLister helps list and get LocalQueues. @@ -73,26 +65,5 @@ type LocalQueueNamespaceLister interface { // localQueueNamespaceLister implements the LocalQueueNamespaceLister // interface. type localQueueNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all LocalQueues in the indexer for a given namespace. -func (s localQueueNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.LocalQueue, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.LocalQueue)) - }) - return ret, err -} - -// Get retrieves the LocalQueue from the indexer for a given namespace and name. -func (s localQueueNamespaceLister) Get(name string) (*v1alpha1.LocalQueue, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1alpha1.Resource("localqueue"), name) - } - return obj.(*v1alpha1.LocalQueue), nil + listers.ResourceIndexer[*v1alpha1.LocalQueue] } diff --git a/cmd/experimental/kjobctl/Makefile b/cmd/experimental/kjobctl/Makefile index 96d7b11a79..3b0255ddec 100644 --- a/cmd/experimental/kjobctl/Makefile +++ b/cmd/experimental/kjobctl/Makefile @@ -1,5 +1,5 @@ # ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. -ENVTEST_K8S_VERSION = 1.30.0 +ENVTEST_K8S_VERSION = 1.31.0 # Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) ifeq (,$(shell go env GOBIN)) diff --git a/cmd/experimental/kjobctl/client-go/clientset/versioned/fake/clientset_generated.go b/cmd/experimental/kjobctl/client-go/clientset/versioned/fake/clientset_generated.go index 86f0112c71..0f9beb6633 100644 --- a/cmd/experimental/kjobctl/client-go/clientset/versioned/fake/clientset_generated.go +++ b/cmd/experimental/kjobctl/client-go/clientset/versioned/fake/clientset_generated.go @@ -30,8 +30,12 @@ import ( // NewSimpleClientset returns a clientset that will respond with the provided objects. // It's backed by a very simple object tracker that processes creates, updates and deletions as-is, -// without applying any validations and/or defaults. It shouldn't be considered a replacement +// without applying any field management, validations and/or defaults. It shouldn't be considered a replacement // for a real clientset and is mostly useful in simple unit tests. +// +// DEPRECATED: NewClientset replaces this with support for field management, which significantly improves +// server side apply testing. NewClientset is only available when apply configurations are generated (e.g. +// via --with-applyconfig). func NewSimpleClientset(objects ...runtime.Object) *Clientset { o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) for _, obj := range objects { diff --git a/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/applicationprofile.go b/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/applicationprofile.go index c0c2b8ed45..e57894b2c6 100644 --- a/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/applicationprofile.go +++ b/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/applicationprofile.go @@ -19,12 +19,11 @@ package v1alpha1 import ( "context" - "time" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" v1alpha1 "sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1" scheme "sigs.k8s.io/kueue/cmd/experimental/kjobctl/client-go/clientset/versioned/scheme" ) @@ -50,128 +49,18 @@ type ApplicationProfileInterface interface { // applicationProfiles implements ApplicationProfileInterface type applicationProfiles struct { - client rest.Interface - ns string + *gentype.ClientWithList[*v1alpha1.ApplicationProfile, *v1alpha1.ApplicationProfileList] } // newApplicationProfiles returns a ApplicationProfiles func newApplicationProfiles(c *KjobctlV1alpha1Client, namespace string) *applicationProfiles { return &applicationProfiles{ - client: c.RESTClient(), - ns: namespace, + gentype.NewClientWithList[*v1alpha1.ApplicationProfile, *v1alpha1.ApplicationProfileList]( + "applicationprofiles", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *v1alpha1.ApplicationProfile { return &v1alpha1.ApplicationProfile{} }, + func() *v1alpha1.ApplicationProfileList { return &v1alpha1.ApplicationProfileList{} }), } } - -// Get takes name of the applicationProfile, and returns the corresponding applicationProfile object, and an error if there is any. -func (c *applicationProfiles) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ApplicationProfile, err error) { - result = &v1alpha1.ApplicationProfile{} - err = c.client.Get(). - Namespace(c.ns). - Resource("applicationprofiles"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of ApplicationProfiles that match those selectors. -func (c *applicationProfiles) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ApplicationProfileList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.ApplicationProfileList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("applicationprofiles"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested applicationProfiles. -func (c *applicationProfiles) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("applicationprofiles"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a applicationProfile and creates it. Returns the server's representation of the applicationProfile, and an error, if there is any. -func (c *applicationProfiles) Create(ctx context.Context, applicationProfile *v1alpha1.ApplicationProfile, opts v1.CreateOptions) (result *v1alpha1.ApplicationProfile, err error) { - result = &v1alpha1.ApplicationProfile{} - err = c.client.Post(). - Namespace(c.ns). - Resource("applicationprofiles"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(applicationProfile). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a applicationProfile and updates it. Returns the server's representation of the applicationProfile, and an error, if there is any. -func (c *applicationProfiles) Update(ctx context.Context, applicationProfile *v1alpha1.ApplicationProfile, opts v1.UpdateOptions) (result *v1alpha1.ApplicationProfile, err error) { - result = &v1alpha1.ApplicationProfile{} - err = c.client.Put(). - Namespace(c.ns). - Resource("applicationprofiles"). - Name(applicationProfile.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(applicationProfile). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the applicationProfile and deletes it. Returns an error if one occurs. -func (c *applicationProfiles) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("applicationprofiles"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *applicationProfiles) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("applicationprofiles"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched applicationProfile. -func (c *applicationProfiles) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ApplicationProfile, err error) { - result = &v1alpha1.ApplicationProfile{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("applicationprofiles"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/fake/fake_applicationprofile.go b/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/fake/fake_applicationprofile.go index facf97e206..80963e1e9f 100644 --- a/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/fake/fake_applicationprofile.go +++ b/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/fake/fake_applicationprofile.go @@ -40,22 +40,24 @@ var applicationprofilesKind = v1alpha1.SchemeGroupVersion.WithKind("ApplicationP // Get takes name of the applicationProfile, and returns the corresponding applicationProfile object, and an error if there is any. func (c *FakeApplicationProfiles) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ApplicationProfile, err error) { + emptyResult := &v1alpha1.ApplicationProfile{} obj, err := c.Fake. - Invokes(testing.NewGetAction(applicationprofilesResource, c.ns, name), &v1alpha1.ApplicationProfile{}) + Invokes(testing.NewGetActionWithOptions(applicationprofilesResource, c.ns, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.ApplicationProfile), err } // List takes label and field selectors, and returns the list of ApplicationProfiles that match those selectors. func (c *FakeApplicationProfiles) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ApplicationProfileList, err error) { + emptyResult := &v1alpha1.ApplicationProfileList{} obj, err := c.Fake. - Invokes(testing.NewListAction(applicationprofilesResource, applicationprofilesKind, c.ns, opts), &v1alpha1.ApplicationProfileList{}) + Invokes(testing.NewListActionWithOptions(applicationprofilesResource, applicationprofilesKind, c.ns, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -74,28 +76,30 @@ func (c *FakeApplicationProfiles) List(ctx context.Context, opts v1.ListOptions) // Watch returns a watch.Interface that watches the requested applicationProfiles. func (c *FakeApplicationProfiles) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewWatchAction(applicationprofilesResource, c.ns, opts)) + InvokesWatch(testing.NewWatchActionWithOptions(applicationprofilesResource, c.ns, opts)) } // Create takes the representation of a applicationProfile and creates it. Returns the server's representation of the applicationProfile, and an error, if there is any. func (c *FakeApplicationProfiles) Create(ctx context.Context, applicationProfile *v1alpha1.ApplicationProfile, opts v1.CreateOptions) (result *v1alpha1.ApplicationProfile, err error) { + emptyResult := &v1alpha1.ApplicationProfile{} obj, err := c.Fake. - Invokes(testing.NewCreateAction(applicationprofilesResource, c.ns, applicationProfile), &v1alpha1.ApplicationProfile{}) + Invokes(testing.NewCreateActionWithOptions(applicationprofilesResource, c.ns, applicationProfile, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.ApplicationProfile), err } // Update takes the representation of a applicationProfile and updates it. Returns the server's representation of the applicationProfile, and an error, if there is any. func (c *FakeApplicationProfiles) Update(ctx context.Context, applicationProfile *v1alpha1.ApplicationProfile, opts v1.UpdateOptions) (result *v1alpha1.ApplicationProfile, err error) { + emptyResult := &v1alpha1.ApplicationProfile{} obj, err := c.Fake. - Invokes(testing.NewUpdateAction(applicationprofilesResource, c.ns, applicationProfile), &v1alpha1.ApplicationProfile{}) + Invokes(testing.NewUpdateActionWithOptions(applicationprofilesResource, c.ns, applicationProfile, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.ApplicationProfile), err } @@ -110,7 +114,7 @@ func (c *FakeApplicationProfiles) Delete(ctx context.Context, name string, opts // DeleteCollection deletes a collection of objects. func (c *FakeApplicationProfiles) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(applicationprofilesResource, c.ns, listOpts) + action := testing.NewDeleteCollectionActionWithOptions(applicationprofilesResource, c.ns, opts, listOpts) _, err := c.Fake.Invokes(action, &v1alpha1.ApplicationProfileList{}) return err @@ -118,11 +122,12 @@ func (c *FakeApplicationProfiles) DeleteCollection(ctx context.Context, opts v1. // Patch applies the patch and returns the patched applicationProfile. func (c *FakeApplicationProfiles) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ApplicationProfile, err error) { + emptyResult := &v1alpha1.ApplicationProfile{} obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(applicationprofilesResource, c.ns, name, pt, data, subresources...), &v1alpha1.ApplicationProfile{}) + Invokes(testing.NewPatchSubresourceActionWithOptions(applicationprofilesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.ApplicationProfile), err } diff --git a/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/fake/fake_jobtemplate.go b/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/fake/fake_jobtemplate.go index 590d64aa0a..456d17661c 100644 --- a/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/fake/fake_jobtemplate.go +++ b/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/fake/fake_jobtemplate.go @@ -40,22 +40,24 @@ var jobtemplatesKind = v1alpha1.SchemeGroupVersion.WithKind("JobTemplate") // Get takes name of the jobTemplate, and returns the corresponding jobTemplate object, and an error if there is any. func (c *FakeJobTemplates) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.JobTemplate, err error) { + emptyResult := &v1alpha1.JobTemplate{} obj, err := c.Fake. - Invokes(testing.NewGetAction(jobtemplatesResource, c.ns, name), &v1alpha1.JobTemplate{}) + Invokes(testing.NewGetActionWithOptions(jobtemplatesResource, c.ns, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.JobTemplate), err } // List takes label and field selectors, and returns the list of JobTemplates that match those selectors. func (c *FakeJobTemplates) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.JobTemplateList, err error) { + emptyResult := &v1alpha1.JobTemplateList{} obj, err := c.Fake. - Invokes(testing.NewListAction(jobtemplatesResource, jobtemplatesKind, c.ns, opts), &v1alpha1.JobTemplateList{}) + Invokes(testing.NewListActionWithOptions(jobtemplatesResource, jobtemplatesKind, c.ns, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -74,28 +76,30 @@ func (c *FakeJobTemplates) List(ctx context.Context, opts v1.ListOptions) (resul // Watch returns a watch.Interface that watches the requested jobTemplates. func (c *FakeJobTemplates) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewWatchAction(jobtemplatesResource, c.ns, opts)) + InvokesWatch(testing.NewWatchActionWithOptions(jobtemplatesResource, c.ns, opts)) } // Create takes the representation of a jobTemplate and creates it. Returns the server's representation of the jobTemplate, and an error, if there is any. func (c *FakeJobTemplates) Create(ctx context.Context, jobTemplate *v1alpha1.JobTemplate, opts v1.CreateOptions) (result *v1alpha1.JobTemplate, err error) { + emptyResult := &v1alpha1.JobTemplate{} obj, err := c.Fake. - Invokes(testing.NewCreateAction(jobtemplatesResource, c.ns, jobTemplate), &v1alpha1.JobTemplate{}) + Invokes(testing.NewCreateActionWithOptions(jobtemplatesResource, c.ns, jobTemplate, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.JobTemplate), err } // Update takes the representation of a jobTemplate and updates it. Returns the server's representation of the jobTemplate, and an error, if there is any. func (c *FakeJobTemplates) Update(ctx context.Context, jobTemplate *v1alpha1.JobTemplate, opts v1.UpdateOptions) (result *v1alpha1.JobTemplate, err error) { + emptyResult := &v1alpha1.JobTemplate{} obj, err := c.Fake. - Invokes(testing.NewUpdateAction(jobtemplatesResource, c.ns, jobTemplate), &v1alpha1.JobTemplate{}) + Invokes(testing.NewUpdateActionWithOptions(jobtemplatesResource, c.ns, jobTemplate, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.JobTemplate), err } @@ -110,7 +114,7 @@ func (c *FakeJobTemplates) Delete(ctx context.Context, name string, opts v1.Dele // DeleteCollection deletes a collection of objects. func (c *FakeJobTemplates) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(jobtemplatesResource, c.ns, listOpts) + action := testing.NewDeleteCollectionActionWithOptions(jobtemplatesResource, c.ns, opts, listOpts) _, err := c.Fake.Invokes(action, &v1alpha1.JobTemplateList{}) return err @@ -118,11 +122,12 @@ func (c *FakeJobTemplates) DeleteCollection(ctx context.Context, opts v1.DeleteO // Patch applies the patch and returns the patched jobTemplate. func (c *FakeJobTemplates) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.JobTemplate, err error) { + emptyResult := &v1alpha1.JobTemplate{} obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(jobtemplatesResource, c.ns, name, pt, data, subresources...), &v1alpha1.JobTemplate{}) + Invokes(testing.NewPatchSubresourceActionWithOptions(jobtemplatesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.JobTemplate), err } diff --git a/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/fake/fake_rayclustertemplate.go b/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/fake/fake_rayclustertemplate.go index 6de333512e..4e0cb8637e 100644 --- a/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/fake/fake_rayclustertemplate.go +++ b/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/fake/fake_rayclustertemplate.go @@ -40,22 +40,24 @@ var rayclustertemplatesKind = v1alpha1.SchemeGroupVersion.WithKind("RayClusterTe // Get takes name of the rayClusterTemplate, and returns the corresponding rayClusterTemplate object, and an error if there is any. func (c *FakeRayClusterTemplates) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.RayClusterTemplate, err error) { + emptyResult := &v1alpha1.RayClusterTemplate{} obj, err := c.Fake. - Invokes(testing.NewGetAction(rayclustertemplatesResource, c.ns, name), &v1alpha1.RayClusterTemplate{}) + Invokes(testing.NewGetActionWithOptions(rayclustertemplatesResource, c.ns, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.RayClusterTemplate), err } // List takes label and field selectors, and returns the list of RayClusterTemplates that match those selectors. func (c *FakeRayClusterTemplates) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.RayClusterTemplateList, err error) { + emptyResult := &v1alpha1.RayClusterTemplateList{} obj, err := c.Fake. - Invokes(testing.NewListAction(rayclustertemplatesResource, rayclustertemplatesKind, c.ns, opts), &v1alpha1.RayClusterTemplateList{}) + Invokes(testing.NewListActionWithOptions(rayclustertemplatesResource, rayclustertemplatesKind, c.ns, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -74,28 +76,30 @@ func (c *FakeRayClusterTemplates) List(ctx context.Context, opts v1.ListOptions) // Watch returns a watch.Interface that watches the requested rayClusterTemplates. func (c *FakeRayClusterTemplates) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewWatchAction(rayclustertemplatesResource, c.ns, opts)) + InvokesWatch(testing.NewWatchActionWithOptions(rayclustertemplatesResource, c.ns, opts)) } // Create takes the representation of a rayClusterTemplate and creates it. Returns the server's representation of the rayClusterTemplate, and an error, if there is any. func (c *FakeRayClusterTemplates) Create(ctx context.Context, rayClusterTemplate *v1alpha1.RayClusterTemplate, opts v1.CreateOptions) (result *v1alpha1.RayClusterTemplate, err error) { + emptyResult := &v1alpha1.RayClusterTemplate{} obj, err := c.Fake. - Invokes(testing.NewCreateAction(rayclustertemplatesResource, c.ns, rayClusterTemplate), &v1alpha1.RayClusterTemplate{}) + Invokes(testing.NewCreateActionWithOptions(rayclustertemplatesResource, c.ns, rayClusterTemplate, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.RayClusterTemplate), err } // Update takes the representation of a rayClusterTemplate and updates it. Returns the server's representation of the rayClusterTemplate, and an error, if there is any. func (c *FakeRayClusterTemplates) Update(ctx context.Context, rayClusterTemplate *v1alpha1.RayClusterTemplate, opts v1.UpdateOptions) (result *v1alpha1.RayClusterTemplate, err error) { + emptyResult := &v1alpha1.RayClusterTemplate{} obj, err := c.Fake. - Invokes(testing.NewUpdateAction(rayclustertemplatesResource, c.ns, rayClusterTemplate), &v1alpha1.RayClusterTemplate{}) + Invokes(testing.NewUpdateActionWithOptions(rayclustertemplatesResource, c.ns, rayClusterTemplate, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.RayClusterTemplate), err } @@ -110,7 +114,7 @@ func (c *FakeRayClusterTemplates) Delete(ctx context.Context, name string, opts // DeleteCollection deletes a collection of objects. func (c *FakeRayClusterTemplates) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(rayclustertemplatesResource, c.ns, listOpts) + action := testing.NewDeleteCollectionActionWithOptions(rayclustertemplatesResource, c.ns, opts, listOpts) _, err := c.Fake.Invokes(action, &v1alpha1.RayClusterTemplateList{}) return err @@ -118,11 +122,12 @@ func (c *FakeRayClusterTemplates) DeleteCollection(ctx context.Context, opts v1. // Patch applies the patch and returns the patched rayClusterTemplate. func (c *FakeRayClusterTemplates) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.RayClusterTemplate, err error) { + emptyResult := &v1alpha1.RayClusterTemplate{} obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(rayclustertemplatesResource, c.ns, name, pt, data, subresources...), &v1alpha1.RayClusterTemplate{}) + Invokes(testing.NewPatchSubresourceActionWithOptions(rayclustertemplatesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.RayClusterTemplate), err } diff --git a/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/fake/fake_rayjobtemplate.go b/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/fake/fake_rayjobtemplate.go index b155cf40f7..2c9ea7193e 100644 --- a/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/fake/fake_rayjobtemplate.go +++ b/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/fake/fake_rayjobtemplate.go @@ -40,22 +40,24 @@ var rayjobtemplatesKind = v1alpha1.SchemeGroupVersion.WithKind("RayJobTemplate") // Get takes name of the rayJobTemplate, and returns the corresponding rayJobTemplate object, and an error if there is any. func (c *FakeRayJobTemplates) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.RayJobTemplate, err error) { + emptyResult := &v1alpha1.RayJobTemplate{} obj, err := c.Fake. - Invokes(testing.NewGetAction(rayjobtemplatesResource, c.ns, name), &v1alpha1.RayJobTemplate{}) + Invokes(testing.NewGetActionWithOptions(rayjobtemplatesResource, c.ns, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.RayJobTemplate), err } // List takes label and field selectors, and returns the list of RayJobTemplates that match those selectors. func (c *FakeRayJobTemplates) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.RayJobTemplateList, err error) { + emptyResult := &v1alpha1.RayJobTemplateList{} obj, err := c.Fake. - Invokes(testing.NewListAction(rayjobtemplatesResource, rayjobtemplatesKind, c.ns, opts), &v1alpha1.RayJobTemplateList{}) + Invokes(testing.NewListActionWithOptions(rayjobtemplatesResource, rayjobtemplatesKind, c.ns, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -74,28 +76,30 @@ func (c *FakeRayJobTemplates) List(ctx context.Context, opts v1.ListOptions) (re // Watch returns a watch.Interface that watches the requested rayJobTemplates. func (c *FakeRayJobTemplates) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewWatchAction(rayjobtemplatesResource, c.ns, opts)) + InvokesWatch(testing.NewWatchActionWithOptions(rayjobtemplatesResource, c.ns, opts)) } // Create takes the representation of a rayJobTemplate and creates it. Returns the server's representation of the rayJobTemplate, and an error, if there is any. func (c *FakeRayJobTemplates) Create(ctx context.Context, rayJobTemplate *v1alpha1.RayJobTemplate, opts v1.CreateOptions) (result *v1alpha1.RayJobTemplate, err error) { + emptyResult := &v1alpha1.RayJobTemplate{} obj, err := c.Fake. - Invokes(testing.NewCreateAction(rayjobtemplatesResource, c.ns, rayJobTemplate), &v1alpha1.RayJobTemplate{}) + Invokes(testing.NewCreateActionWithOptions(rayjobtemplatesResource, c.ns, rayJobTemplate, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.RayJobTemplate), err } // Update takes the representation of a rayJobTemplate and updates it. Returns the server's representation of the rayJobTemplate, and an error, if there is any. func (c *FakeRayJobTemplates) Update(ctx context.Context, rayJobTemplate *v1alpha1.RayJobTemplate, opts v1.UpdateOptions) (result *v1alpha1.RayJobTemplate, err error) { + emptyResult := &v1alpha1.RayJobTemplate{} obj, err := c.Fake. - Invokes(testing.NewUpdateAction(rayjobtemplatesResource, c.ns, rayJobTemplate), &v1alpha1.RayJobTemplate{}) + Invokes(testing.NewUpdateActionWithOptions(rayjobtemplatesResource, c.ns, rayJobTemplate, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.RayJobTemplate), err } @@ -110,7 +114,7 @@ func (c *FakeRayJobTemplates) Delete(ctx context.Context, name string, opts v1.D // DeleteCollection deletes a collection of objects. func (c *FakeRayJobTemplates) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(rayjobtemplatesResource, c.ns, listOpts) + action := testing.NewDeleteCollectionActionWithOptions(rayjobtemplatesResource, c.ns, opts, listOpts) _, err := c.Fake.Invokes(action, &v1alpha1.RayJobTemplateList{}) return err @@ -118,11 +122,12 @@ func (c *FakeRayJobTemplates) DeleteCollection(ctx context.Context, opts v1.Dele // Patch applies the patch and returns the patched rayJobTemplate. func (c *FakeRayJobTemplates) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.RayJobTemplate, err error) { + emptyResult := &v1alpha1.RayJobTemplate{} obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(rayjobtemplatesResource, c.ns, name, pt, data, subresources...), &v1alpha1.RayJobTemplate{}) + Invokes(testing.NewPatchSubresourceActionWithOptions(rayjobtemplatesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.RayJobTemplate), err } diff --git a/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/fake/fake_volumebundle.go b/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/fake/fake_volumebundle.go index 939237e002..7626eb0269 100644 --- a/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/fake/fake_volumebundle.go +++ b/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/fake/fake_volumebundle.go @@ -40,22 +40,24 @@ var volumebundlesKind = v1alpha1.SchemeGroupVersion.WithKind("VolumeBundle") // Get takes name of the volumeBundle, and returns the corresponding volumeBundle object, and an error if there is any. func (c *FakeVolumeBundles) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.VolumeBundle, err error) { + emptyResult := &v1alpha1.VolumeBundle{} obj, err := c.Fake. - Invokes(testing.NewGetAction(volumebundlesResource, c.ns, name), &v1alpha1.VolumeBundle{}) + Invokes(testing.NewGetActionWithOptions(volumebundlesResource, c.ns, name, options), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.VolumeBundle), err } // List takes label and field selectors, and returns the list of VolumeBundles that match those selectors. func (c *FakeVolumeBundles) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.VolumeBundleList, err error) { + emptyResult := &v1alpha1.VolumeBundleList{} obj, err := c.Fake. - Invokes(testing.NewListAction(volumebundlesResource, volumebundlesKind, c.ns, opts), &v1alpha1.VolumeBundleList{}) + Invokes(testing.NewListActionWithOptions(volumebundlesResource, volumebundlesKind, c.ns, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } label, _, _ := testing.ExtractFromListOptions(opts) @@ -74,28 +76,30 @@ func (c *FakeVolumeBundles) List(ctx context.Context, opts v1.ListOptions) (resu // Watch returns a watch.Interface that watches the requested volumeBundles. func (c *FakeVolumeBundles) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewWatchAction(volumebundlesResource, c.ns, opts)) + InvokesWatch(testing.NewWatchActionWithOptions(volumebundlesResource, c.ns, opts)) } // Create takes the representation of a volumeBundle and creates it. Returns the server's representation of the volumeBundle, and an error, if there is any. func (c *FakeVolumeBundles) Create(ctx context.Context, volumeBundle *v1alpha1.VolumeBundle, opts v1.CreateOptions) (result *v1alpha1.VolumeBundle, err error) { + emptyResult := &v1alpha1.VolumeBundle{} obj, err := c.Fake. - Invokes(testing.NewCreateAction(volumebundlesResource, c.ns, volumeBundle), &v1alpha1.VolumeBundle{}) + Invokes(testing.NewCreateActionWithOptions(volumebundlesResource, c.ns, volumeBundle, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.VolumeBundle), err } // Update takes the representation of a volumeBundle and updates it. Returns the server's representation of the volumeBundle, and an error, if there is any. func (c *FakeVolumeBundles) Update(ctx context.Context, volumeBundle *v1alpha1.VolumeBundle, opts v1.UpdateOptions) (result *v1alpha1.VolumeBundle, err error) { + emptyResult := &v1alpha1.VolumeBundle{} obj, err := c.Fake. - Invokes(testing.NewUpdateAction(volumebundlesResource, c.ns, volumeBundle), &v1alpha1.VolumeBundle{}) + Invokes(testing.NewUpdateActionWithOptions(volumebundlesResource, c.ns, volumeBundle, opts), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.VolumeBundle), err } @@ -110,7 +114,7 @@ func (c *FakeVolumeBundles) Delete(ctx context.Context, name string, opts v1.Del // DeleteCollection deletes a collection of objects. func (c *FakeVolumeBundles) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(volumebundlesResource, c.ns, listOpts) + action := testing.NewDeleteCollectionActionWithOptions(volumebundlesResource, c.ns, opts, listOpts) _, err := c.Fake.Invokes(action, &v1alpha1.VolumeBundleList{}) return err @@ -118,11 +122,12 @@ func (c *FakeVolumeBundles) DeleteCollection(ctx context.Context, opts v1.Delete // Patch applies the patch and returns the patched volumeBundle. func (c *FakeVolumeBundles) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.VolumeBundle, err error) { + emptyResult := &v1alpha1.VolumeBundle{} obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(volumebundlesResource, c.ns, name, pt, data, subresources...), &v1alpha1.VolumeBundle{}) + Invokes(testing.NewPatchSubresourceActionWithOptions(volumebundlesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) if obj == nil { - return nil, err + return emptyResult, err } return obj.(*v1alpha1.VolumeBundle), err } diff --git a/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/jobtemplate.go b/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/jobtemplate.go index 311deefe7c..3d94830dc9 100644 --- a/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/jobtemplate.go +++ b/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/jobtemplate.go @@ -19,12 +19,11 @@ package v1alpha1 import ( "context" - "time" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" v1alpha1 "sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1" scheme "sigs.k8s.io/kueue/cmd/experimental/kjobctl/client-go/clientset/versioned/scheme" ) @@ -50,128 +49,18 @@ type JobTemplateInterface interface { // jobTemplates implements JobTemplateInterface type jobTemplates struct { - client rest.Interface - ns string + *gentype.ClientWithList[*v1alpha1.JobTemplate, *v1alpha1.JobTemplateList] } // newJobTemplates returns a JobTemplates func newJobTemplates(c *KjobctlV1alpha1Client, namespace string) *jobTemplates { return &jobTemplates{ - client: c.RESTClient(), - ns: namespace, + gentype.NewClientWithList[*v1alpha1.JobTemplate, *v1alpha1.JobTemplateList]( + "jobtemplates", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *v1alpha1.JobTemplate { return &v1alpha1.JobTemplate{} }, + func() *v1alpha1.JobTemplateList { return &v1alpha1.JobTemplateList{} }), } } - -// Get takes name of the jobTemplate, and returns the corresponding jobTemplate object, and an error if there is any. -func (c *jobTemplates) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.JobTemplate, err error) { - result = &v1alpha1.JobTemplate{} - err = c.client.Get(). - Namespace(c.ns). - Resource("jobtemplates"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of JobTemplates that match those selectors. -func (c *jobTemplates) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.JobTemplateList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.JobTemplateList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("jobtemplates"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested jobTemplates. -func (c *jobTemplates) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("jobtemplates"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a jobTemplate and creates it. Returns the server's representation of the jobTemplate, and an error, if there is any. -func (c *jobTemplates) Create(ctx context.Context, jobTemplate *v1alpha1.JobTemplate, opts v1.CreateOptions) (result *v1alpha1.JobTemplate, err error) { - result = &v1alpha1.JobTemplate{} - err = c.client.Post(). - Namespace(c.ns). - Resource("jobtemplates"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(jobTemplate). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a jobTemplate and updates it. Returns the server's representation of the jobTemplate, and an error, if there is any. -func (c *jobTemplates) Update(ctx context.Context, jobTemplate *v1alpha1.JobTemplate, opts v1.UpdateOptions) (result *v1alpha1.JobTemplate, err error) { - result = &v1alpha1.JobTemplate{} - err = c.client.Put(). - Namespace(c.ns). - Resource("jobtemplates"). - Name(jobTemplate.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(jobTemplate). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the jobTemplate and deletes it. Returns an error if one occurs. -func (c *jobTemplates) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("jobtemplates"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *jobTemplates) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("jobtemplates"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched jobTemplate. -func (c *jobTemplates) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.JobTemplate, err error) { - result = &v1alpha1.JobTemplate{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("jobtemplates"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/rayclustertemplate.go b/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/rayclustertemplate.go index 5da7db6bb5..02ca4569c6 100644 --- a/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/rayclustertemplate.go +++ b/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/rayclustertemplate.go @@ -19,12 +19,11 @@ package v1alpha1 import ( "context" - "time" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" v1alpha1 "sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1" scheme "sigs.k8s.io/kueue/cmd/experimental/kjobctl/client-go/clientset/versioned/scheme" ) @@ -50,128 +49,18 @@ type RayClusterTemplateInterface interface { // rayClusterTemplates implements RayClusterTemplateInterface type rayClusterTemplates struct { - client rest.Interface - ns string + *gentype.ClientWithList[*v1alpha1.RayClusterTemplate, *v1alpha1.RayClusterTemplateList] } // newRayClusterTemplates returns a RayClusterTemplates func newRayClusterTemplates(c *KjobctlV1alpha1Client, namespace string) *rayClusterTemplates { return &rayClusterTemplates{ - client: c.RESTClient(), - ns: namespace, + gentype.NewClientWithList[*v1alpha1.RayClusterTemplate, *v1alpha1.RayClusterTemplateList]( + "rayclustertemplates", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *v1alpha1.RayClusterTemplate { return &v1alpha1.RayClusterTemplate{} }, + func() *v1alpha1.RayClusterTemplateList { return &v1alpha1.RayClusterTemplateList{} }), } } - -// Get takes name of the rayClusterTemplate, and returns the corresponding rayClusterTemplate object, and an error if there is any. -func (c *rayClusterTemplates) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.RayClusterTemplate, err error) { - result = &v1alpha1.RayClusterTemplate{} - err = c.client.Get(). - Namespace(c.ns). - Resource("rayclustertemplates"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of RayClusterTemplates that match those selectors. -func (c *rayClusterTemplates) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.RayClusterTemplateList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.RayClusterTemplateList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("rayclustertemplates"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested rayClusterTemplates. -func (c *rayClusterTemplates) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("rayclustertemplates"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a rayClusterTemplate and creates it. Returns the server's representation of the rayClusterTemplate, and an error, if there is any. -func (c *rayClusterTemplates) Create(ctx context.Context, rayClusterTemplate *v1alpha1.RayClusterTemplate, opts v1.CreateOptions) (result *v1alpha1.RayClusterTemplate, err error) { - result = &v1alpha1.RayClusterTemplate{} - err = c.client.Post(). - Namespace(c.ns). - Resource("rayclustertemplates"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(rayClusterTemplate). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a rayClusterTemplate and updates it. Returns the server's representation of the rayClusterTemplate, and an error, if there is any. -func (c *rayClusterTemplates) Update(ctx context.Context, rayClusterTemplate *v1alpha1.RayClusterTemplate, opts v1.UpdateOptions) (result *v1alpha1.RayClusterTemplate, err error) { - result = &v1alpha1.RayClusterTemplate{} - err = c.client.Put(). - Namespace(c.ns). - Resource("rayclustertemplates"). - Name(rayClusterTemplate.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(rayClusterTemplate). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the rayClusterTemplate and deletes it. Returns an error if one occurs. -func (c *rayClusterTemplates) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("rayclustertemplates"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *rayClusterTemplates) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("rayclustertemplates"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched rayClusterTemplate. -func (c *rayClusterTemplates) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.RayClusterTemplate, err error) { - result = &v1alpha1.RayClusterTemplate{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("rayclustertemplates"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/rayjobtemplate.go b/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/rayjobtemplate.go index ac9b958829..3c616960f0 100644 --- a/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/rayjobtemplate.go +++ b/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/rayjobtemplate.go @@ -19,12 +19,11 @@ package v1alpha1 import ( "context" - "time" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" v1alpha1 "sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1" scheme "sigs.k8s.io/kueue/cmd/experimental/kjobctl/client-go/clientset/versioned/scheme" ) @@ -50,128 +49,18 @@ type RayJobTemplateInterface interface { // rayJobTemplates implements RayJobTemplateInterface type rayJobTemplates struct { - client rest.Interface - ns string + *gentype.ClientWithList[*v1alpha1.RayJobTemplate, *v1alpha1.RayJobTemplateList] } // newRayJobTemplates returns a RayJobTemplates func newRayJobTemplates(c *KjobctlV1alpha1Client, namespace string) *rayJobTemplates { return &rayJobTemplates{ - client: c.RESTClient(), - ns: namespace, + gentype.NewClientWithList[*v1alpha1.RayJobTemplate, *v1alpha1.RayJobTemplateList]( + "rayjobtemplates", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *v1alpha1.RayJobTemplate { return &v1alpha1.RayJobTemplate{} }, + func() *v1alpha1.RayJobTemplateList { return &v1alpha1.RayJobTemplateList{} }), } } - -// Get takes name of the rayJobTemplate, and returns the corresponding rayJobTemplate object, and an error if there is any. -func (c *rayJobTemplates) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.RayJobTemplate, err error) { - result = &v1alpha1.RayJobTemplate{} - err = c.client.Get(). - Namespace(c.ns). - Resource("rayjobtemplates"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of RayJobTemplates that match those selectors. -func (c *rayJobTemplates) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.RayJobTemplateList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.RayJobTemplateList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("rayjobtemplates"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested rayJobTemplates. -func (c *rayJobTemplates) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("rayjobtemplates"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a rayJobTemplate and creates it. Returns the server's representation of the rayJobTemplate, and an error, if there is any. -func (c *rayJobTemplates) Create(ctx context.Context, rayJobTemplate *v1alpha1.RayJobTemplate, opts v1.CreateOptions) (result *v1alpha1.RayJobTemplate, err error) { - result = &v1alpha1.RayJobTemplate{} - err = c.client.Post(). - Namespace(c.ns). - Resource("rayjobtemplates"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(rayJobTemplate). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a rayJobTemplate and updates it. Returns the server's representation of the rayJobTemplate, and an error, if there is any. -func (c *rayJobTemplates) Update(ctx context.Context, rayJobTemplate *v1alpha1.RayJobTemplate, opts v1.UpdateOptions) (result *v1alpha1.RayJobTemplate, err error) { - result = &v1alpha1.RayJobTemplate{} - err = c.client.Put(). - Namespace(c.ns). - Resource("rayjobtemplates"). - Name(rayJobTemplate.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(rayJobTemplate). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the rayJobTemplate and deletes it. Returns an error if one occurs. -func (c *rayJobTemplates) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("rayjobtemplates"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *rayJobTemplates) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("rayjobtemplates"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched rayJobTemplate. -func (c *rayJobTemplates) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.RayJobTemplate, err error) { - result = &v1alpha1.RayJobTemplate{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("rayjobtemplates"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/volumebundle.go b/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/volumebundle.go index cd304512fd..afa0590e5f 100644 --- a/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/volumebundle.go +++ b/cmd/experimental/kjobctl/client-go/clientset/versioned/typed/apis/v1alpha1/volumebundle.go @@ -19,12 +19,11 @@ package v1alpha1 import ( "context" - "time" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" v1alpha1 "sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1" scheme "sigs.k8s.io/kueue/cmd/experimental/kjobctl/client-go/clientset/versioned/scheme" ) @@ -50,128 +49,18 @@ type VolumeBundleInterface interface { // volumeBundles implements VolumeBundleInterface type volumeBundles struct { - client rest.Interface - ns string + *gentype.ClientWithList[*v1alpha1.VolumeBundle, *v1alpha1.VolumeBundleList] } // newVolumeBundles returns a VolumeBundles func newVolumeBundles(c *KjobctlV1alpha1Client, namespace string) *volumeBundles { return &volumeBundles{ - client: c.RESTClient(), - ns: namespace, + gentype.NewClientWithList[*v1alpha1.VolumeBundle, *v1alpha1.VolumeBundleList]( + "volumebundles", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *v1alpha1.VolumeBundle { return &v1alpha1.VolumeBundle{} }, + func() *v1alpha1.VolumeBundleList { return &v1alpha1.VolumeBundleList{} }), } } - -// Get takes name of the volumeBundle, and returns the corresponding volumeBundle object, and an error if there is any. -func (c *volumeBundles) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.VolumeBundle, err error) { - result = &v1alpha1.VolumeBundle{} - err = c.client.Get(). - Namespace(c.ns). - Resource("volumebundles"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of VolumeBundles that match those selectors. -func (c *volumeBundles) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.VolumeBundleList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.VolumeBundleList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("volumebundles"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested volumeBundles. -func (c *volumeBundles) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("volumebundles"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a volumeBundle and creates it. Returns the server's representation of the volumeBundle, and an error, if there is any. -func (c *volumeBundles) Create(ctx context.Context, volumeBundle *v1alpha1.VolumeBundle, opts v1.CreateOptions) (result *v1alpha1.VolumeBundle, err error) { - result = &v1alpha1.VolumeBundle{} - err = c.client.Post(). - Namespace(c.ns). - Resource("volumebundles"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(volumeBundle). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a volumeBundle and updates it. Returns the server's representation of the volumeBundle, and an error, if there is any. -func (c *volumeBundles) Update(ctx context.Context, volumeBundle *v1alpha1.VolumeBundle, opts v1.UpdateOptions) (result *v1alpha1.VolumeBundle, err error) { - result = &v1alpha1.VolumeBundle{} - err = c.client.Put(). - Namespace(c.ns). - Resource("volumebundles"). - Name(volumeBundle.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(volumeBundle). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the volumeBundle and deletes it. Returns an error if one occurs. -func (c *volumeBundles) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("volumebundles"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *volumeBundles) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("volumebundles"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched volumeBundle. -func (c *volumeBundles) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.VolumeBundle, err error) { - result = &v1alpha1.VolumeBundle{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("volumebundles"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/cmd/experimental/kjobctl/config/crd/bases/kjobctl.x-k8s.io_applicationprofiles.yaml b/cmd/experimental/kjobctl/config/crd/bases/kjobctl.x-k8s.io_applicationprofiles.yaml index bfa7eb50c2..d72fcdde7b 100644 --- a/cmd/experimental/kjobctl/config/crd/bases/kjobctl.x-k8s.io_applicationprofiles.yaml +++ b/cmd/experimental/kjobctl/config/crd/bases/kjobctl.x-k8s.io_applicationprofiles.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.16.2 name: applicationprofiles.kjobctl.x-k8s.io spec: group: kjobctl.x-k8s.io @@ -66,7 +66,6 @@ spec: For the Slurm mode, the possible values are: array, cpus-per-task, error, gpus-per-task, input, job-name, mem-per-cpu, mem-per-gpu, mem-per-task, nodes, ntasks, output, partition, localqueue. - cmd and requests values are going to be added only to the first primary container. items: enum: diff --git a/cmd/experimental/kjobctl/config/crd/bases/kjobctl.x-k8s.io_jobtemplates.yaml b/cmd/experimental/kjobctl/config/crd/bases/kjobctl.x-k8s.io_jobtemplates.yaml index 28af1278bf..f88ae058bc 100644 --- a/cmd/experimental/kjobctl/config/crd/bases/kjobctl.x-k8s.io_jobtemplates.yaml +++ b/cmd/experimental/kjobctl/config/crd/bases/kjobctl.x-k8s.io_jobtemplates.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.16.2 name: jobtemplates.kjobctl.x-k8s.io spec: group: kjobctl.x-k8s.io @@ -78,12 +78,10 @@ spec: completionMode specifies how Pod completions are tracked. It can be `NonIndexed` (default) or `Indexed`. - `NonIndexed` means that the Job is considered complete when there have been .spec.completions successfully completed Pods. Each Pod completion is homologous to each other. - `Indexed` means that the Pods of a Job get an associated completion index from 0 to (.spec.completions - 1), available in the annotation batch.kubernetes.io/job-completion-index. @@ -95,7 +93,6 @@ spec: `$(job-name)-$(index)-$(random-string)`, the Pod hostname takes the form `$(job-name)-$(index)`. - More completion modes can be added in the future. If the Job controller observes a mode that it doesn't recognize, which is possible during upgrades due to version skew, the controller @@ -120,8 +117,8 @@ spec: The value must be a valid domain-prefixed path (e.g. acme.io/foo) - all characters before the first "/" must be a valid subdomain as defined by RFC 1123. All characters trailing the first "/" must be valid HTTP Path - characters as defined by RFC 3986. The value cannot exceed 64 characters. - + characters as defined by RFC 3986. The value cannot exceed 63 characters. + This field is immutable. This field is alpha-level. The job controller accepts setting the field when the feature gate JobManagedBy is enabled (disabled by default). @@ -171,10 +168,6 @@ spec: represented by the jobs's .status.failed field, is incremented and it is checked against the backoffLimit. This field cannot be used in combination with restartPolicy=OnFailure. - - - This field is beta-level. It can be used when the `JobPodFailurePolicy` - feature gate is enabled (enabled by default). properties: rules: description: |- @@ -193,7 +186,6 @@ spec: Specifies the action taken on a pod failure when the requirements are satisfied. Possible values are: - - FailJob: indicates that the pod's job is marked as Failed and all running pods are terminated. - FailIndex: indicates that the pod's index is marked as Failed and will @@ -224,7 +216,6 @@ spec: specified values. Containers completed with success (exit code 0) are excluded from the requirement check. Possible values are: - - In: the requirement is satisfied if at least one container exit code (might be multiple if there are multiple containers not restricted by the 'containerName' field) is in the set of specified values. @@ -294,7 +285,6 @@ spec: - Failed means to wait until a previously created Pod is fully terminated (has phase Failed or Succeeded) before creating a replacement Pod. - When using podFailurePolicy, Failed is the the only allowed value. TerminatingOrFailed and Failed are allowed values when podFailurePolicy is not in use. This is an beta field. To use this, enable the JobPodReplacementPolicy feature toggle. @@ -357,9 +347,8 @@ spec: When the field is specified, it must be immutable and works only for the Indexed Jobs. Once the Job meets the SuccessPolicy, the lingering pods are terminated. - - This field is alpha-level. To use this field, you must enable the - `JobSuccessPolicy` feature gate (disabled by default). + This field is beta-level. To use this field, you must enable the + `JobSuccessPolicy` feature gate (enabled by default). properties: rules: description: |- @@ -729,7 +718,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -744,7 +733,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -913,7 +902,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -928,7 +917,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1095,7 +1084,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1110,7 +1099,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1279,7 +1268,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1294,7 +1283,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1460,9 +1449,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap @@ -1532,9 +1519,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret @@ -1574,9 +1559,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap @@ -1599,9 +1582,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret @@ -1902,11 +1883,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -2118,11 +2099,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -2272,11 +2253,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one @@ -2288,6 +2267,12 @@ spec: the Pod where this field is used. It makes that resource available inside a container. type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string required: - name type: object @@ -2411,7 +2396,7 @@ spec: procMount: description: |- procMount denotes the type of proc mount to use for the containers. - The default is DefaultProcMount which uses the container runtime defaults for + The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. @@ -2493,7 +2478,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -2575,11 +2559,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -2797,10 +2781,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -2808,11 +2790,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -2921,7 +2901,6 @@ spec: removed or restarted. The kubelet may evict a Pod if an ephemeral container causes the Pod to exceed its resource allocation. - To add an ephemeral container, use the ephemeralcontainers subresource of an existing Pod. Ephemeral containers may not be removed or restarted. properties: @@ -2994,9 +2973,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap @@ -3066,9 +3043,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret @@ -3108,9 +3083,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap @@ -3133,9 +3106,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret @@ -3430,11 +3401,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -3636,11 +3607,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -3789,11 +3760,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one @@ -3805,6 +3774,12 @@ spec: the Pod where this field is used. It makes that resource available inside a container. type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string required: - name type: object @@ -3916,7 +3891,7 @@ spec: procMount: description: |- procMount denotes the type of proc mount to use for the containers. - The default is DefaultProcMount which uses the container runtime defaults for + The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. @@ -3998,7 +3973,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -4074,11 +4048,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -4217,7 +4191,6 @@ spec: The ephemeral container will be run in the namespaces (IPC, PID, etc) of this container. If not set then the ephemeral container uses the namespaces configured in the Pod spec. - The container runtime must implement support for this feature. If the runtime does not support namespace targeting then the result of setting this field is undefined. type: string @@ -4306,10 +4279,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -4317,11 +4288,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -4433,9 +4402,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -4531,9 +4498,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap @@ -4603,9 +4568,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret @@ -4645,9 +4608,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap @@ -4670,9 +4631,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret @@ -4973,11 +4932,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -5189,11 +5148,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -5343,11 +5302,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one @@ -5359,6 +5316,12 @@ spec: the Pod where this field is used. It makes that resource available inside a container. type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string required: - name type: object @@ -5482,7 +5445,7 @@ spec: procMount: description: |- procMount denotes the type of proc mount to use for the containers. - The default is DefaultProcMount which uses the container runtime defaults for + The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. @@ -5564,7 +5527,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -5646,11 +5608,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -5868,10 +5830,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -5879,11 +5839,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -5922,9 +5880,11 @@ spec: x-kubernetes-list-type: map nodeName: description: |- - NodeName is a request to schedule this pod onto a specific node. If it is non-empty, - the scheduler simply schedules this pod onto that node, assuming that it fits resource - requirements. + NodeName indicates in which node this pod is scheduled. + If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. + Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. + This field should not be used to express a desire for the pod to be scheduled on a specific node. + https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename type: string nodeSelector: additionalProperties: @@ -5940,11 +5900,9 @@ spec: Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set. - If the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions - If the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC @@ -5959,6 +5917,7 @@ spec: - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups + - spec.securityContext.supplementalGroupsPolicy - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile @@ -6046,15 +6005,16 @@ spec: will be made available to those containers which consume them by name. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. items: description: |- - PodResourceClaim references exactly one ResourceClaim through a ClaimSource. + PodResourceClaim references exactly one ResourceClaim, either directly + or by naming a ResourceClaimTemplate which is then turned into a ResourceClaim + for the pod. + It adds a name to it that uniquely identifies the ResourceClaim inside the Pod. Containers that need access to the ResourceClaim reference it with this name. properties: @@ -6063,33 +6023,32 @@ spec: Name uniquely identifies this resource claim inside the pod. This must be a DNS_LABEL. type: string - source: - description: Source describes where to find the - ResourceClaim. - properties: - resourceClaimName: - description: |- - ResourceClaimName is the name of a ResourceClaim object in the same - namespace as this pod. - type: string - resourceClaimTemplateName: - description: |- - ResourceClaimTemplateName is the name of a ResourceClaimTemplate - object in the same namespace as this pod. + resourceClaimName: + description: |- + ResourceClaimName is the name of a ResourceClaim object in the same + namespace as this pod. + Exactly one of ResourceClaimName and ResourceClaimTemplateName must + be set. + type: string + resourceClaimTemplateName: + description: |- + ResourceClaimTemplateName is the name of a ResourceClaimTemplate + object in the same namespace as this pod. - The template will be used to create a new ResourceClaim, which will - be bound to this pod. When this pod is deleted, the ResourceClaim - will also be deleted. The pod name and resource name, along with a - generated component, will be used to form a unique name for the - ResourceClaim, which will be recorded in pod.status.resourceClaimStatuses. + The template will be used to create a new ResourceClaim, which will + be bound to this pod. When this pod is deleted, the ResourceClaim + will also be deleted. The pod name and resource name, along with a + generated component, will be used to form a unique name for the + ResourceClaim, which will be recorded in pod.status.resourceClaimStatuses. + This field is immutable and no changes will be made to the + corresponding ResourceClaim by the control plane after creating the + ResourceClaim. - This field is immutable and no changes will be made to the - corresponding ResourceClaim by the control plane after creating the - ResourceClaim. - type: string - type: object + Exactly one of ResourceClaimName and ResourceClaimTemplateName must + be set. + type: string required: - name type: object @@ -6123,7 +6082,6 @@ spec: If schedulingGates is not empty, the pod will stay in the SchedulingGated state and the scheduler will not attempt to schedule the pod. - SchedulingGates can only be set at pod creation time, and be removed only afterwards. items: description: PodSchedulingGate is associated to a Pod @@ -6175,12 +6133,10 @@ spec: Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: - 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- - If unset, the Kubelet will not modify the ownership and permissions of any volume. Note that this field cannot be set when spec.os.name is windows. format: int64 @@ -6267,7 +6223,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -6277,18 +6232,28 @@ spec: type: object supplementalGroups: description: |- - A list of groups applied to the first process run in each container, in addition - to the container's primary GID, the fsGroup (if specified), and group memberships - defined in the container image for the uid of the container process. If unspecified, - no additional groups are added to any container. Note that group memberships - defined in the container image for the uid of the container process are still effective, - even if they are not included in this list. + A list of groups applied to the first process run in each container, in + addition to the container's primary GID and fsGroup (if specified). If + the SupplementalGroupsPolicy feature is enabled, the + supplementalGroupsPolicy field determines whether these are in addition + to or instead of any group memberships defined in the container image. + If unspecified, no additional groups are added, though group memberships + defined in the container image may still be used, depending on the + supplementalGroupsPolicy field. Note that this field cannot be set when spec.os.name is windows. items: format: int64 type: integer type: array x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + description: |- + Defines how supplemental groups of the first container processes are calculated. + Valid values are "Merge" and "Strict". If not specified, "Merge" is used. + (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled + and the container runtime must implement support for this feature. + Note that this field cannot be set when spec.os.name is windows. + type: string sysctls: description: |- Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported @@ -6496,7 +6461,6 @@ spec: Keys that don't exist in the incoming pod labels will be ignored. A null or empty list means only match against labelSelector. - This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). items: type: string @@ -6536,7 +6500,6 @@ spec: Valid values are integers greater than 0. When value is not nil, WhenUnsatisfiable must be DoNotSchedule. - For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same labelSelector spread as 2/2/2: | zone1 | zone2 | zone3 | @@ -6554,7 +6517,6 @@ spec: - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. - If this value is nil, the behavior is equivalent to the Honor policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -6566,7 +6528,6 @@ spec: has a toleration, are included. - Ignore: node taints are ignored. All nodes are included. - If this value is nil, the behavior is equivalent to the Ignore policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -6634,7 +6595,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - TODO: how do we prevent errors in the filesystem from compromising the machine type: string partition: description: |- @@ -6674,6 +6634,7 @@ spec: in the blob storage type: string fsType: + default: ext4 description: |- fsType is Filesystem type to mount. Must be a filesystem type supported by the host operating system. @@ -6687,6 +6648,7 @@ spec: set). defaults to shared' type: string readOnly: + default: false description: |- readOnly Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. @@ -6757,9 +6719,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -6801,9 +6761,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -6876,9 +6834,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional specify whether the ConfigMap @@ -6917,9 +6873,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -7062,7 +7016,6 @@ spec: The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted when the pod is removed. - Use this if: a) the volume is only needed while the pod runs, b) features of normal volumes like restoring from snapshot or capacity @@ -7073,17 +7026,14 @@ spec: information on the connection between this volume type and PersistentVolumeClaim). - Use PersistentVolumeClaim or one of the vendor-specific APIs for volumes that persist for longer than the lifecycle of an individual pod. - Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to be used that way - see the documentation of the driver for more information. - A pod can use both types of ephemeral volumes and persistent volumes at the same time. properties: @@ -7097,7 +7047,6 @@ spec: entry. Pod validation will reject the pod if the concatenated name is not valid for a PVC (for example, too long). - An existing PVC with that name that is not owned by the pod will *not* be used for the pod to avoid using an unrelated volume by mistake. Starting the pod is then blocked until @@ -7107,11 +7056,9 @@ spec: this should not be necessary, but it may be useful when manually reconstructing a broken cluster. - This field is read-only and no changes will be made by Kubernetes to the PVC after it has been created. - Required, must not be nil. properties: metadata: @@ -7315,7 +7262,7 @@ spec: set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource exists. More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Alpha) Using this field requires the VolumeAttributesClass feature gate to be enabled. + (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). type: string volumeMode: description: |- @@ -7342,7 +7289,6 @@ spec: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - TODO: how do we prevent errors in the filesystem from compromising the machine type: string lun: description: 'lun is Optional: FC target lun @@ -7411,9 +7357,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -7448,7 +7392,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - TODO: how do we prevent errors in the filesystem from compromising the machine type: string partition: description: |- @@ -7529,9 +7472,6 @@ spec: used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - --- - TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not - mount host directories as read/write. properties: path: description: |- @@ -7548,6 +7488,41 @@ spec: required: - path type: object + image: + description: |- + image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine. + The volume is resolved at pod startup depending on which PullPolicy value is provided: + + - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + + The volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation. + A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message. + The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field. + The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images. + The volume will be mounted read-only (ro) and non-executable files (noexec). + Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath). + The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. + properties: + pullPolicy: + description: |- + Policy for pulling OCI objects. Possible values are: + Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + type: string + reference: + description: |- + Required: Image or artifact reference to be used. + Behaves in the same way as pod.spec.containers[*].image. + Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets. + More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management to default or override + container images in workload controllers like Deployments and StatefulSets. + type: string + type: object iscsi: description: |- iscsi represents an ISCSI Disk resource that is attached to a @@ -7568,7 +7543,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi - TODO: how do we prevent errors in the filesystem from compromising the machine type: string initiatorName: description: |- @@ -7581,6 +7555,7 @@ spec: Name. type: string iscsiInterface: + default: default description: |- iscsiInterface is the interface Name that uses an iSCSI transport. Defaults to 'default' (tcp). @@ -7614,9 +7589,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -7735,24 +7708,24 @@ spec: format: int32 type: integer sources: - description: sources is the list of volume projections + description: |- + sources is the list of volume projections. Each entry in this list + handles one source. items: - description: Projection that may be projected - along with other supported volume types + description: |- + Projection that may be projected along with other supported volume types. + Exactly one of these fields must be set. properties: clusterTrustBundle: description: |- ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field of ClusterTrustBundle objects in an auto-updating file. - Alpha, gated by the ClusterTrustBundleProjection feature gate. - ClusterTrustBundle objects can either be selected by name, or by the combination of signer name and a label selector. - Kubelet performs aggressive normalization of the PEM contents written into the pod filesystem. Esoteric PEM features such as inter-block comments and block headers are stripped. Certificates are deduplicated. @@ -7889,9 +7862,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional specify whether @@ -8038,9 +8009,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional field specify @@ -8132,7 +8101,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd - TODO: how do we prevent errors in the filesystem from compromising the machine type: string image: description: |- @@ -8140,6 +8108,7 @@ spec: More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it type: string keyring: + default: /etc/ceph/keyring description: |- keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. @@ -8154,6 +8123,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd description: |- pool is the rados pool name. Default is rbd. @@ -8179,13 +8149,12 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic user: + default: admin description: |- user is the rados user name. Default is admin. @@ -8200,6 +8169,7 @@ spec: volume attached and mounted on Kubernetes nodes. properties: fsType: + default: xfs description: |- fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. @@ -8232,9 +8202,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -8243,6 +8211,7 @@ spec: SSL communication with Gateway, default false type: boolean storageMode: + default: ThinProvisioned description: |- storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. Default is ThinProvisioned. @@ -8357,9 +8326,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -8432,6 +8399,8 @@ spec: required: - spec type: object + required: + - template type: object served: true storage: true diff --git a/cmd/experimental/kjobctl/config/crd/bases/kjobctl.x-k8s.io_rayclustertemplates.yaml b/cmd/experimental/kjobctl/config/crd/bases/kjobctl.x-k8s.io_rayclustertemplates.yaml index ab03069f38..35aeb6e03f 100644 --- a/cmd/experimental/kjobctl/config/crd/bases/kjobctl.x-k8s.io_rayclustertemplates.yaml +++ b/cmd/experimental/kjobctl/config/crd/bases/kjobctl.x-k8s.io_rayclustertemplates.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.16.2 name: rayclustertemplates.kjobctl.x-k8s.io spec: group: kjobctl.x-k8s.io @@ -90,9 +90,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap or @@ -158,9 +156,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret or its @@ -192,9 +188,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap must @@ -216,9 +210,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret must be @@ -254,11 +246,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. @@ -269,6 +259,12 @@ spec: the Pod where this field is used. It makes that resource available inside a container. type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string required: - name type: object @@ -374,7 +370,7 @@ spec: procMount: description: |- procMount denotes the type of proc mount to use for the containers. - The default is DefaultProcMount which uses the container runtime defaults for + The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. @@ -456,7 +452,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -543,10 +538,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -554,11 +547,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -671,7 +662,6 @@ spec: clients must ensure that clusterIPs[0] and clusterIP have the same value. - This field may hold a maximum of two entries (dual-stack IPs, in either order). These IPs must correspond to the values of the ipFamilies field. Both clusterIPs and ipFamilies are governed by the ipFamilyPolicy field. @@ -751,7 +741,6 @@ spec: NodePort, and LoadBalancer, and does apply to "headless" services. This field will be wiped when updating a Service to type ExternalName. - This field may hold a maximum of two entries (dual-stack families, in either order). These families must correspond to the values of the clusterIPs field, if specified. Both clusterIPs and ipFamilies are @@ -822,17 +811,14 @@ spec: This field follows standard Kubernetes label syntax. Valid values are either: - * Un-prefixed protocol names - reserved for IANA standard service names (as per RFC-6335 and https://www.iana.org/assignments/service-names). - * Kubernetes-defined prefixed names: * 'kubernetes.io/h2c' - HTTP/2 prior knowledge over cleartext as described in https://www.rfc-editor.org/rfc/rfc9113.html#name-starting-http-2-with-prior- * 'kubernetes.io/ws' - WebSocket over cleartext as described in https://www.rfc-editor.org/rfc/rfc6455 * 'kubernetes.io/wss' - WebSocket over TLS as described in https://www.rfc-editor.org/rfc/rfc6455 - * Other protocols should use implementation-defined prefixed names such as mycompany.com/my-custom-protocol. type: string @@ -978,19 +964,8 @@ spec: conditions: description: Current service state 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}" + description: Condition contains details for one + aspect of the current state of this API Resource. properties: lastTransitionTime: description: |- @@ -1032,12 +1007,8 @@ spec: - 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) + description: type of condition in CamelCase + or in foo.example.com/CamelCase. 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 @@ -1099,8 +1070,6 @@ spec: CamelCase names - cloud provider specific error values must have names that comply with the format foo.example.com/CamelCase. - --- - 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 @@ -1111,12 +1080,12 @@ spec: format: int32 type: integer protocol: - default: TCP description: |- Protocol is the protocol of the service port of which status is recorded here The supported values are: "TCP", "UDP", "SCTP" type: string required: + - error - port - protocol type: object @@ -1454,7 +1423,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1469,7 +1438,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1639,7 +1608,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1654,7 +1623,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1823,7 +1792,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1838,7 +1807,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -2008,7 +1977,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -2023,7 +1992,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -2191,9 +2160,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the @@ -2266,9 +2233,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the @@ -2308,9 +2273,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap @@ -2333,9 +2296,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret @@ -2640,11 +2601,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -2861,11 +2822,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -3019,11 +2980,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references @@ -3035,6 +2994,12 @@ spec: the Pod where this field is used. It makes that resource available inside a container. type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string required: - name type: object @@ -3158,7 +3123,7 @@ spec: procMount: description: |- procMount denotes the type of proc mount to use for the containers. - The default is DefaultProcMount which uses the container runtime defaults for + The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. @@ -3240,7 +3205,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -3325,11 +3289,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -3550,10 +3514,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -3561,11 +3523,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -3674,7 +3634,6 @@ spec: removed or restarted. The kubelet may evict a Pod if an ephemeral container causes the Pod to exceed its resource allocation. - To add an ephemeral container, use the ephemeralcontainers subresource of an existing Pod. Ephemeral containers may not be removed or restarted. properties: @@ -3748,9 +3707,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the @@ -3823,9 +3780,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the @@ -3865,9 +3820,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap @@ -3890,9 +3843,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret @@ -4191,11 +4142,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -4402,11 +4353,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -4559,11 +4510,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references @@ -4575,6 +4524,12 @@ spec: the Pod where this field is used. It makes that resource available inside a container. type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string required: - name type: object @@ -4686,7 +4641,7 @@ spec: procMount: description: |- procMount denotes the type of proc mount to use for the containers. - The default is DefaultProcMount which uses the container runtime defaults for + The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. @@ -4768,7 +4723,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -4847,11 +4801,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -4993,7 +4947,6 @@ spec: The ephemeral container will be run in the namespaces (IPC, PID, etc) of this container. If not set then the ephemeral container uses the namespaces configured in the Pod spec. - The container runtime must implement support for this feature. If the runtime does not support namespace targeting then the result of setting this field is undefined. type: string @@ -5082,10 +5035,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -5093,11 +5044,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -5209,9 +5158,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -5308,9 +5255,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the @@ -5383,9 +5328,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the @@ -5425,9 +5368,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap @@ -5450,9 +5391,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret @@ -5757,11 +5696,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -5978,11 +5917,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -6136,11 +6075,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references @@ -6152,6 +6089,12 @@ spec: the Pod where this field is used. It makes that resource available inside a container. type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string required: - name type: object @@ -6275,7 +6218,7 @@ spec: procMount: description: |- procMount denotes the type of proc mount to use for the containers. - The default is DefaultProcMount which uses the container runtime defaults for + The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. @@ -6357,7 +6300,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -6442,11 +6384,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -6667,10 +6609,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -6678,11 +6618,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -6721,9 +6659,11 @@ spec: x-kubernetes-list-type: map nodeName: description: |- - NodeName is a request to schedule this pod onto a specific node. If it is non-empty, - the scheduler simply schedules this pod onto that node, assuming that it fits resource - requirements. + NodeName indicates in which node this pod is scheduled. + If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. + Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. + This field should not be used to express a desire for the pod to be scheduled on a specific node. + https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename type: string nodeSelector: additionalProperties: @@ -6739,11 +6679,9 @@ spec: Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set. - If the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions - If the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC @@ -6758,6 +6696,7 @@ spec: - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups + - spec.securityContext.supplementalGroupsPolicy - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile @@ -6846,15 +6785,16 @@ spec: will be made available to those containers which consume them by name. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. items: description: |- - PodResourceClaim references exactly one ResourceClaim through a ClaimSource. + PodResourceClaim references exactly one ResourceClaim, either directly + or by naming a ResourceClaimTemplate which is then turned into a ResourceClaim + for the pod. + It adds a name to it that uniquely identifies the ResourceClaim inside the Pod. Containers that need access to the ResourceClaim reference it with this name. properties: @@ -6863,33 +6803,32 @@ spec: Name uniquely identifies this resource claim inside the pod. This must be a DNS_LABEL. type: string - source: - description: Source describes where to find - the ResourceClaim. - properties: - resourceClaimName: - description: |- - ResourceClaimName is the name of a ResourceClaim object in the same - namespace as this pod. - type: string - resourceClaimTemplateName: - description: |- - ResourceClaimTemplateName is the name of a ResourceClaimTemplate - object in the same namespace as this pod. + resourceClaimName: + description: |- + ResourceClaimName is the name of a ResourceClaim object in the same + namespace as this pod. + Exactly one of ResourceClaimName and ResourceClaimTemplateName must + be set. + type: string + resourceClaimTemplateName: + description: |- + ResourceClaimTemplateName is the name of a ResourceClaimTemplate + object in the same namespace as this pod. - The template will be used to create a new ResourceClaim, which will - be bound to this pod. When this pod is deleted, the ResourceClaim - will also be deleted. The pod name and resource name, along with a - generated component, will be used to form a unique name for the - ResourceClaim, which will be recorded in pod.status.resourceClaimStatuses. + The template will be used to create a new ResourceClaim, which will + be bound to this pod. When this pod is deleted, the ResourceClaim + will also be deleted. The pod name and resource name, along with a + generated component, will be used to form a unique name for the + ResourceClaim, which will be recorded in pod.status.resourceClaimStatuses. + This field is immutable and no changes will be made to the + corresponding ResourceClaim by the control plane after creating the + ResourceClaim. - This field is immutable and no changes will be made to the - corresponding ResourceClaim by the control plane after creating the - ResourceClaim. - type: string - type: object + Exactly one of ResourceClaimName and ResourceClaimTemplateName must + be set. + type: string required: - name type: object @@ -6923,7 +6862,6 @@ spec: If schedulingGates is not empty, the pod will stay in the SchedulingGated state and the scheduler will not attempt to schedule the pod. - SchedulingGates can only be set at pod creation time, and be removed only afterwards. items: description: PodSchedulingGate is associated to @@ -6975,12 +6913,10 @@ spec: Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: - 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- - If unset, the Kubelet will not modify the ownership and permissions of any volume. Note that this field cannot be set when spec.os.name is windows. format: int64 @@ -7067,7 +7003,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -7077,18 +7012,28 @@ spec: type: object supplementalGroups: description: |- - A list of groups applied to the first process run in each container, in addition - to the container's primary GID, the fsGroup (if specified), and group memberships - defined in the container image for the uid of the container process. If unspecified, - no additional groups are added to any container. Note that group memberships - defined in the container image for the uid of the container process are still effective, - even if they are not included in this list. + A list of groups applied to the first process run in each container, in + addition to the container's primary GID and fsGroup (if specified). If + the SupplementalGroupsPolicy feature is enabled, the + supplementalGroupsPolicy field determines whether these are in addition + to or instead of any group memberships defined in the container image. + If unspecified, no additional groups are added, though group memberships + defined in the container image may still be used, depending on the + supplementalGroupsPolicy field. Note that this field cannot be set when spec.os.name is windows. items: format: int64 type: integer type: array x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + description: |- + Defines how supplemental groups of the first container processes are calculated. + Valid values are "Merge" and "Strict". If not specified, "Merge" is used. + (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled + and the container runtime must implement support for this feature. + Note that this field cannot be set when spec.os.name is windows. + type: string sysctls: description: |- Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported @@ -7296,7 +7241,6 @@ spec: Keys that don't exist in the incoming pod labels will be ignored. A null or empty list means only match against labelSelector. - This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). items: type: string @@ -7336,7 +7280,6 @@ spec: Valid values are integers greater than 0. When value is not nil, WhenUnsatisfiable must be DoNotSchedule. - For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same labelSelector spread as 2/2/2: | zone1 | zone2 | zone3 | @@ -7354,7 +7297,6 @@ spec: - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. - If this value is nil, the behavior is equivalent to the Honor policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -7366,7 +7308,6 @@ spec: has a toleration, are included. - Ignore: node taints are ignored. All nodes are included. - If this value is nil, the behavior is equivalent to the Ignore policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -7435,7 +7376,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - TODO: how do we prevent errors in the filesystem from compromising the machine type: string partition: description: |- @@ -7476,6 +7416,7 @@ spec: disk in the blob storage type: string fsType: + default: ext4 description: |- fsType is Filesystem type to mount. Must be a filesystem type supported by the host operating system. @@ -7489,6 +7430,7 @@ spec: availability set). defaults to shared' type: string readOnly: + default: false description: |- readOnly Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. @@ -7560,9 +7502,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -7604,9 +7544,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -7679,9 +7617,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional specify whether the @@ -7720,9 +7656,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -7870,7 +7804,6 @@ spec: The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted when the pod is removed. - Use this if: a) the volume is only needed while the pod runs, b) features of normal volumes like restoring from snapshot or capacity @@ -7881,17 +7814,14 @@ spec: information on the connection between this volume type and PersistentVolumeClaim). - Use PersistentVolumeClaim or one of the vendor-specific APIs for volumes that persist for longer than the lifecycle of an individual pod. - Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to be used that way - see the documentation of the driver for more information. - A pod can use both types of ephemeral volumes and persistent volumes at the same time. properties: @@ -7905,7 +7835,6 @@ spec: entry. Pod validation will reject the pod if the concatenated name is not valid for a PVC (for example, too long). - An existing PVC with that name that is not owned by the pod will *not* be used for the pod to avoid using an unrelated volume by mistake. Starting the pod is then blocked until @@ -7915,11 +7844,9 @@ spec: this should not be necessary, but it may be useful when manually reconstructing a broken cluster. - This field is read-only and no changes will be made by Kubernetes to the PVC after it has been created. - Required, must not be nil. properties: metadata: @@ -8125,7 +8052,7 @@ spec: set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource exists. More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Alpha) Using this field requires the VolumeAttributesClass feature gate to be enabled. + (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). type: string volumeMode: description: |- @@ -8152,7 +8079,6 @@ spec: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - TODO: how do we prevent errors in the filesystem from compromising the machine type: string lun: description: 'lun is Optional: FC target @@ -8221,9 +8147,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -8259,7 +8183,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - TODO: how do we prevent errors in the filesystem from compromising the machine type: string partition: description: |- @@ -8340,9 +8263,6 @@ spec: used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - --- - TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not - mount host directories as read/write. properties: path: description: |- @@ -8359,6 +8279,41 @@ spec: required: - path type: object + image: + description: |- + image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine. + The volume is resolved at pod startup depending on which PullPolicy value is provided: + + - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + + The volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation. + A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message. + The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field. + The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images. + The volume will be mounted read-only (ro) and non-executable files (noexec). + Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath). + The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. + properties: + pullPolicy: + description: |- + Policy for pulling OCI objects. Possible values are: + Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + type: string + reference: + description: |- + Required: Image or artifact reference to be used. + Behaves in the same way as pod.spec.containers[*].image. + Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets. + More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management to default or override + container images in workload controllers like Deployments and StatefulSets. + type: string + type: object iscsi: description: |- iscsi represents an ISCSI Disk resource that is attached to a @@ -8379,7 +8334,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi - TODO: how do we prevent errors in the filesystem from compromising the machine type: string initiatorName: description: |- @@ -8392,6 +8346,7 @@ spec: Name. type: string iscsiInterface: + default: default description: |- iscsiInterface is the interface Name that uses an iSCSI transport. Defaults to 'default' (tcp). @@ -8425,9 +8380,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -8548,25 +8501,24 @@ spec: format: int32 type: integer sources: - description: sources is the list of volume - projections + description: |- + sources is the list of volume projections. Each entry in this list + handles one source. items: - description: Projection that may be projected - along with other supported volume types + description: |- + Projection that may be projected along with other supported volume types. + Exactly one of these fields must be set. properties: clusterTrustBundle: description: |- ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field of ClusterTrustBundle objects in an auto-updating file. - Alpha, gated by the ClusterTrustBundleProjection feature gate. - ClusterTrustBundle objects can either be selected by name, or by the combination of signer name and a label selector. - Kubelet performs aggressive normalization of the PEM contents written into the pod filesystem. Esoteric PEM features such as inter-block comments and block headers are stripped. Certificates are deduplicated. @@ -8705,9 +8657,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional specify @@ -8861,9 +8811,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional field specify @@ -8955,7 +8903,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd - TODO: how do we prevent errors in the filesystem from compromising the machine type: string image: description: |- @@ -8963,6 +8910,7 @@ spec: More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it type: string keyring: + default: /etc/ceph/keyring description: |- keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. @@ -8977,6 +8925,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd description: |- pool is the rados pool name. Default is rbd. @@ -9002,13 +8951,12 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic user: + default: admin description: |- user is the rados user name. Default is admin. @@ -9024,6 +8972,7 @@ spec: nodes. properties: fsType: + default: xfs description: |- fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. @@ -9056,9 +9005,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -9068,6 +9015,7 @@ spec: false type: boolean storageMode: + default: ThinProvisioned description: |- storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. Default is ThinProvisioned. @@ -9184,9 +9132,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -9629,7 +9575,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -9644,7 +9590,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -9816,7 +9762,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -9831,7 +9777,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -10003,7 +9949,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -10018,7 +9964,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -10190,7 +10136,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -10205,7 +10151,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -10375,9 +10321,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether @@ -10450,9 +10394,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether @@ -10494,9 +10436,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the @@ -10519,9 +10459,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the @@ -10826,11 +10764,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -11048,11 +10986,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -11207,11 +11145,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references @@ -11223,6 +11159,12 @@ spec: the Pod where this field is used. It makes that resource available inside a container. type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string required: - name type: object @@ -11346,7 +11288,7 @@ spec: procMount: description: |- procMount denotes the type of proc mount to use for the containers. - The default is DefaultProcMount which uses the container runtime defaults for + The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. @@ -11428,7 +11370,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -11513,11 +11454,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -11740,10 +11681,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -11751,11 +11690,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -11864,7 +11801,6 @@ spec: removed or restarted. The kubelet may evict a Pod if an ephemeral container causes the Pod to exceed its resource allocation. - To add an ephemeral container, use the ephemeralcontainers subresource of an existing Pod. Ephemeral containers may not be removed or restarted. properties: @@ -11939,9 +11875,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether @@ -12014,9 +11948,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether @@ -12058,9 +11990,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the @@ -12083,9 +12013,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the @@ -12384,11 +12312,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -12596,11 +12524,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -12754,11 +12682,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references @@ -12770,6 +12696,12 @@ spec: the Pod where this field is used. It makes that resource available inside a container. type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string required: - name type: object @@ -12881,7 +12813,7 @@ spec: procMount: description: |- procMount denotes the type of proc mount to use for the containers. - The default is DefaultProcMount which uses the container runtime defaults for + The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. @@ -12963,7 +12895,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -13042,11 +12973,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -13189,7 +13120,6 @@ spec: The ephemeral container will be run in the namespaces (IPC, PID, etc) of this container. If not set then the ephemeral container uses the namespaces configured in the Pod spec. - The container runtime must implement support for this feature. If the runtime does not support namespace targeting then the result of setting this field is undefined. type: string @@ -13279,10 +13209,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -13290,11 +13218,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -13406,9 +13332,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -13506,9 +13430,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether @@ -13581,9 +13503,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether @@ -13625,9 +13545,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the @@ -13650,9 +13568,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the @@ -13957,11 +13873,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -14179,11 +14095,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -14338,11 +14254,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references @@ -14354,6 +14268,12 @@ spec: the Pod where this field is used. It makes that resource available inside a container. type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string required: - name type: object @@ -14477,7 +14397,7 @@ spec: procMount: description: |- procMount denotes the type of proc mount to use for the containers. - The default is DefaultProcMount which uses the container runtime defaults for + The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. @@ -14559,7 +14479,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -14644,11 +14563,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -14871,10 +14790,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -14882,11 +14799,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -14925,9 +14840,11 @@ spec: x-kubernetes-list-type: map nodeName: description: |- - NodeName is a request to schedule this pod onto a specific node. If it is non-empty, - the scheduler simply schedules this pod onto that node, assuming that it fits resource - requirements. + NodeName indicates in which node this pod is scheduled. + If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. + Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. + This field should not be used to express a desire for the pod to be scheduled on a specific node. + https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename type: string nodeSelector: additionalProperties: @@ -14943,11 +14860,9 @@ spec: Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set. - If the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions - If the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC @@ -14962,6 +14877,7 @@ spec: - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups + - spec.securityContext.supplementalGroupsPolicy - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile @@ -15050,15 +14966,16 @@ spec: will be made available to those containers which consume them by name. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. items: description: |- - PodResourceClaim references exactly one ResourceClaim through a ClaimSource. + PodResourceClaim references exactly one ResourceClaim, either directly + or by naming a ResourceClaimTemplate which is then turned into a ResourceClaim + for the pod. + It adds a name to it that uniquely identifies the ResourceClaim inside the Pod. Containers that need access to the ResourceClaim reference it with this name. properties: @@ -15067,33 +14984,32 @@ spec: Name uniquely identifies this resource claim inside the pod. This must be a DNS_LABEL. type: string - source: - description: Source describes where to find - the ResourceClaim. - properties: - resourceClaimName: - description: |- - ResourceClaimName is the name of a ResourceClaim object in the same - namespace as this pod. - type: string - resourceClaimTemplateName: - description: |- - ResourceClaimTemplateName is the name of a ResourceClaimTemplate - object in the same namespace as this pod. + resourceClaimName: + description: |- + ResourceClaimName is the name of a ResourceClaim object in the same + namespace as this pod. + Exactly one of ResourceClaimName and ResourceClaimTemplateName must + be set. + type: string + resourceClaimTemplateName: + description: |- + ResourceClaimTemplateName is the name of a ResourceClaimTemplate + object in the same namespace as this pod. - The template will be used to create a new ResourceClaim, which will - be bound to this pod. When this pod is deleted, the ResourceClaim - will also be deleted. The pod name and resource name, along with a - generated component, will be used to form a unique name for the - ResourceClaim, which will be recorded in pod.status.resourceClaimStatuses. + The template will be used to create a new ResourceClaim, which will + be bound to this pod. When this pod is deleted, the ResourceClaim + will also be deleted. The pod name and resource name, along with a + generated component, will be used to form a unique name for the + ResourceClaim, which will be recorded in pod.status.resourceClaimStatuses. + This field is immutable and no changes will be made to the + corresponding ResourceClaim by the control plane after creating the + ResourceClaim. - This field is immutable and no changes will be made to the - corresponding ResourceClaim by the control plane after creating the - ResourceClaim. - type: string - type: object + Exactly one of ResourceClaimName and ResourceClaimTemplateName must + be set. + type: string required: - name type: object @@ -15127,7 +15043,6 @@ spec: If schedulingGates is not empty, the pod will stay in the SchedulingGated state and the scheduler will not attempt to schedule the pod. - SchedulingGates can only be set at pod creation time, and be removed only afterwards. items: description: PodSchedulingGate is associated to @@ -15179,12 +15094,10 @@ spec: Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: - 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- - If unset, the Kubelet will not modify the ownership and permissions of any volume. Note that this field cannot be set when spec.os.name is windows. format: int64 @@ -15271,7 +15184,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -15281,18 +15193,28 @@ spec: type: object supplementalGroups: description: |- - A list of groups applied to the first process run in each container, in addition - to the container's primary GID, the fsGroup (if specified), and group memberships - defined in the container image for the uid of the container process. If unspecified, - no additional groups are added to any container. Note that group memberships - defined in the container image for the uid of the container process are still effective, - even if they are not included in this list. + A list of groups applied to the first process run in each container, in + addition to the container's primary GID and fsGroup (if specified). If + the SupplementalGroupsPolicy feature is enabled, the + supplementalGroupsPolicy field determines whether these are in addition + to or instead of any group memberships defined in the container image. + If unspecified, no additional groups are added, though group memberships + defined in the container image may still be used, depending on the + supplementalGroupsPolicy field. Note that this field cannot be set when spec.os.name is windows. items: format: int64 type: integer type: array x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + description: |- + Defines how supplemental groups of the first container processes are calculated. + Valid values are "Merge" and "Strict". If not specified, "Merge" is used. + (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled + and the container runtime must implement support for this feature. + Note that this field cannot be set when spec.os.name is windows. + type: string sysctls: description: |- Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported @@ -15501,7 +15423,6 @@ spec: Keys that don't exist in the incoming pod labels will be ignored. A null or empty list means only match against labelSelector. - This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). items: type: string @@ -15541,7 +15462,6 @@ spec: Valid values are integers greater than 0. When value is not nil, WhenUnsatisfiable must be DoNotSchedule. - For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same labelSelector spread as 2/2/2: | zone1 | zone2 | zone3 | @@ -15559,7 +15479,6 @@ spec: - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. - If this value is nil, the behavior is equivalent to the Honor policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -15571,7 +15490,6 @@ spec: has a toleration, are included. - Ignore: node taints are ignored. All nodes are included. - If this value is nil, the behavior is equivalent to the Ignore policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -15640,7 +15558,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - TODO: how do we prevent errors in the filesystem from compromising the machine type: string partition: description: |- @@ -15682,6 +15599,7 @@ spec: disk in the blob storage type: string fsType: + default: ext4 description: |- fsType is Filesystem type to mount. Must be a filesystem type supported by the host operating system. @@ -15696,6 +15614,7 @@ spec: set). defaults to shared' type: string readOnly: + default: false description: |- readOnly Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. @@ -15767,9 +15686,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -15811,9 +15728,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -15886,9 +15801,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional specify whether @@ -15927,9 +15840,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -16077,7 +15988,6 @@ spec: The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted when the pod is removed. - Use this if: a) the volume is only needed while the pod runs, b) features of normal volumes like restoring from snapshot or capacity @@ -16088,17 +15998,14 @@ spec: information on the connection between this volume type and PersistentVolumeClaim). - Use PersistentVolumeClaim or one of the vendor-specific APIs for volumes that persist for longer than the lifecycle of an individual pod. - Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to be used that way - see the documentation of the driver for more information. - A pod can use both types of ephemeral volumes and persistent volumes at the same time. properties: @@ -16112,7 +16019,6 @@ spec: entry. Pod validation will reject the pod if the concatenated name is not valid for a PVC (for example, too long). - An existing PVC with that name that is not owned by the pod will *not* be used for the pod to avoid using an unrelated volume by mistake. Starting the pod is then blocked until @@ -16122,11 +16028,9 @@ spec: this should not be necessary, but it may be useful when manually reconstructing a broken cluster. - This field is read-only and no changes will be made by Kubernetes to the PVC after it has been created. - Required, must not be nil. properties: metadata: @@ -16333,7 +16237,7 @@ spec: set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource exists. More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Alpha) Using this field requires the VolumeAttributesClass feature gate to be enabled. + (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). type: string volumeMode: description: |- @@ -16360,7 +16264,6 @@ spec: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - TODO: how do we prevent errors in the filesystem from compromising the machine type: string lun: description: 'lun is Optional: FC target @@ -16430,9 +16333,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -16468,7 +16369,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - TODO: how do we prevent errors in the filesystem from compromising the machine type: string partition: description: |- @@ -16549,9 +16449,6 @@ spec: used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - --- - TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not - mount host directories as read/write. properties: path: description: |- @@ -16568,6 +16465,41 @@ spec: required: - path type: object + image: + description: |- + image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine. + The volume is resolved at pod startup depending on which PullPolicy value is provided: + + - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + + The volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation. + A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message. + The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field. + The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images. + The volume will be mounted read-only (ro) and non-executable files (noexec). + Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath). + The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. + properties: + pullPolicy: + description: |- + Policy for pulling OCI objects. Possible values are: + Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + type: string + reference: + description: |- + Required: Image or artifact reference to be used. + Behaves in the same way as pod.spec.containers[*].image. + Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets. + More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management to default or override + container images in workload controllers like Deployments and StatefulSets. + type: string + type: object iscsi: description: |- iscsi represents an ISCSI Disk resource that is attached to a @@ -16589,7 +16521,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi - TODO: how do we prevent errors in the filesystem from compromising the machine type: string initiatorName: description: |- @@ -16602,6 +16533,7 @@ spec: Name. type: string iscsiInterface: + default: default description: |- iscsiInterface is the interface Name that uses an iSCSI transport. Defaults to 'default' (tcp). @@ -16635,9 +16567,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -16758,26 +16688,24 @@ spec: format: int32 type: integer sources: - description: sources is the list of volume - projections + description: |- + sources is the list of volume projections. Each entry in this list + handles one source. items: - description: Projection that may be - projected along with other supported - volume types + description: |- + Projection that may be projected along with other supported volume types. + Exactly one of these fields must be set. properties: clusterTrustBundle: description: |- ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field of ClusterTrustBundle objects in an auto-updating file. - Alpha, gated by the ClusterTrustBundleProjection feature gate. - ClusterTrustBundle objects can either be selected by name, or by the combination of signer name and a label selector. - Kubelet performs aggressive normalization of the PEM contents written into the pod filesystem. Esoteric PEM features such as inter-block comments and block headers are stripped. Certificates are deduplicated. @@ -16916,9 +16844,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional specify @@ -17073,9 +16999,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional field @@ -17168,7 +17092,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd - TODO: how do we prevent errors in the filesystem from compromising the machine type: string image: description: |- @@ -17176,6 +17099,7 @@ spec: More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it type: string keyring: + default: /etc/ceph/keyring description: |- keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. @@ -17190,6 +17114,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd description: |- pool is the rados pool name. Default is rbd. @@ -17215,13 +17140,12 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic user: + default: admin description: |- user is the rados user name. Default is admin. @@ -17237,6 +17161,7 @@ spec: Kubernetes nodes. properties: fsType: + default: xfs description: |- fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. @@ -17269,9 +17194,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -17281,6 +17204,7 @@ spec: false type: boolean storageMode: + default: ThinProvisioned description: |- storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. Default is ThinProvisioned. @@ -17397,9 +17321,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -17471,6 +17393,8 @@ spec: required: - spec type: object + required: + - template type: object served: true storage: true diff --git a/cmd/experimental/kjobctl/config/crd/bases/kjobctl.x-k8s.io_rayjobtemplates.yaml b/cmd/experimental/kjobctl/config/crd/bases/kjobctl.x-k8s.io_rayjobtemplates.yaml index ec22f7cc36..3e3001b710 100644 --- a/cmd/experimental/kjobctl/config/crd/bases/kjobctl.x-k8s.io_rayjobtemplates.yaml +++ b/cmd/experimental/kjobctl/config/crd/bases/kjobctl.x-k8s.io_rayjobtemplates.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.16.2 name: rayjobtemplates.kjobctl.x-k8s.io spec: group: kjobctl.x-k8s.io @@ -139,9 +139,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap @@ -208,9 +206,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret @@ -242,9 +238,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap must @@ -266,9 +260,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret must @@ -304,11 +296,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry @@ -320,6 +310,12 @@ spec: the Pod where this field is used. It makes that resource available inside a container. type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string required: - name type: object @@ -425,7 +421,7 @@ spec: procMount: description: |- procMount denotes the type of proc mount to use for the containers. - The default is DefaultProcMount which uses the container runtime defaults for + The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. @@ -507,7 +503,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -594,10 +589,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -605,11 +598,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -722,7 +713,6 @@ spec: clients must ensure that clusterIPs[0] and clusterIP have the same value. - This field may hold a maximum of two entries (dual-stack IPs, in either order). These IPs must correspond to the values of the ipFamilies field. Both clusterIPs and ipFamilies are governed by the ipFamilyPolicy field. @@ -802,7 +792,6 @@ spec: NodePort, and LoadBalancer, and does apply to "headless" services. This field will be wiped when updating a Service to type ExternalName. - This field may hold a maximum of two entries (dual-stack families, in either order). These families must correspond to the values of the clusterIPs field, if specified. Both clusterIPs and ipFamilies are @@ -873,17 +862,14 @@ spec: This field follows standard Kubernetes label syntax. Valid values are either: - * Un-prefixed protocol names - reserved for IANA standard service names (as per RFC-6335 and https://www.iana.org/assignments/service-names). - * Kubernetes-defined prefixed names: * 'kubernetes.io/h2c' - HTTP/2 prior knowledge over cleartext as described in https://www.rfc-editor.org/rfc/rfc9113.html#name-starting-http-2-with-prior- * 'kubernetes.io/ws' - WebSocket over cleartext as described in https://www.rfc-editor.org/rfc/rfc6455 * 'kubernetes.io/wss' - WebSocket over TLS as described in https://www.rfc-editor.org/rfc/rfc6455 - * Other protocols should use implementation-defined prefixed names such as mycompany.com/my-custom-protocol. type: string @@ -1029,20 +1015,9 @@ spec: conditions: description: Current service state items: - description: "Condition contains details for + 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}" + Resource. properties: lastTransitionTime: description: |- @@ -1084,12 +1059,8 @@ spec: - 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) + description: type of condition in CamelCase + or in foo.example.com/CamelCase. 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 @@ -1151,8 +1122,6 @@ spec: CamelCase names - cloud provider specific error values must have names that comply with the format foo.example.com/CamelCase. - --- - 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 @@ -1163,12 +1132,12 @@ spec: format: int32 type: integer protocol: - default: TCP description: |- Protocol is the protocol of the service port of which status is recorded here The supported values are: "TCP", "UDP", "SCTP" type: string required: + - error - port - protocol type: object @@ -1514,7 +1483,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1529,7 +1498,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1701,7 +1670,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1716,7 +1685,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1888,7 +1857,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -1903,7 +1872,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -2075,7 +2044,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -2090,7 +2059,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -2260,9 +2229,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether @@ -2336,9 +2303,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether @@ -2380,9 +2345,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the @@ -2406,9 +2369,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the @@ -2713,11 +2674,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -2935,11 +2896,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -3094,11 +3055,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references @@ -3110,6 +3069,12 @@ spec: the Pod where this field is used. It makes that resource available inside a container. type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string required: - name type: object @@ -3233,7 +3198,7 @@ spec: procMount: description: |- procMount denotes the type of proc mount to use for the containers. - The default is DefaultProcMount which uses the container runtime defaults for + The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. @@ -3315,7 +3280,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -3400,11 +3364,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -3628,10 +3592,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -3639,11 +3601,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -3752,7 +3712,6 @@ spec: removed or restarted. The kubelet may evict a Pod if an ephemeral container causes the Pod to exceed its resource allocation. - To add an ephemeral container, use the ephemeralcontainers subresource of an existing Pod. Ephemeral containers may not be removed or restarted. properties: @@ -3827,9 +3786,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether @@ -3903,9 +3860,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether @@ -3947,9 +3902,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the @@ -3973,9 +3926,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the @@ -4274,11 +4225,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -4486,11 +4437,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -4644,11 +4595,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references @@ -4660,6 +4609,12 @@ spec: the Pod where this field is used. It makes that resource available inside a container. type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string required: - name type: object @@ -4771,7 +4726,7 @@ spec: procMount: description: |- procMount denotes the type of proc mount to use for the containers. - The default is DefaultProcMount which uses the container runtime defaults for + The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. @@ -4853,7 +4808,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -4932,11 +4886,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -5079,7 +5033,6 @@ spec: The ephemeral container will be run in the namespaces (IPC, PID, etc) of this container. If not set then the ephemeral container uses the namespaces configured in the Pod spec. - The container runtime must implement support for this feature. If the runtime does not support namespace targeting then the result of setting this field is undefined. type: string @@ -5170,10 +5123,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -5181,11 +5132,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -5299,9 +5248,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -5399,9 +5346,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether @@ -5475,9 +5420,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether @@ -5519,9 +5462,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the @@ -5545,9 +5486,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the @@ -5852,11 +5791,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -6074,11 +6013,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -6233,11 +6172,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references @@ -6249,6 +6186,12 @@ spec: the Pod where this field is used. It makes that resource available inside a container. type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string required: - name type: object @@ -6372,7 +6315,7 @@ spec: procMount: description: |- procMount denotes the type of proc mount to use for the containers. - The default is DefaultProcMount which uses the container runtime defaults for + The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. @@ -6454,7 +6397,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -6539,11 +6481,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -6767,10 +6709,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -6778,11 +6718,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -6821,9 +6759,11 @@ spec: x-kubernetes-list-type: map nodeName: description: |- - NodeName is a request to schedule this pod onto a specific node. If it is non-empty, - the scheduler simply schedules this pod onto that node, assuming that it fits resource - requirements. + NodeName indicates in which node this pod is scheduled. + If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. + Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. + This field should not be used to express a desire for the pod to be scheduled on a specific node. + https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename type: string nodeSelector: additionalProperties: @@ -6839,11 +6779,9 @@ spec: Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set. - If the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions - If the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC @@ -6858,6 +6796,7 @@ spec: - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups + - spec.securityContext.supplementalGroupsPolicy - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile @@ -6946,15 +6885,16 @@ spec: will be made available to those containers which consume them by name. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. items: description: |- - PodResourceClaim references exactly one ResourceClaim through a ClaimSource. + PodResourceClaim references exactly one ResourceClaim, either directly + or by naming a ResourceClaimTemplate which is then turned into a ResourceClaim + for the pod. + It adds a name to it that uniquely identifies the ResourceClaim inside the Pod. Containers that need access to the ResourceClaim reference it with this name. properties: @@ -6963,33 +6903,32 @@ spec: Name uniquely identifies this resource claim inside the pod. This must be a DNS_LABEL. type: string - source: - description: Source describes where to find - the ResourceClaim. - properties: - resourceClaimName: - description: |- - ResourceClaimName is the name of a ResourceClaim object in the same - namespace as this pod. - type: string - resourceClaimTemplateName: - description: |- - ResourceClaimTemplateName is the name of a ResourceClaimTemplate - object in the same namespace as this pod. + resourceClaimName: + description: |- + ResourceClaimName is the name of a ResourceClaim object in the same + namespace as this pod. + Exactly one of ResourceClaimName and ResourceClaimTemplateName must + be set. + type: string + resourceClaimTemplateName: + description: |- + ResourceClaimTemplateName is the name of a ResourceClaimTemplate + object in the same namespace as this pod. - The template will be used to create a new ResourceClaim, which will - be bound to this pod. When this pod is deleted, the ResourceClaim - will also be deleted. The pod name and resource name, along with a - generated component, will be used to form a unique name for the - ResourceClaim, which will be recorded in pod.status.resourceClaimStatuses. + The template will be used to create a new ResourceClaim, which will + be bound to this pod. When this pod is deleted, the ResourceClaim + will also be deleted. The pod name and resource name, along with a + generated component, will be used to form a unique name for the + ResourceClaim, which will be recorded in pod.status.resourceClaimStatuses. + This field is immutable and no changes will be made to the + corresponding ResourceClaim by the control plane after creating the + ResourceClaim. - This field is immutable and no changes will be made to the - corresponding ResourceClaim by the control plane after creating the - ResourceClaim. - type: string - type: object + Exactly one of ResourceClaimName and ResourceClaimTemplateName must + be set. + type: string required: - name type: object @@ -7023,7 +6962,6 @@ spec: If schedulingGates is not empty, the pod will stay in the SchedulingGated state and the scheduler will not attempt to schedule the pod. - SchedulingGates can only be set at pod creation time, and be removed only afterwards. items: description: PodSchedulingGate is associated @@ -7075,12 +7013,10 @@ spec: Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: - 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- - If unset, the Kubelet will not modify the ownership and permissions of any volume. Note that this field cannot be set when spec.os.name is windows. format: int64 @@ -7167,7 +7103,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -7177,18 +7112,28 @@ spec: type: object supplementalGroups: description: |- - A list of groups applied to the first process run in each container, in addition - to the container's primary GID, the fsGroup (if specified), and group memberships - defined in the container image for the uid of the container process. If unspecified, - no additional groups are added to any container. Note that group memberships - defined in the container image for the uid of the container process are still effective, - even if they are not included in this list. + A list of groups applied to the first process run in each container, in + addition to the container's primary GID and fsGroup (if specified). If + the SupplementalGroupsPolicy feature is enabled, the + supplementalGroupsPolicy field determines whether these are in addition + to or instead of any group memberships defined in the container image. + If unspecified, no additional groups are added, though group memberships + defined in the container image may still be used, depending on the + supplementalGroupsPolicy field. Note that this field cannot be set when spec.os.name is windows. items: format: int64 type: integer type: array x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + description: |- + Defines how supplemental groups of the first container processes are calculated. + Valid values are "Merge" and "Strict". If not specified, "Merge" is used. + (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled + and the container runtime must implement support for this feature. + Note that this field cannot be set when spec.os.name is windows. + type: string sysctls: description: |- Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported @@ -7400,7 +7345,6 @@ spec: Keys that don't exist in the incoming pod labels will be ignored. A null or empty list means only match against labelSelector. - This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). items: type: string @@ -7440,7 +7384,6 @@ spec: Valid values are integers greater than 0. When value is not nil, WhenUnsatisfiable must be DoNotSchedule. - For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same labelSelector spread as 2/2/2: | zone1 | zone2 | zone3 | @@ -7458,7 +7401,6 @@ spec: - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. - If this value is nil, the behavior is equivalent to the Honor policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -7470,7 +7412,6 @@ spec: has a toleration, are included. - Ignore: node taints are ignored. All nodes are included. - If this value is nil, the behavior is equivalent to the Ignore policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -7539,7 +7480,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - TODO: how do we prevent errors in the filesystem from compromising the machine type: string partition: description: |- @@ -7581,6 +7521,7 @@ spec: disk in the blob storage type: string fsType: + default: ext4 description: |- fsType is Filesystem type to mount. Must be a filesystem type supported by the host operating system. @@ -7595,6 +7536,7 @@ spec: availability set). defaults to shared' type: string readOnly: + default: false description: |- readOnly Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. @@ -7667,9 +7609,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -7711,9 +7651,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -7787,9 +7725,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional specify whether @@ -7830,9 +7766,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -7981,7 +7915,6 @@ spec: The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted when the pod is removed. - Use this if: a) the volume is only needed while the pod runs, b) features of normal volumes like restoring from snapshot or capacity @@ -7992,17 +7925,14 @@ spec: information on the connection between this volume type and PersistentVolumeClaim). - Use PersistentVolumeClaim or one of the vendor-specific APIs for volumes that persist for longer than the lifecycle of an individual pod. - Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to be used that way - see the documentation of the driver for more information. - A pod can use both types of ephemeral volumes and persistent volumes at the same time. properties: @@ -8016,7 +7946,6 @@ spec: entry. Pod validation will reject the pod if the concatenated name is not valid for a PVC (for example, too long). - An existing PVC with that name that is not owned by the pod will *not* be used for the pod to avoid using an unrelated volume by mistake. Starting the pod is then blocked until @@ -8026,11 +7955,9 @@ spec: this should not be necessary, but it may be useful when manually reconstructing a broken cluster. - This field is read-only and no changes will be made by Kubernetes to the PVC after it has been created. - Required, must not be nil. properties: metadata: @@ -8241,7 +8168,7 @@ spec: set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource exists. More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Alpha) Using this field requires the VolumeAttributesClass feature gate to be enabled. + (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). type: string volumeMode: description: |- @@ -8268,7 +8195,6 @@ spec: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - TODO: how do we prevent errors in the filesystem from compromising the machine type: string lun: description: 'lun is Optional: FC target @@ -8338,9 +8264,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -8376,7 +8300,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - TODO: how do we prevent errors in the filesystem from compromising the machine type: string partition: description: |- @@ -8457,9 +8380,6 @@ spec: used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - --- - TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not - mount host directories as read/write. properties: path: description: |- @@ -8476,6 +8396,41 @@ spec: required: - path type: object + image: + description: |- + image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine. + The volume is resolved at pod startup depending on which PullPolicy value is provided: + + - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + + The volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation. + A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message. + The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field. + The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images. + The volume will be mounted read-only (ro) and non-executable files (noexec). + Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath). + The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. + properties: + pullPolicy: + description: |- + Policy for pulling OCI objects. Possible values are: + Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + type: string + reference: + description: |- + Required: Image or artifact reference to be used. + Behaves in the same way as pod.spec.containers[*].image. + Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets. + More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management to default or override + container images in workload controllers like Deployments and StatefulSets. + type: string + type: object iscsi: description: |- iscsi represents an ISCSI Disk resource that is attached to a @@ -8498,7 +8453,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi - TODO: how do we prevent errors in the filesystem from compromising the machine type: string initiatorName: description: |- @@ -8511,6 +8465,7 @@ spec: Qualified Name. type: string iscsiInterface: + default: default description: |- iscsiInterface is the interface Name that uses an iSCSI transport. Defaults to 'default' (tcp). @@ -8544,9 +8499,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -8667,26 +8620,24 @@ spec: format: int32 type: integer sources: - description: sources is the list of - volume projections + description: |- + sources is the list of volume projections. Each entry in this list + handles one source. items: - description: Projection that may be - projected along with other supported - volume types + description: |- + Projection that may be projected along with other supported volume types. + Exactly one of these fields must be set. properties: clusterTrustBundle: description: |- ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field of ClusterTrustBundle objects in an auto-updating file. - Alpha, gated by the ClusterTrustBundleProjection feature gate. - ClusterTrustBundle objects can either be selected by name, or by the combination of signer name and a label selector. - Kubelet performs aggressive normalization of the PEM contents written into the pod filesystem. Esoteric PEM features such as inter-block comments and block headers are stripped. Certificates are deduplicated. @@ -8827,9 +8778,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional specify @@ -8989,9 +8938,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional field @@ -9085,7 +9032,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd - TODO: how do we prevent errors in the filesystem from compromising the machine type: string image: description: |- @@ -9093,6 +9039,7 @@ spec: More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it type: string keyring: + default: /etc/ceph/keyring description: |- keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. @@ -9107,6 +9054,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd description: |- pool is the rados pool name. Default is rbd. @@ -9132,13 +9080,12 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic user: + default: admin description: |- user is the rados user name. Default is admin. @@ -9154,6 +9101,7 @@ spec: on Kubernetes nodes. properties: fsType: + default: xfs description: |- fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. @@ -9186,9 +9134,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -9198,6 +9144,7 @@ spec: false type: boolean storageMode: + default: ThinProvisioned description: |- storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. Default is ThinProvisioned. @@ -9316,9 +9263,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -9770,7 +9715,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -9785,7 +9730,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -9958,7 +9903,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -9973,7 +9918,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -10147,7 +10092,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -10162,7 +10107,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -10335,7 +10280,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -10350,7 +10295,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -10522,9 +10467,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether @@ -10599,9 +10542,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether @@ -10643,9 +10584,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether @@ -10669,9 +10608,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether @@ -10976,11 +10913,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -11198,11 +11135,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -11357,11 +11294,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references @@ -11373,6 +11308,12 @@ spec: the Pod where this field is used. It makes that resource available inside a container. type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string required: - name type: object @@ -11496,7 +11437,7 @@ spec: procMount: description: |- procMount denotes the type of proc mount to use for the containers. - The default is DefaultProcMount which uses the container runtime defaults for + The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. @@ -11582,7 +11523,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -11667,11 +11607,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -11895,10 +11835,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -11906,11 +11844,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -12019,7 +11955,6 @@ spec: removed or restarted. The kubelet may evict a Pod if an ephemeral container causes the Pod to exceed its resource allocation. - To add an ephemeral container, use the ephemeralcontainers subresource of an existing Pod. Ephemeral containers may not be removed or restarted. properties: @@ -12095,9 +12030,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether @@ -12172,9 +12105,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether @@ -12216,9 +12147,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether @@ -12242,9 +12171,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether @@ -12543,11 +12470,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -12755,11 +12682,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -12913,11 +12840,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references @@ -12929,6 +12854,12 @@ spec: the Pod where this field is used. It makes that resource available inside a container. type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string required: - name type: object @@ -13040,7 +12971,7 @@ spec: procMount: description: |- procMount denotes the type of proc mount to use for the containers. - The default is DefaultProcMount which uses the container runtime defaults for + The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. @@ -13126,7 +13057,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -13205,11 +13135,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -13352,7 +13282,6 @@ spec: The ephemeral container will be run in the namespaces (IPC, PID, etc) of this container. If not set then the ephemeral container uses the namespaces configured in the Pod spec. - The container runtime must implement support for this feature. If the runtime does not support namespace targeting then the result of setting this field is undefined. type: string @@ -13443,10 +13372,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -13454,11 +13381,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -13572,9 +13497,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -13673,9 +13596,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether @@ -13750,9 +13671,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether @@ -13794,9 +13713,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether @@ -13820,9 +13737,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether @@ -14127,11 +14042,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -14349,11 +14264,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -14508,11 +14423,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references @@ -14524,6 +14437,12 @@ spec: the Pod where this field is used. It makes that resource available inside a container. type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string required: - name type: object @@ -14647,7 +14566,7 @@ spec: procMount: description: |- procMount denotes the type of proc mount to use for the containers. - The default is DefaultProcMount which uses the container runtime defaults for + The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. @@ -14733,7 +14652,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -14818,11 +14736,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -15046,10 +14964,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -15057,11 +14973,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -15100,9 +15014,11 @@ spec: x-kubernetes-list-type: map nodeName: description: |- - NodeName is a request to schedule this pod onto a specific node. If it is non-empty, - the scheduler simply schedules this pod onto that node, assuming that it fits resource - requirements. + NodeName indicates in which node this pod is scheduled. + If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. + Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. + This field should not be used to express a desire for the pod to be scheduled on a specific node. + https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename type: string nodeSelector: additionalProperties: @@ -15118,11 +15034,9 @@ spec: Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set. - If the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions - If the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC @@ -15137,6 +15051,7 @@ spec: - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups + - spec.securityContext.supplementalGroupsPolicy - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile @@ -15225,15 +15140,16 @@ spec: will be made available to those containers which consume them by name. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. items: description: |- - PodResourceClaim references exactly one ResourceClaim through a ClaimSource. + PodResourceClaim references exactly one ResourceClaim, either directly + or by naming a ResourceClaimTemplate which is then turned into a ResourceClaim + for the pod. + It adds a name to it that uniquely identifies the ResourceClaim inside the Pod. Containers that need access to the ResourceClaim reference it with this name. properties: @@ -15242,33 +15158,32 @@ spec: Name uniquely identifies this resource claim inside the pod. This must be a DNS_LABEL. type: string - source: - description: Source describes where to - find the ResourceClaim. - properties: - resourceClaimName: - description: |- - ResourceClaimName is the name of a ResourceClaim object in the same - namespace as this pod. - type: string - resourceClaimTemplateName: - description: |- - ResourceClaimTemplateName is the name of a ResourceClaimTemplate - object in the same namespace as this pod. + resourceClaimName: + description: |- + ResourceClaimName is the name of a ResourceClaim object in the same + namespace as this pod. + Exactly one of ResourceClaimName and ResourceClaimTemplateName must + be set. + type: string + resourceClaimTemplateName: + description: |- + ResourceClaimTemplateName is the name of a ResourceClaimTemplate + object in the same namespace as this pod. - The template will be used to create a new ResourceClaim, which will - be bound to this pod. When this pod is deleted, the ResourceClaim - will also be deleted. The pod name and resource name, along with a - generated component, will be used to form a unique name for the - ResourceClaim, which will be recorded in pod.status.resourceClaimStatuses. + The template will be used to create a new ResourceClaim, which will + be bound to this pod. When this pod is deleted, the ResourceClaim + will also be deleted. The pod name and resource name, along with a + generated component, will be used to form a unique name for the + ResourceClaim, which will be recorded in pod.status.resourceClaimStatuses. + This field is immutable and no changes will be made to the + corresponding ResourceClaim by the control plane after creating the + ResourceClaim. - This field is immutable and no changes will be made to the - corresponding ResourceClaim by the control plane after creating the - ResourceClaim. - type: string - type: object + Exactly one of ResourceClaimName and ResourceClaimTemplateName must + be set. + type: string required: - name type: object @@ -15302,7 +15217,6 @@ spec: If schedulingGates is not empty, the pod will stay in the SchedulingGated state and the scheduler will not attempt to schedule the pod. - SchedulingGates can only be set at pod creation time, and be removed only afterwards. items: description: PodSchedulingGate is associated @@ -15354,12 +15268,10 @@ spec: Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: - 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- - If unset, the Kubelet will not modify the ownership and permissions of any volume. Note that this field cannot be set when spec.os.name is windows. format: int64 @@ -15446,7 +15358,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -15456,18 +15367,28 @@ spec: type: object supplementalGroups: description: |- - A list of groups applied to the first process run in each container, in addition - to the container's primary GID, the fsGroup (if specified), and group memberships - defined in the container image for the uid of the container process. If unspecified, - no additional groups are added to any container. Note that group memberships - defined in the container image for the uid of the container process are still effective, - even if they are not included in this list. + A list of groups applied to the first process run in each container, in + addition to the container's primary GID and fsGroup (if specified). If + the SupplementalGroupsPolicy feature is enabled, the + supplementalGroupsPolicy field determines whether these are in addition + to or instead of any group memberships defined in the container image. + If unspecified, no additional groups are added, though group memberships + defined in the container image may still be used, depending on the + supplementalGroupsPolicy field. Note that this field cannot be set when spec.os.name is windows. items: format: int64 type: integer type: array x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + description: |- + Defines how supplemental groups of the first container processes are calculated. + Valid values are "Merge" and "Strict". If not specified, "Merge" is used. + (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled + and the container runtime must implement support for this feature. + Note that this field cannot be set when spec.os.name is windows. + type: string sysctls: description: |- Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported @@ -15680,7 +15601,6 @@ spec: Keys that don't exist in the incoming pod labels will be ignored. A null or empty list means only match against labelSelector. - This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). items: type: string @@ -15720,7 +15640,6 @@ spec: Valid values are integers greater than 0. When value is not nil, WhenUnsatisfiable must be DoNotSchedule. - For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same labelSelector spread as 2/2/2: | zone1 | zone2 | zone3 | @@ -15738,7 +15657,6 @@ spec: - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. - If this value is nil, the behavior is equivalent to the Honor policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -15750,7 +15668,6 @@ spec: has a toleration, are included. - Ignore: node taints are ignored. All nodes are included. - If this value is nil, the behavior is equivalent to the Ignore policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -15819,7 +15736,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - TODO: how do we prevent errors in the filesystem from compromising the machine type: string partition: description: |- @@ -15861,6 +15777,7 @@ spec: data disk in the blob storage type: string fsType: + default: ext4 description: |- fsType is Filesystem type to mount. Must be a filesystem type supported by the host operating system. @@ -15876,6 +15793,7 @@ spec: to shared' type: string readOnly: + default: false description: |- readOnly Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. @@ -15948,9 +15866,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -15992,9 +15908,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -16068,9 +15982,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional specify whether @@ -16111,9 +16023,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -16264,7 +16174,6 @@ spec: The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted when the pod is removed. - Use this if: a) the volume is only needed while the pod runs, b) features of normal volumes like restoring from snapshot or capacity @@ -16275,17 +16184,14 @@ spec: information on the connection between this volume type and PersistentVolumeClaim). - Use PersistentVolumeClaim or one of the vendor-specific APIs for volumes that persist for longer than the lifecycle of an individual pod. - Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to be used that way - see the documentation of the driver for more information. - A pod can use both types of ephemeral volumes and persistent volumes at the same time. properties: @@ -16299,7 +16205,6 @@ spec: entry. Pod validation will reject the pod if the concatenated name is not valid for a PVC (for example, too long). - An existing PVC with that name that is not owned by the pod will *not* be used for the pod to avoid using an unrelated volume by mistake. Starting the pod is then blocked until @@ -16309,11 +16214,9 @@ spec: this should not be necessary, but it may be useful when manually reconstructing a broken cluster. - This field is read-only and no changes will be made by Kubernetes to the PVC after it has been created. - Required, must not be nil. properties: metadata: @@ -16524,7 +16427,7 @@ spec: set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource exists. More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Alpha) Using this field requires the VolumeAttributesClass feature gate to be enabled. + (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). type: string volumeMode: description: |- @@ -16553,7 +16456,6 @@ spec: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - TODO: how do we prevent errors in the filesystem from compromising the machine type: string lun: description: 'lun is Optional: FC @@ -16623,9 +16525,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -16661,7 +16561,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - TODO: how do we prevent errors in the filesystem from compromising the machine type: string partition: description: |- @@ -16742,9 +16641,6 @@ spec: used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - --- - TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not - mount host directories as read/write. properties: path: description: |- @@ -16761,6 +16657,41 @@ spec: required: - path type: object + image: + description: |- + image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine. + The volume is resolved at pod startup depending on which PullPolicy value is provided: + + - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + + The volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation. + A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message. + The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field. + The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images. + The volume will be mounted read-only (ro) and non-executable files (noexec). + Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath). + The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. + properties: + pullPolicy: + description: |- + Policy for pulling OCI objects. Possible values are: + Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + type: string + reference: + description: |- + Required: Image or artifact reference to be used. + Behaves in the same way as pod.spec.containers[*].image. + Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets. + More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management to default or override + container images in workload controllers like Deployments and StatefulSets. + type: string + type: object iscsi: description: |- iscsi represents an ISCSI Disk resource that is attached to a @@ -16783,7 +16714,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi - TODO: how do we prevent errors in the filesystem from compromising the machine type: string initiatorName: description: |- @@ -16796,6 +16726,7 @@ spec: Qualified Name. type: string iscsiInterface: + default: default description: |- iscsiInterface is the interface Name that uses an iSCSI transport. Defaults to 'default' (tcp). @@ -16830,9 +16761,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -16953,26 +16882,24 @@ spec: format: int32 type: integer sources: - description: sources is the list of - volume projections + description: |- + sources is the list of volume projections. Each entry in this list + handles one source. items: - description: Projection that may - be projected along with other - supported volume types + description: |- + Projection that may be projected along with other supported volume types. + Exactly one of these fields must be set. properties: clusterTrustBundle: description: |- ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field of ClusterTrustBundle objects in an auto-updating file. - Alpha, gated by the ClusterTrustBundleProjection feature gate. - ClusterTrustBundle objects can either be selected by name, or by the combination of signer name and a label selector. - Kubelet performs aggressive normalization of the PEM contents written into the pod filesystem. Esoteric PEM features such as inter-block comments and block headers are stripped. Certificates are deduplicated. @@ -17115,9 +17042,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional specify @@ -17281,9 +17206,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional field @@ -17377,7 +17300,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd - TODO: how do we prevent errors in the filesystem from compromising the machine type: string image: description: |- @@ -17385,6 +17307,7 @@ spec: More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it type: string keyring: + default: /etc/ceph/keyring description: |- keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. @@ -17399,6 +17322,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd description: |- pool is the rados pool name. Default is rbd. @@ -17424,13 +17348,12 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic user: + default: admin description: |- user is the rados user name. Default is admin. @@ -17446,6 +17369,7 @@ spec: on Kubernetes nodes. properties: fsType: + default: xfs description: |- fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. @@ -17478,9 +17402,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -17490,6 +17412,7 @@ spec: default false type: boolean storageMode: + default: ThinProvisioned description: |- storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. Default is ThinProvisioned. @@ -17609,9 +17532,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -18014,7 +17935,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -18029,7 +17950,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -18198,7 +18119,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -18213,7 +18134,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -18380,7 +18301,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -18395,7 +18316,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -18564,7 +18485,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both matchLabelKeys and labelSelector. Also, matchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -18579,7 +18500,7 @@ spec: pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. Also, mismatchLabelKeys cannot be set when labelSelector isn't set. - This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array @@ -18745,9 +18666,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap @@ -18817,9 +18736,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret @@ -18859,9 +18776,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap @@ -18884,9 +18799,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret @@ -19187,11 +19100,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -19403,11 +19316,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -19557,11 +19470,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one @@ -19573,6 +19484,12 @@ spec: the Pod where this field is used. It makes that resource available inside a container. type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string required: - name type: object @@ -19696,7 +19613,7 @@ spec: procMount: description: |- procMount denotes the type of proc mount to use for the containers. - The default is DefaultProcMount which uses the container runtime defaults for + The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. @@ -19778,7 +19695,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -19860,11 +19776,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -20082,10 +19998,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -20093,11 +20007,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -20206,7 +20118,6 @@ spec: removed or restarted. The kubelet may evict a Pod if an ephemeral container causes the Pod to exceed its resource allocation. - To add an ephemeral container, use the ephemeralcontainers subresource of an existing Pod. Ephemeral containers may not be removed or restarted. properties: @@ -20279,9 +20190,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap @@ -20351,9 +20260,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret @@ -20393,9 +20300,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap @@ -20418,9 +20323,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret @@ -20715,11 +20618,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -20921,11 +20824,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -21074,11 +20977,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one @@ -21090,6 +20991,12 @@ spec: the Pod where this field is used. It makes that resource available inside a container. type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string required: - name type: object @@ -21201,7 +21108,7 @@ spec: procMount: description: |- procMount denotes the type of proc mount to use for the containers. - The default is DefaultProcMount which uses the container runtime defaults for + The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. @@ -21283,7 +21190,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -21359,11 +21265,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -21502,7 +21408,6 @@ spec: The ephemeral container will be run in the namespaces (IPC, PID, etc) of this container. If not set then the ephemeral container uses the namespaces configured in the Pod spec. - The container runtime must implement support for this feature. If the runtime does not support namespace targeting then the result of setting this field is undefined. type: string @@ -21591,10 +21496,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -21602,11 +21505,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -21718,9 +21619,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -21816,9 +21715,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap @@ -21888,9 +21785,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret @@ -21930,9 +21825,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap @@ -21955,9 +21848,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret @@ -22258,11 +22149,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -22474,11 +22365,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -22628,11 +22519,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one @@ -22644,6 +22533,12 @@ spec: the Pod where this field is used. It makes that resource available inside a container. type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string required: - name type: object @@ -22767,7 +22662,7 @@ spec: procMount: description: |- procMount denotes the type of proc mount to use for the containers. - The default is DefaultProcMount which uses the container runtime defaults for + The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. @@ -22849,7 +22744,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -22931,11 +22825,11 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: @@ -23153,10 +23047,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -23164,11 +23056,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -23207,9 +23097,11 @@ spec: x-kubernetes-list-type: map nodeName: description: |- - NodeName is a request to schedule this pod onto a specific node. If it is non-empty, - the scheduler simply schedules this pod onto that node, assuming that it fits resource - requirements. + NodeName indicates in which node this pod is scheduled. + If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. + Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. + This field should not be used to express a desire for the pod to be scheduled on a specific node. + https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename type: string nodeSelector: additionalProperties: @@ -23225,11 +23117,9 @@ spec: Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set. - If the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions - If the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC @@ -23244,6 +23134,7 @@ spec: - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups + - spec.securityContext.supplementalGroupsPolicy - spec.containers[*].securityContext.appArmorProfile - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile @@ -23331,15 +23222,16 @@ spec: will be made available to those containers which consume them by name. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. items: description: |- - PodResourceClaim references exactly one ResourceClaim through a ClaimSource. + PodResourceClaim references exactly one ResourceClaim, either directly + or by naming a ResourceClaimTemplate which is then turned into a ResourceClaim + for the pod. + It adds a name to it that uniquely identifies the ResourceClaim inside the Pod. Containers that need access to the ResourceClaim reference it with this name. properties: @@ -23348,33 +23240,32 @@ spec: Name uniquely identifies this resource claim inside the pod. This must be a DNS_LABEL. type: string - source: - description: Source describes where to find the - ResourceClaim. - properties: - resourceClaimName: - description: |- - ResourceClaimName is the name of a ResourceClaim object in the same - namespace as this pod. - type: string - resourceClaimTemplateName: - description: |- - ResourceClaimTemplateName is the name of a ResourceClaimTemplate - object in the same namespace as this pod. + resourceClaimName: + description: |- + ResourceClaimName is the name of a ResourceClaim object in the same + namespace as this pod. + Exactly one of ResourceClaimName and ResourceClaimTemplateName must + be set. + type: string + resourceClaimTemplateName: + description: |- + ResourceClaimTemplateName is the name of a ResourceClaimTemplate + object in the same namespace as this pod. - The template will be used to create a new ResourceClaim, which will - be bound to this pod. When this pod is deleted, the ResourceClaim - will also be deleted. The pod name and resource name, along with a - generated component, will be used to form a unique name for the - ResourceClaim, which will be recorded in pod.status.resourceClaimStatuses. + The template will be used to create a new ResourceClaim, which will + be bound to this pod. When this pod is deleted, the ResourceClaim + will also be deleted. The pod name and resource name, along with a + generated component, will be used to form a unique name for the + ResourceClaim, which will be recorded in pod.status.resourceClaimStatuses. + This field is immutable and no changes will be made to the + corresponding ResourceClaim by the control plane after creating the + ResourceClaim. - This field is immutable and no changes will be made to the - corresponding ResourceClaim by the control plane after creating the - ResourceClaim. - type: string - type: object + Exactly one of ResourceClaimName and ResourceClaimTemplateName must + be set. + type: string required: - name type: object @@ -23408,7 +23299,6 @@ spec: If schedulingGates is not empty, the pod will stay in the SchedulingGated state and the scheduler will not attempt to schedule the pod. - SchedulingGates can only be set at pod creation time, and be removed only afterwards. items: description: PodSchedulingGate is associated to a Pod @@ -23460,12 +23350,10 @@ spec: Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: - 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- - If unset, the Kubelet will not modify the ownership and permissions of any volume. Note that this field cannot be set when spec.os.name is windows. format: int64 @@ -23552,7 +23440,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -23562,18 +23449,28 @@ spec: type: object supplementalGroups: description: |- - A list of groups applied to the first process run in each container, in addition - to the container's primary GID, the fsGroup (if specified), and group memberships - defined in the container image for the uid of the container process. If unspecified, - no additional groups are added to any container. Note that group memberships - defined in the container image for the uid of the container process are still effective, - even if they are not included in this list. + A list of groups applied to the first process run in each container, in + addition to the container's primary GID and fsGroup (if specified). If + the SupplementalGroupsPolicy feature is enabled, the + supplementalGroupsPolicy field determines whether these are in addition + to or instead of any group memberships defined in the container image. + If unspecified, no additional groups are added, though group memberships + defined in the container image may still be used, depending on the + supplementalGroupsPolicy field. Note that this field cannot be set when spec.os.name is windows. items: format: int64 type: integer type: array x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + description: |- + Defines how supplemental groups of the first container processes are calculated. + Valid values are "Merge" and "Strict". If not specified, "Merge" is used. + (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled + and the container runtime must implement support for this feature. + Note that this field cannot be set when spec.os.name is windows. + type: string sysctls: description: |- Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported @@ -23781,7 +23678,6 @@ spec: Keys that don't exist in the incoming pod labels will be ignored. A null or empty list means only match against labelSelector. - This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). items: type: string @@ -23821,7 +23717,6 @@ spec: Valid values are integers greater than 0. When value is not nil, WhenUnsatisfiable must be DoNotSchedule. - For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same labelSelector spread as 2/2/2: | zone1 | zone2 | zone3 | @@ -23839,7 +23734,6 @@ spec: - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. - If this value is nil, the behavior is equivalent to the Honor policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -23851,7 +23745,6 @@ spec: has a toleration, are included. - Ignore: node taints are ignored. All nodes are included. - If this value is nil, the behavior is equivalent to the Ignore policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. type: string @@ -23919,7 +23812,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - TODO: how do we prevent errors in the filesystem from compromising the machine type: string partition: description: |- @@ -23959,6 +23851,7 @@ spec: in the blob storage type: string fsType: + default: ext4 description: |- fsType is Filesystem type to mount. Must be a filesystem type supported by the host operating system. @@ -23972,6 +23865,7 @@ spec: set). defaults to shared' type: string readOnly: + default: false description: |- readOnly Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. @@ -24042,9 +23936,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -24086,9 +23978,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -24161,9 +24051,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional specify whether the ConfigMap @@ -24202,9 +24090,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -24347,7 +24233,6 @@ spec: The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted when the pod is removed. - Use this if: a) the volume is only needed while the pod runs, b) features of normal volumes like restoring from snapshot or capacity @@ -24358,17 +24243,14 @@ spec: information on the connection between this volume type and PersistentVolumeClaim). - Use PersistentVolumeClaim or one of the vendor-specific APIs for volumes that persist for longer than the lifecycle of an individual pod. - Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to be used that way - see the documentation of the driver for more information. - A pod can use both types of ephemeral volumes and persistent volumes at the same time. properties: @@ -24382,7 +24264,6 @@ spec: entry. Pod validation will reject the pod if the concatenated name is not valid for a PVC (for example, too long). - An existing PVC with that name that is not owned by the pod will *not* be used for the pod to avoid using an unrelated volume by mistake. Starting the pod is then blocked until @@ -24392,11 +24273,9 @@ spec: this should not be necessary, but it may be useful when manually reconstructing a broken cluster. - This field is read-only and no changes will be made by Kubernetes to the PVC after it has been created. - Required, must not be nil. properties: metadata: @@ -24600,7 +24479,7 @@ spec: set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource exists. More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Alpha) Using this field requires the VolumeAttributesClass feature gate to be enabled. + (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). type: string volumeMode: description: |- @@ -24627,7 +24506,6 @@ spec: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - TODO: how do we prevent errors in the filesystem from compromising the machine type: string lun: description: 'lun is Optional: FC target lun @@ -24696,9 +24574,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -24733,7 +24609,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - TODO: how do we prevent errors in the filesystem from compromising the machine type: string partition: description: |- @@ -24814,9 +24689,6 @@ spec: used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - --- - TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not - mount host directories as read/write. properties: path: description: |- @@ -24833,6 +24705,41 @@ spec: required: - path type: object + image: + description: |- + image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine. + The volume is resolved at pod startup depending on which PullPolicy value is provided: + + - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + + The volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation. + A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message. + The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field. + The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images. + The volume will be mounted read-only (ro) and non-executable files (noexec). + Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath). + The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. + properties: + pullPolicy: + description: |- + Policy for pulling OCI objects. Possible values are: + Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + type: string + reference: + description: |- + Required: Image or artifact reference to be used. + Behaves in the same way as pod.spec.containers[*].image. + Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets. + More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management to default or override + container images in workload controllers like Deployments and StatefulSets. + type: string + type: object iscsi: description: |- iscsi represents an ISCSI Disk resource that is attached to a @@ -24853,7 +24760,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi - TODO: how do we prevent errors in the filesystem from compromising the machine type: string initiatorName: description: |- @@ -24866,6 +24772,7 @@ spec: Name. type: string iscsiInterface: + default: default description: |- iscsiInterface is the interface Name that uses an iSCSI transport. Defaults to 'default' (tcp). @@ -24899,9 +24806,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -25020,24 +24925,24 @@ spec: format: int32 type: integer sources: - description: sources is the list of volume projections + description: |- + sources is the list of volume projections. Each entry in this list + handles one source. items: - description: Projection that may be projected - along with other supported volume types + description: |- + Projection that may be projected along with other supported volume types. + Exactly one of these fields must be set. properties: clusterTrustBundle: description: |- ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field of ClusterTrustBundle objects in an auto-updating file. - Alpha, gated by the ClusterTrustBundleProjection feature gate. - ClusterTrustBundle objects can either be selected by name, or by the combination of signer name and a label selector. - Kubelet performs aggressive normalization of the PEM contents written into the pod filesystem. Esoteric PEM features such as inter-block comments and block headers are stripped. Certificates are deduplicated. @@ -25174,9 +25079,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional specify whether @@ -25323,9 +25226,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional field specify @@ -25417,7 +25318,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd - TODO: how do we prevent errors in the filesystem from compromising the machine type: string image: description: |- @@ -25425,6 +25325,7 @@ spec: More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it type: string keyring: + default: /etc/ceph/keyring description: |- keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. @@ -25439,6 +25340,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd description: |- pool is the rados pool name. Default is rbd. @@ -25464,13 +25366,12 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic user: + default: admin description: |- user is the rados user name. Default is admin. @@ -25485,6 +25386,7 @@ spec: volume attached and mounted on Kubernetes nodes. properties: fsType: + default: xfs description: |- fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. @@ -25517,9 +25419,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -25528,6 +25428,7 @@ spec: SSL communication with Gateway, default false type: boolean storageMode: + default: ThinProvisioned description: |- storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. Default is ThinProvisioned. @@ -25642,9 +25543,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -25721,6 +25620,8 @@ spec: required: - spec type: object + required: + - template type: object served: true storage: true diff --git a/cmd/experimental/kjobctl/config/crd/bases/kjobctl.x-k8s.io_volumebundles.yaml b/cmd/experimental/kjobctl/config/crd/bases/kjobctl.x-k8s.io_volumebundles.yaml index 08264880ea..eff6aed632 100644 --- a/cmd/experimental/kjobctl/config/crd/bases/kjobctl.x-k8s.io_volumebundles.yaml +++ b/cmd/experimental/kjobctl/config/crd/bases/kjobctl.x-k8s.io_volumebundles.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.16.2 name: volumebundles.kjobctl.x-k8s.io spec: group: kjobctl.x-k8s.io @@ -73,10 +73,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -84,11 +82,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -152,9 +148,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap or its key @@ -219,9 +213,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret or its key must @@ -258,7 +250,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - TODO: how do we prevent errors in the filesystem from compromising the machine type: string partition: description: |- @@ -298,6 +289,7 @@ spec: storage type: string fsType: + default: ext4 description: |- fsType is Filesystem type to mount. Must be a filesystem type supported by the host operating system. @@ -310,6 +302,7 @@ spec: disk (only in managed availability set). defaults to shared' type: string readOnly: + default: false description: |- readOnly Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. @@ -377,9 +370,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -421,9 +412,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -495,9 +484,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional specify whether the ConfigMap or its @@ -536,9 +523,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -675,7 +660,6 @@ spec: The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted when the pod is removed. - Use this if: a) the volume is only needed while the pod runs, b) features of normal volumes like restoring from snapshot or capacity @@ -686,17 +670,14 @@ spec: information on the connection between this volume type and PersistentVolumeClaim). - Use PersistentVolumeClaim or one of the vendor-specific APIs for volumes that persist for longer than the lifecycle of an individual pod. - Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to be used that way - see the documentation of the driver for more information. - A pod can use both types of ephemeral volumes and persistent volumes at the same time. properties: @@ -710,7 +691,6 @@ spec: entry. Pod validation will reject the pod if the concatenated name is not valid for a PVC (for example, too long). - An existing PVC with that name that is not owned by the pod will *not* be used for the pod to avoid using an unrelated volume by mistake. Starting the pod is then blocked until @@ -720,11 +700,9 @@ spec: this should not be necessary, but it may be useful when manually reconstructing a broken cluster. - This field is read-only and no changes will be made by Kubernetes to the PVC after it has been created. - Required, must not be nil. properties: metadata: @@ -927,7 +905,7 @@ spec: set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource exists. More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Alpha) Using this field requires the VolumeAttributesClass feature gate to be enabled. + (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). type: string volumeMode: description: |- @@ -953,7 +931,6 @@ spec: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - TODO: how do we prevent errors in the filesystem from compromising the machine type: string lun: description: 'lun is Optional: FC target lun number' @@ -1021,9 +998,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -1057,7 +1032,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - TODO: how do we prevent errors in the filesystem from compromising the machine type: string partition: description: |- @@ -1138,9 +1112,6 @@ spec: used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - --- - TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not - mount host directories as read/write. properties: path: description: |- @@ -1157,6 +1128,41 @@ spec: required: - path type: object + image: + description: |- + image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine. + The volume is resolved at pod startup depending on which PullPolicy value is provided: + + - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + + The volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation. + A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message. + The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field. + The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images. + The volume will be mounted read-only (ro) and non-executable files (noexec). + Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath). + The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. + properties: + pullPolicy: + description: |- + Policy for pulling OCI objects. Possible values are: + Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + type: string + reference: + description: |- + Required: Image or artifact reference to be used. + Behaves in the same way as pod.spec.containers[*].image. + Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets. + More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management to default or override + container images in workload controllers like Deployments and StatefulSets. + type: string + type: object iscsi: description: |- iscsi represents an ISCSI Disk resource that is attached to a @@ -1177,7 +1183,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi - TODO: how do we prevent errors in the filesystem from compromising the machine type: string initiatorName: description: |- @@ -1189,6 +1194,7 @@ spec: description: iqn is the target iSCSI Qualified Name. type: string iscsiInterface: + default: default description: |- iscsiInterface is the interface Name that uses an iSCSI transport. Defaults to 'default' (tcp). @@ -1221,9 +1227,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -1340,24 +1344,24 @@ spec: format: int32 type: integer sources: - description: sources is the list of volume projections + description: |- + sources is the list of volume projections. Each entry in this list + handles one source. items: - description: Projection that may be projected along with - other supported volume types + description: |- + Projection that may be projected along with other supported volume types. + Exactly one of these fields must be set. properties: clusterTrustBundle: description: |- ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field of ClusterTrustBundle objects in an auto-updating file. - Alpha, gated by the ClusterTrustBundleProjection feature gate. - ClusterTrustBundle objects can either be selected by name, or by the combination of signer name and a label selector. - Kubelet performs aggressive normalization of the PEM contents written into the pod filesystem. Esoteric PEM features such as inter-block comments and block headers are stripped. Certificates are deduplicated. @@ -1491,9 +1495,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional specify whether the ConfigMap @@ -1631,9 +1633,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional field specify whether the @@ -1723,7 +1723,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd - TODO: how do we prevent errors in the filesystem from compromising the machine type: string image: description: |- @@ -1731,6 +1730,7 @@ spec: More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it type: string keyring: + default: /etc/ceph/keyring description: |- keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. @@ -1745,6 +1745,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd description: |- pool is the rados pool name. Default is rbd. @@ -1770,13 +1771,12 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic user: + default: admin description: |- user is the rados user name. Default is admin. @@ -1791,6 +1791,7 @@ spec: attached and mounted on Kubernetes nodes. properties: fsType: + default: xfs description: |- fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. @@ -1822,9 +1823,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -1833,6 +1832,7 @@ spec: with Gateway, default false type: boolean storageMode: + default: ThinProvisioned description: |- storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. Default is ThinProvisioned. @@ -1946,9 +1946,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic diff --git a/cmd/experimental/kjobctl/go.mod b/cmd/experimental/kjobctl/go.mod index a95e24a77b..d96046fdfe 100644 --- a/cmd/experimental/kjobctl/go.mod +++ b/cmd/experimental/kjobctl/go.mod @@ -9,14 +9,14 @@ require ( github.com/ray-project/kuberay/ray-operator v1.2.1 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 - k8s.io/api v0.30.4 - k8s.io/apimachinery v0.30.4 - k8s.io/cli-runtime v0.30.4 - k8s.io/client-go v0.30.4 + k8s.io/api v0.31.1 + k8s.io/apimachinery v0.31.1 + k8s.io/cli-runtime v0.31.1 + k8s.io/client-go v0.31.1 k8s.io/klog/v2 v2.130.1 - k8s.io/kubectl v0.30.4 - k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 - sigs.k8s.io/controller-runtime v0.18.4 + k8s.io/kubectl v0.31.1 + k8s.io/utils v0.0.0-20240902221715-702e33fdd3c3 + sigs.k8s.io/controller-runtime v0.19.0 sigs.k8s.io/kueue v0.8.1 ) @@ -24,16 +24,16 @@ require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // 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/fsnotify/fsnotify v1.7.0 // indirect - github.com/fvbommel/sortorder v1.1.0 // indirect + github.com/fxamacker/cbor/v2 v2.7.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.21.0 // indirect @@ -59,8 +59,8 @@ require ( 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/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 @@ -73,6 +73,7 @@ require ( github.com/prometheus/common v0.57.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/x448/float16 v0.8.4 // indirect github.com/xlab/treeprint v1.2.0 // indirect go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect @@ -86,15 +87,16 @@ require ( golang.org/x/tools v0.24.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.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.1 // indirect - k8s.io/component-base v0.30.4 // indirect + k8s.io/apiextensions-apiserver v0.31.1 // indirect + k8s.io/component-base v0.31.1 // indirect k8s.io/kube-openapi v0.0.0-20240620174524-b456828f718b // 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 + sigs.k8s.io/kustomize/api v0.17.2 // indirect + sigs.k8s.io/kustomize/kyaml v0.17.1 // 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/go.sum b/cmd/experimental/kjobctl/go.sum index b41ce15dac..b84d89ba9b 100644 --- a/cmd/experimental/kjobctl/go.sum +++ b/cmd/experimental/kjobctl/go.sum @@ -8,6 +8,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd 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/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -21,8 +23,9 @@ github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t 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/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/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= @@ -37,8 +40,8 @@ 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/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.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= @@ -91,7 +94,6 @@ 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= @@ -118,14 +120,16 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= 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/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY= +github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= 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/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= @@ -145,8 +149,9 @@ github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+v 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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg= github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -162,8 +167,8 @@ github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU 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= +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/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= @@ -175,6 +180,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= 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= @@ -273,6 +280,8 @@ google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWn 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= +gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= +gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -283,36 +292,36 @@ 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.4 h1:XASIELmW8w8q0i1Y4124LqPoWMycLjyQti/fdYHYjCs= -k8s.io/api v0.30.4/go.mod h1:ZqniWRKu7WIeLijbbzetF4U9qZ03cg5IRwl8YVs8mX0= -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.4 h1:5QHQI2tInzr8LsT4kU/2+fSeibH1eIHswNx480cqIoY= -k8s.io/apimachinery v0.30.4/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= -k8s.io/cli-runtime v0.30.4 h1:3iDwgInzWaMh3lrDY8JDj1D6c60agHSv2hy3O/a2a0U= -k8s.io/cli-runtime v0.30.4/go.mod h1:O9Rf0F9x0zeMCcBQEIQxzd4zvxoqfhZZgDAet4hhBPs= -k8s.io/client-go v0.30.4 h1:eculUe+HPQoPbixfwmaSZGsKcOf7D288tH6hDAdd+wY= -k8s.io/client-go v0.30.4/go.mod h1:IBS0R/Mt0LHkNHF4E6n+SUDPG7+m2po6RZU7YHeOpzc= -k8s.io/component-base v0.30.4 h1:FlgKqazIkIIxpLA4wFXsiPiDllJn9fhsN3G4TeX7T7U= -k8s.io/component-base v0.30.4/go.mod h1:Qd3h+OJxV/LrnriXG/E15ZK83dzd306qJHW9+87S5ls= +k8s.io/api v0.31.1 h1:Xe1hX/fPW3PXYYv8BlozYqw63ytA92snr96zMW9gWTU= +k8s.io/api v0.31.1/go.mod h1:sbN1g6eY6XVLeqNsZGLnI5FwVseTrZX7Fv3O26rhAaI= +k8s.io/apiextensions-apiserver v0.31.1 h1:L+hwULvXx+nvTYX/MKM3kKMZyei+UiSXQWciX/N6E40= +k8s.io/apiextensions-apiserver v0.31.1/go.mod h1:tWMPR3sgW+jsl2xm9v7lAyRF1rYEK71i9G5dRtkknoQ= +k8s.io/apimachinery v0.31.1 h1:mhcUBbj7KUjaVhyXILglcVjuS4nYXiwC+KKFBgIVy7U= +k8s.io/apimachinery v0.31.1/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/cli-runtime v0.31.1 h1:/ZmKhmZ6hNqDM+yf9s3Y4KEYakNXUn5sod2LWGGwCuk= +k8s.io/cli-runtime v0.31.1/go.mod h1:pKv1cDIaq7ehWGuXQ+A//1OIF+7DI+xudXtExMCbe9U= +k8s.io/client-go v0.31.1 h1:f0ugtWSbWpxHR7sjVpQwuvw9a3ZKLXX0u0itkFXufb0= +k8s.io/client-go v0.31.1/go.mod h1:sKI8871MJN2OyeqRlmA4W4KM9KBdBUpDLu/43eGemCg= +k8s.io/component-base v0.31.1 h1:UpOepcrX3rQ3ab5NB6g5iP0tvsgJWzxTyAo20sgYSy8= +k8s.io/component-base v0.31.1/go.mod h1:WGeaw7t/kTsqpVTaCoVEtillbqAhF2/JgvO0LDOMa0w= 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-20240620174524-b456828f718b h1:Q9xmGWBvOGd8UJyccgpYlLosk/JlfP3xQLNkQlHJeXw= k8s.io/kube-openapi v0.0.0-20240620174524-b456828f718b/go.mod h1:UxDHUPsUwTOOxSU+oXURfFBcAS6JwiRXTYqYwfuGowc= -k8s.io/kubectl v0.30.4 h1:jU+6WSvcSgzs07H624RA2L79FnqppyV6BKI+dHWDzyo= -k8s.io/kubectl v0.30.4/go.mod h1:4KnGCshO4fFxd/tncWcbKH3Nj9wtoFYwMYPj8CUnduE= -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= +k8s.io/kubectl v0.31.1 h1:ih4JQJHxsEggFqDJEHSOdJ69ZxZftgeZvYo7M/cpp24= +k8s.io/kubectl v0.31.1/go.mod h1:aNuQoR43W6MLAtXQ/Bu4GDmoHlbhHKuyD49lmTC8eJM= +k8s.io/utils v0.0.0-20240902221715-702e33fdd3c3 h1:b2FmK8YH+QEwq/Sy2uAEhmqL5nPfGYbJOcaqjeYYZoA= +k8s.io/utils v0.0.0-20240902221715-702e33fdd3c3/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q= +sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= 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.8.1 h1:jK1ei/EkgmcpMqv4qjyt+6Fmz3TyVTrLUikgPkfREXw= sigs.k8s.io/kueue v0.8.1/go.mod h1:1u80mOR4w6tny+a9cE9x/Hq9OJDAVuGNu7WIfyPtMTU= -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= -sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3/go.mod h1:JWP1Fj0VWGHyw3YUPjXSQnRnrwezrZSrApfX5S0nIag= +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/kyaml v0.17.1 h1:TnxYQxFXzbmNG6gOINgGWQt09GghzgTP6mIurOgrLCQ= +sigs.k8s.io/kustomize/kyaml v0.17.1/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/go.mod b/cmd/experimental/kjobctl/hack/tools/go.mod index 76bc0ee92b..464e01692d 100644 --- a/cmd/experimental/kjobctl/hack/tools/go.mod +++ b/cmd/experimental/kjobctl/hack/tools/go.mod @@ -8,11 +8,11 @@ require ( 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.4 - k8s.io/component-base v0.30.4 - sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20240605185440-12cc8d59fabe - sigs.k8s.io/controller-tools v0.15.0 - sigs.k8s.io/kueue/cmd/experimental/kjobctl v0.0.0-20240724135500-379208b7a148 + k8s.io/code-generator v0.31.1 + k8s.io/component-base v0.31.1 + sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20240813183042-b901db121e1f + sigs.k8s.io/controller-tools v0.16.2 + sigs.k8s.io/kueue/cmd/experimental/kjobctl v0.0.0-00010101000000-000000000000 sigs.k8s.io/kustomize/kustomize/v5 v5.4.3 ) @@ -29,13 +29,12 @@ require ( 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/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/fatih/color v1.17.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/fvbommel/sortorder v1.1.0 // indirect + github.com/fxamacker/cbor/v2 v2.7.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.21.0 // indirect @@ -65,7 +64,7 @@ require ( 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.0.0-20221205130635-1aeaba878587 // 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 @@ -80,6 +79,7 @@ require ( github.com/ray-project/kuberay/ray-operator v1.2.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spf13/afero v1.11.0 // indirect + github.com/x448/float16 v0.8.4 // indirect github.com/xlab/treeprint v1.2.0 // indirect go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect @@ -98,17 +98,17 @@ require ( 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/api v0.30.4 // indirect - k8s.io/apiextensions-apiserver v0.30.3 // indirect - k8s.io/apimachinery v0.30.4 // indirect - k8s.io/cli-runtime v0.30.4 // indirect - k8s.io/client-go v0.30.4 // indirect + k8s.io/api v0.31.1 // indirect + k8s.io/apiextensions-apiserver v0.31.1 // indirect + k8s.io/apimachinery v0.31.1 // indirect + k8s.io/cli-runtime v0.31.1 // indirect + k8s.io/client-go v0.31.1 // 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.4 // indirect - k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect - sigs.k8s.io/controller-runtime v0.18.4 // indirect + k8s.io/kubectl v0.31.1 // indirect + k8s.io/utils v0.0.0-20240902221715-702e33fdd3c3 // indirect + sigs.k8s.io/controller-runtime v0.19.0 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/kueue v0.8.1 // indirect sigs.k8s.io/kustomize/api v0.17.3 // indirect diff --git a/cmd/experimental/kjobctl/hack/tools/go.sum b/cmd/experimental/kjobctl/hack/tools/go.sum index 8ba1c333cd..225222680b 100644 --- a/cmd/experimental/kjobctl/hack/tools/go.sum +++ b/cmd/experimental/kjobctl/hack/tools/go.sum @@ -48,8 +48,8 @@ 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/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.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= @@ -62,7 +62,6 @@ github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF 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= @@ -133,6 +132,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= 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/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY= +github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= 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= @@ -146,8 +147,8 @@ github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQ 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.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA= -github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +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= @@ -210,6 +211,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 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/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= 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= @@ -392,36 +395,36 @@ gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= 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.4 h1:XASIELmW8w8q0i1Y4124LqPoWMycLjyQti/fdYHYjCs= -k8s.io/api v0.30.4/go.mod h1:ZqniWRKu7WIeLijbbzetF4U9qZ03cg5IRwl8YVs8mX0= -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.30.4 h1:5QHQI2tInzr8LsT4kU/2+fSeibH1eIHswNx480cqIoY= -k8s.io/apimachinery v0.30.4/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= -k8s.io/cli-runtime v0.30.4 h1:3iDwgInzWaMh3lrDY8JDj1D6c60agHSv2hy3O/a2a0U= -k8s.io/cli-runtime v0.30.4/go.mod h1:O9Rf0F9x0zeMCcBQEIQxzd4zvxoqfhZZgDAet4hhBPs= -k8s.io/client-go v0.30.4 h1:eculUe+HPQoPbixfwmaSZGsKcOf7D288tH6hDAdd+wY= -k8s.io/client-go v0.30.4/go.mod h1:IBS0R/Mt0LHkNHF4E6n+SUDPG7+m2po6RZU7YHeOpzc= -k8s.io/code-generator v0.30.4 h1:1J2AcpPNBGh/NH9+m4TDh8Yj+mSbM+JyQhH0QdIMwmE= -k8s.io/code-generator v0.30.4/go.mod h1:Dd8gxOr5ieh9yHCLKnIkKDmk1H2glH8nYCAqwFogD2M= -k8s.io/component-base v0.30.4 h1:FlgKqazIkIIxpLA4wFXsiPiDllJn9fhsN3G4TeX7T7U= -k8s.io/component-base v0.30.4/go.mod h1:Qd3h+OJxV/LrnriXG/E15ZK83dzd306qJHW9+87S5ls= +k8s.io/api v0.31.1 h1:Xe1hX/fPW3PXYYv8BlozYqw63ytA92snr96zMW9gWTU= +k8s.io/api v0.31.1/go.mod h1:sbN1g6eY6XVLeqNsZGLnI5FwVseTrZX7Fv3O26rhAaI= +k8s.io/apiextensions-apiserver v0.31.1 h1:L+hwULvXx+nvTYX/MKM3kKMZyei+UiSXQWciX/N6E40= +k8s.io/apiextensions-apiserver v0.31.1/go.mod h1:tWMPR3sgW+jsl2xm9v7lAyRF1rYEK71i9G5dRtkknoQ= +k8s.io/apimachinery v0.31.1 h1:mhcUBbj7KUjaVhyXILglcVjuS4nYXiwC+KKFBgIVy7U= +k8s.io/apimachinery v0.31.1/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/cli-runtime v0.31.1 h1:/ZmKhmZ6hNqDM+yf9s3Y4KEYakNXUn5sod2LWGGwCuk= +k8s.io/cli-runtime v0.31.1/go.mod h1:pKv1cDIaq7ehWGuXQ+A//1OIF+7DI+xudXtExMCbe9U= +k8s.io/client-go v0.31.1 h1:f0ugtWSbWpxHR7sjVpQwuvw9a3ZKLXX0u0itkFXufb0= +k8s.io/client-go v0.31.1/go.mod h1:sKI8871MJN2OyeqRlmA4W4KM9KBdBUpDLu/43eGemCg= +k8s.io/code-generator v0.31.1 h1:GvkRZEP2g2UnB2QKT2Dgc/kYxIkDxCHENv2Q1itioVs= +k8s.io/code-generator v0.31.1/go.mod h1:oL2ky46L48osNqqZAeOcWWy0S5BXj50vVdwOtTefqIs= +k8s.io/component-base v0.31.1 h1:UpOepcrX3rQ3ab5NB6g5iP0tvsgJWzxTyAo20sgYSy8= +k8s.io/component-base v0.31.1/go.mod h1:WGeaw7t/kTsqpVTaCoVEtillbqAhF2/JgvO0LDOMa0w= 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.4 h1:jU+6WSvcSgzs07H624RA2L79FnqppyV6BKI+dHWDzyo= -k8s.io/kubectl v0.30.4/go.mod h1:4KnGCshO4fFxd/tncWcbKH3Nj9wtoFYwMYPj8CUnduE= -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-20240605185440-12cc8d59fabe h1:fPapvQwJ+A7I2Vm56JkEWJ4VsGQq4d6B1tL9DSdn+xA= -sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20240605185440-12cc8d59fabe/go.mod h1:4+4tM2Es0ycqPedATtzPer5RTrUq3Xab59BYogt0mCE= -sigs.k8s.io/controller-tools v0.15.0 h1:4dxdABXGDhIa68Fiwaif0vcu32xfwmgQ+w8p+5CxoAI= -sigs.k8s.io/controller-tools v0.15.0/go.mod h1:8zUSS2T8Hx0APCNRhJWbS3CAQEbIxLa07khzh7pZmXM= +k8s.io/kubectl v0.31.1 h1:ih4JQJHxsEggFqDJEHSOdJ69ZxZftgeZvYo7M/cpp24= +k8s.io/kubectl v0.31.1/go.mod h1:aNuQoR43W6MLAtXQ/Bu4GDmoHlbhHKuyD49lmTC8eJM= +k8s.io/utils v0.0.0-20240902221715-702e33fdd3c3 h1:b2FmK8YH+QEwq/Sy2uAEhmqL5nPfGYbJOcaqjeYYZoA= +k8s.io/utils v0.0.0-20240902221715-702e33fdd3c3/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q= +sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= +sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20240813183042-b901db121e1f h1:RIqUbZQO5yizUt9nozxQdzyLRD1sG6s2oi/QZrlg/hs= +sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20240813183042-b901db121e1f/go.mod h1:IaDsO8xSPRxRG1/rm9CP7+jPmj0nMNAuNi/yiHnLX8k= +sigs.k8s.io/controller-tools v0.16.2 h1:uUFF/AW3phBWPiERvkSNOVct//L427bPS7xGfKi6Tz4= +sigs.k8s.io/controller-tools v0.16.2/go.mod h1:0I0xqjR65YTfoO12iR+mZR6s6UAVcUARgXRlsu0ljB0= 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.8.1 h1:jK1ei/EkgmcpMqv4qjyt+6Fmz3TyVTrLUikgPkfREXw= diff --git a/cmd/experimental/kjobctl/pkg/cmd/printcrds/embed/manifest.gz b/cmd/experimental/kjobctl/pkg/cmd/printcrds/embed/manifest.gz index e9659c8fbd22a8a4dcc3d6e344fca92f069fda00..f8a2a42c3922970aa00d7982a1a8b16c3fdd3311 100644 GIT binary patch literal 432404 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

t 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 br@i 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 z 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�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�LVO1BWDx_lnA?X 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 FKLDE0`40d9 literal 428592 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%0A)$L2jalrjIdu8Km2I38 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%0A2bUD3kFisL`gN zN3TZrYILtg_iA*nM)zuTuSWN3bgxGDYV=cHLx-Jo=_a$}o(DgCr;x!HK}VN@^DVvY_mCh`Qk+=SLuSfj>TNZJkg;S2@3j{p@h9H({IfC z+sLbXDCYchkO?dEtC)AgczpoNP&J6ii9$H!w*25F%}E8)srrCH`jQ1|q=+*w-Ep+- zT_prdD9}A2dS@Z<422}miAiyGiiF-4aaU=Znx`ePDfZ9|o!Fu@2KW_%&%n^g&DGbk z7%_57m@=LB$t_J(b-GYHlPVc_j&VluGM^08eHx^EY2V9e$w3py`Wk^`i;RJP0wuq@ z49$6tQt7%{F%}8Hg~cbVhRD}o0Y)~%%p?DRl3N}mshE5`!2#2cyslBb9c=xjooVMWU zMhXuUJndX}z=SyyJ~WN0O?Xug?8=zp+(dKR3detOMojXxmMRcsHT@9_o*v4hqrSR9 zU)`XuZqVS5pKEo4IhKa{jbi$6u>+4`YI*QGs&$|rg(X#JB2g2WIgPN)d4s7V>9~1b zuIaqqDo)eDK?@>=<}q+Ir7T@@TJD5*QLv!7wN980AFSfb(r~!NQn`Z%$`^!JLD+e@ z1MrPG-K(?bH`1SQVqJ9qEQwekeoI8{?WtOn4XRq%36@5R#@UhQQ&Yl&m0310BQC!m z$C=<-8P~s$nyjlQbQ1`dl}lP4G~O8Z%j}yQ?BwfT_V=$sqxRx`CDG8RjW`}Q=yh8< z=?%pX;Ey{jYtu1=&BPHp#}ZcVPVddAqn*Y?bx>k8w9s*68<^-6Uf7tcY!hLI%|0N1 zO@4Q;9mE}4#~$GMG{O(h;U>F=9yWiE)&Wn!o4xyB#Ip)WvSnQv({ekTcwZz~n^&WZ%?!)i)*W{FRHh?w~rHlUf=E7r5iueDLVkxBzr@ye6=~OW;35Yh-q*a{1&RJH^DAR|vF%_axAGstdcGt8rSh8Y{y?Bdd*b)(j zClCs1vWRo$`6}FO17SNV56=tuOyx5X2g?iTB|@}BU|jV=;dd_-Rvye| z<-*GFy=eHnL<97+EpS4fVSLoY3rv!YTc)f-2~cdHYaqZCVE~$hv8t}=CG#3yc?&Qs za~XUTHM=u+IU^FHjCHGRZ$cP9ZhKIyp-$&u>2mpodKL(B<^(f|_8nmEK-Pb;AIWH3 zCyQzohyU}xM~&_k^&f_IS{JD=m??~)! zl>Gbn^G843$DcnM@#^ExkDN^(e_mBl`uOw4|>>)=~@(34d8npS4pxRa@O<=SYDscrgQoH4$MCwJ`bXfmIm2Cu(Csz@DFIHn;3S!ti;3|)_rd};;h-j>v zN|cf*Wu~TtC>hh5JZCm#G-^#opqXfr7ST! zqLx#!2RLn7?J|xtoB>DhH$WxaH_kGC7bhP(ywq5oeduptS7j15(1jr4@!qX%T<};U zf~B0rz7N4;bhLC>eKUg91MQm;eBR9nJoJy>l_2CKp?|@Sx)LDt)0_YY6U0Dv%1qIs zu1qD(O=iXgIklBAnmkmm3nwA{VU`#P%nUWJB#3WQ83KZ;rn7+aO`75xbayoX0%g!^ z(65?UFo_PeT9z#=QmP@08v5K`a1@Q+5@(0a=q+Kj0(dBoj+_y=tjq?@(?#(Olcu2x z>yq-h7o|(rit67zE$Kf#uBrx2XV`)(QR0zCt)lLrK0~Jh0^K`q?5c3Uj*136t9BU6 z1BTV`@dM^Y6CwzaK-PrIB*T7Fz4P4<eG75AZ6~llUGn-?6W51VifJEb^BA_cviVpTS4L5{Ql20+O0P&+wR&ooz>5@uJ3ji-6E&omqPj9 ztv^F;e}?{b_3eLqB=>t8W9co9YMB0r>$k}>2-JQ9Vptz z?@OH1`-_(CQRP3r%{uTqT08Ead$m0`Z(zlWJMP^#ojobh556n!Jr@&rQ$5cDJKlLW zyt8*XZ`;7O2Y|je0pD#OQr~yqm#_)$JKhFIiM}_0`jFS&@HDxi|1y8pz2Sa%`a27) zE~4+wV>ZNl&kfi4d(E@&iudsLcmLXZ%BuHYhyUFDAIsqXV{I5`QGU_Tl8C2(h+MP&XX9CRpA zCeuKf2x4LU3_XlLN9W7Q@$TsoB8t&T-=GAtGs)E!s$i z9k^7>VvknV*gt)D05`y2%Bdfv$KTYc@45HZuNfZnyn&z%@mCHiMi<}mP^Ro zie85ZA03EwH4oN? z9*_8kZ>H&Myy4cIM{|Uqa2lY)NG{zrHs{jG@WRR@#)RUjcP(AbuOull-hk|z>OYy? z-ihsuAk%vLyW!aXM1wLI_%uQkk?>wx=H99bZ9-CWXw0Y!qLO zmgO3XFsl+@y!YgGa4*2I7m(K(mo5rxblEQ^T_xHIQ+DH~| z0rc;~389P({Sl1kjFx2(@F35?M59CV+1yN!tIj72=alng2UNqom~Yke^FKeyf62ac zMVY$KK}=qBbde^9%aoFQ%Q7aal9Mh!$cmjpD9Jh6+Xsn~DfT=AP_w^PT~Qh}ymp4H z>WVXgNEs>^nk;SkfF4KWuwQh9{asG#j!a%}S<)d$L`_KXw6oc}^{Bas-!*vNwy0ea zO2UIAC`r>((mC}wh1&A?kq9Zxfn9_(xdcdMdt`?QsRWhjQuJfah%+JMuwu< zXdeyXWNBpagtJ~>;BWo2pT4wifj%qHnJ6t&kbaNzrR&Q&r7tgo%rFs!G7l(>Lms9w z7QA*B)&f&UDMdl4g$?+g}<}nM!`2x$*zp(9a2uza7XsVe7-JB{=TAZH^!P zStb&^EMAt-=U_`g-2n_uv5ya{LcMfJ3P?C*J=l+O?L&|OcJ*hNlfDwa<;>% zJ%U7q9mMzGJD8by@erc@jzz_)&TAUjdJ_v*t85 z`l}>s8=mW)@t(E^x4l=r;opaOF4aTZYdTiE#b0Zdvdc_^bC(cE*0<5rn;{vB`NlGT zDAfpddO>ui9~96!FoQVGqjsHbsz(+EqML@IT1F5<4|WQ-Yk;d%2HX#~r__Fj4-#pF zlLGv}ftzyX3JjBebR;#KhXkl42&y96XJ*uqg zd@|AGjR&2Av3*qGbf|LHQK8VZ!i-lt$oI3IL>j7w)n=B=#USW7rbwe#7IzLcP+A{R z(k7EPDY2R7UygHm%B75vnZv1QutXUTCIzqGswHXJZ07;*Jha)-( zR&9;6kV-31uBZ(LPh}zlH7vI_induu9$xYjY9}4`U)9afR&GZ>>ZZ66^`sx?hgS4M z#fE>gIeI~Uod{fkB86?a>gTdmQvhIWIRkl&%w0T6jWJ|vM<+L=!j*Cy{4NFU6(kHX-%WH8SPtm%@h2j-y(!xaS*Urpeg&Q^J93!4 zfGjDFl9OzZXsBk+O$7Pz;tHvGGd3QgLgH?E-ZvtJi6nxSC8=89Dy_6+ftM_k$a==iC|l%j75u(Dzh+W z9)5sT#lvjxZ=)q!-Ds-+!BIouS)`61@h|fS!%2+B^<5Pv70@0 z2yEP;1mtA~R9fyizfwU{;L+`FYY-q26{nE#QTMkhn zr0N<_8_j+(lPG>YRJGNyfA*HLsq!xtXm7wp!#3stt+g)F5$8Z=R`xTmB8x^;-HAiba%RUOPs0a z2K>jq#R3V z1!nRf?iMzPuT5R7En+8?ORG=%nd+838xUF+sTkfMF48(taZ8@%4}4N-i+jS z{(KR`Mn*|5;UB|5S;QZzWtWKW~2t~ac!q`5YUzKc!kM)1oXX#+k6@Enym9#s8N z%o)2;Uq6e=XgC_j6!UsXG!h8&2GbfoRn8-IG6GRg2riSY&urA*9%ygbT%0GucAD|G z7qX>Sz)S_xW{$-V+`qi7WT`7_B)hvj>1~$^hW%ddjOyAkbAfvZqtN0Y>Vh>(FuR5*Fx z%s-@%?9p7=UF)VhX4%i*4!5zzE4NZGU_JH^^S~+N0|Za$f6=}<4n_?Kb<9;e2!aOzm#YaFA>gL8w5wZN%>FTVxC=j57eA^D;?P(Syn^bZUj&#snR1I}q zZ6Is1G4ZA`6ht^6TUleFc6wnjehoo)eJUtM5NUYYKv{s8k`PK>7Mle!{th?KE_+=^(!z0d=i%vg($8xJiI%={!&jD-5~MS|QS-ZXpN8W+OSASup3tk+|_s`D}|p;mO)EX@x& zkXZ;S2!ib?FQm$py~Y+oW=WFn*!dF<>M&^tRF!h7#4c+TNA?#wq+Mp(PZVId-}Q-r zb*v*AZ4{AXC!ST|b46A`GnKh%Fl{JEG4;}-Rwzw(YtZg27I9^en<(hI9Pzp=sp1JZ z(!(m`c$G@U&mSbR@yZv7UA>Cn&f~eXZ($xJa2JVP2U<3WUHP6kyozEzzuN=!d6mo) zdl*g-FXFkr$H8O&9oP71eI3swkCS*7&&564;9WFbDDpk7WzfL8NG^8KQnu(neBhRC z_9_?2-HPL+nbN$NTqIiz1JL9}h)&*G7Is8wj#3nqsp$%BsdD8%t*MOSyy95Hx1X!s zwe24Bv)=X#^MH638wVRwEau}*5;pBxQT!rQyA&6~?qGU02eI_va|k^FGF?TD+LI)J ziAU^$8&~MU_c7+XrAW7C%vy04Jj^mbtGTVQr!4eLzbGYV#m;L*%~4S+$wD+ETQ2_- zR|4YIZIoeo9zbR6>{F>3Op_QK$Fi7o$Lp#eU7?ze)T2_6N;v4L7g77w)M{)0O9tgP z(dE?9%ObL28YiUK8tsgo@ELw4U~@qmv?rReC95&ddYeVZi+Sq7cRdPhmScQgGYt@U zEc@_ZNCxbwX}rO@*68YH>*JJXYcX!303PEGN?Tz)#t*dNNei5kc66}kBp&C&lA|3+ zb8nIve`J{WIH&7XL@Z!erP>S&%!_T<#up0bw)Jj*oh+-H68_c$RdVp%P-;RhNGAeE zPh4@3xbbUhMUKEQwg%fsSG=PG%4mhv&|{a-quGga{B-p#kq7VJp!lHEV!Z_DeERIzspLr09>J=|@(t-wh~ z;7CqhzpqLcB^ucZAkj0-CXi!YTdeT@{;ClU4qe8y5zSDUhfb@8PAP|u`fxY#=thf? zJ$7`bEz2<)xZ{Nlx;^arGV1bECo>skVdVZL>)7o+6^`}NQ3-v;$oZ|xFzz}?-Bi78 zwv1A0^L0Ut8ZW3o)LPiO)A~J|k$BY$95m1_jrrfcNBkG z@y?E**>6jaz`;9%b(}1b8Ww0?R;q^*3m*e2qec{D%&|;2g+AD^PD+RByuRSnEWbJ^ z4SS)kU_B9XpzakNOFO<#NqP)yE}?-`4v2T`U5_hb_NCE66DBOc!q`sJnPE91%1^Wj zIObS5?>u9Sva?88GaP_BjHE#3W?|w#umQ^)Hgj^)j}w_mGy!RBV6a}m`W2WuP)%zi zg7S3BRmU9bfb+Z>VJk2icJFjOrAScZ114yF6QqL5{r9BVc)BV-@iZvX~}<$M1E&*8lB3*ZuYf&>WuZ z<BEP{2#y+?j6IR-y|DFc_aChhvtH@ zg6MBG#=41wDj%Mf#k{$1E6+^%+25id)pO)CZ&zuRC}f^!Q_lw&3dO8i`Q72Ndi$ro zm8;6~3Oa%)B{&I##6ITIyY}8{2Oll=d9Ns#l#d95H7(eM$_U+C7m#tw-AS*~a&lX| zIa6`5@){$tTL>0-Nd{;|lPqT^sbB_3-NX>!!HH~#SRscY24uUcA#K7zFgwa~7P7-HpEYmC}PxTpa&4b+6S$$)}dn3^?(DYNA~y9T@x3 zg64VD)^0=5p*d*Q%qhptA^<@Lsa#R14(Y6NwMANX-jh}mR<>m9^tz^9m5XcN0k7P; zue#zz@~UUZi;4IqK0{w&Ev$3o<@ex6KErN#jT_`;_cGmwZ;k#R({1u9{+A{4s@fgN z+`1ky|Fge_*%*;!-Xj^>(wM}B+o9e7*Nm-u_< z|4ZgyZe~NsHq5G4PI4)YX_5kbB9 zNs`cu7Jw4Kgg{|XW4L2iN!yX+KF)9Sq^@8Ut)_q0?tEQ4X>W1Sxn=DfsS}q?3;m8{ zR(PF7+$$KRfCK~7QT?PDd;b|&DQ!K^v+#@Rk6^HGRnO*0PAn?Uu4`Ds;{Zk}551Hq z)_(tH{#;ghlwowIG`AE-=6pKqXN>dYZ4^x90`@Xw--z}krxcUSefF70DFb%WR~cYK zT%h8Ww?e*fxgiJfGxhzRU>j1G4_3P0jkyfyV^3$vft-1YEnS4uIM_c;3&`lkuDa^xKR$5c=5Td zQgs_E5f>B3%b~Q$Z{4LRFz4UZTF$4#MkyvGKgU-QIrw+}rW{ zy1N~O`1(CkSR3o-yyN5P;^Oi0)!AxaGh)uaP`I<*$kfZY^Xc}Ill8gj6jxYS+q>#r z;2?pn_QpG_6uk}hm2%*Hi@KMUDwAI1RT!W){!_5p9@H;clVJcdnU+py~hE3#rX@9d%~j$=JZt4Cej zS8U!*88gHiQ$Uyaa~{2QHXD23Cr?jY}nx8Q7@BVN_KB6GO!tG;azG@V(Kcx0z`v zfuuOk%5glM=-Fyx{-%OcSNN;Fm_RS>O;8$j_@rx6iGoIr$>Z*-{r*+uCzmibfoWfD zR~H6&8{5CKC^te7pt{@Bs(^^#}&qA!hE z?TmO#&cyFx4~-kDJiCVhuK^?=GeyfdO;%N|gh5Y0rH?SmV9oWw+3jvbmIP*6Kk4gc zS8no5#PDP|W^8Z+mYgLzMoI|c3 zu8xM1w8kSRu?3+3GUsF6;LZRJoP`#o9AslY2`9u=yDZp>InC64K>{~CzsAZ!TFM0q zj7Ve91*#VRa`$En@#cm`5QneLSc>Vrx@^Rt(yojz-f~K8)0Laj3_uOB>7H1{++7Fq zXW2ON(o$Z&_;m=uplU*FdAVb`>|R!z&#%3N2bAL#@CGU;RM~Kd&%WI)hJ*q_qb@$D zff5~(T^OI`_9?FhTW}mCon6Q&3yQ+)JC3~V3U+#pTT8DjC_RkVgL$U?JY-pm27M-2 zm0y<5cj&%$VmK*dgwmo&nE8ce3(JRXr0@Ty9qDj&LzC3-rw5Q_c; zQ$hs*&YTsum2=~51&*ZZC})kGQ2Xsiy$anP(tcM^M|D*}E=XdisiKAL;LIJckB1EM zPIkfa`T;W|;d&01e9bqqL=}apAVsuNiS26OGcHQt2UlufjjAyvOB#+dft`?nFLDT? z2B8B1&_Szn(dZ1Ib=#NTfex?$+pOazSJy8I!{Iy9FhqKCo>^huR}=nB{#{$zE2VEQ z%+OM}&B1_EPdun>o#E}lKMY1Z=~AQzv5Usda=VMuAGRT{$#O*|0@TGp^9m6ADF3UU zto9v;m(zttnafz0!$+3*60jSj2GpLfry2MG)+VlOaDH{E#G)Mmv~F{xUn7~oL{ zA|WoR?(kLV(k?M7V4j|1p~_0V$xpAn^)liu2^LQVd#ew?1W-(MTtVaY6=i@fRG^2N zoMa(Yq;ax|4yB^-V# zj0Rij9+++LIz0I~6*-2Wv>o@q@=EJwl*%OTcukMGDIXh^;eRh-PDUZQ3vNQka*WuS z{U%euGc|K2GcHhV zc_h=czQlvfdr0m>rkLX*nGk$36k{mA0;XJHZU^mX^~DG`jIh3Mqk-9eOx5&>FHZt| zuamOiHcTO*%K8(xXhhLAE>uAqCs{oWC9XQFY*N_C-wEhG!VN#qFelQNGu`toCY>VWL$)&tI6A2YxUTI3OM5-N zUFUTGPqkVc-~x7tvyN4y9C8xJvhFi)-Ri8h`n@EuCC%?v`6lxDl88k#)s8F!TEi(V zdD|5;MI@W0+w6bXsE-aU8UGj;6=38}JgZ!E2;gQD*Xpg^1=d**@Hmqh?94jjW*DBk z#)`&D<|0($6OC2pW|fMN)Fe}A0pw3}gvjp&wh%Mq_nIwkTa-*Wn;2xn-2yfZ2-G(X z621^mgs54v_djx+0)#Jj;(Vg3*LP&b7vt<+sk}3{G-DUOb^ff49f04_+7jx1M8*nG1CzRS${ zFo&d=sGQc%5I2mBv9~=iPg9q!*cO8b+%;dM@=M*63+%Kv;ACw;$W^|}@zD`U3x=$} z$_lf(?Ou1C2%YW9Q%E5IbhX%z1>c(QEF^7k)wRnkJ=X0+MIav{#_si{suj1C`y zFpn_~Im9|7x>;Pb_LOOkbYLGa=A@LjWP-ByIt;0hWVYIHhzHL0gH=V#9oxm%*m@5Z zO>ylF^JkLZ8Htu13|nJD-Y#d}J0Z5Iw>%>>Tg`QRtP5PpTQx$NO<)VA8b2%5*5ejK z@hz<8MC_>G91yqH49-CMd;lKS_xgYL$5R6-%X$;|epHV+RI(FV>X|@mJO`AI%MD@= zbCYPP7OGB5rUBFW@OI|p z(_PVTyiUhlWrqdZR1KO+(@U5_d(|l`hC6SZ_-(1;?~@TXXH1J41RibQk0Jfzx5z2( zz%+MhrsWDJ$W^33^UVKL(`?#j9q1ECK&l;yFUT#wn8#iYIYyKa^H~k3_d+9bk{i}2 zBsJ{cp(c1mMMuk#QP8>uONRU zTFBs>*}B0-ZLpAt{n;gj@Z%XnJB74<=sKb%DAgHV7i%})1TQo zJC&C%_lP-m!#Rc zg1c8jEe6`)>`#EPug}XcOgolDjr(DFu96khuNjg&Np+C2+^--~Gjs)JXZc!39Lq_U zwET**k2RFnX2y7I?8qH$!xEGut(pc@>B;U4S@~)O{zlPKrh1QSv}#N<6wZdVg=Oht zRXmsNm`PV)G={fK-s*LNYxEVHHi|2w*IT<1OfWh7IyN*$ug;(I7qPKfJX&(ScnOG; zIW~DFyrWKAstqz~wyRzB@DR*2HBa~Z$n9pdG_I+Y3`L(QqVzz%0Z=sBxaw2Oai3G> zAGLnUZ`sT_d!9YOwsh{k*6pp__)6JXbAt>^YRBfk>jH1?wDp zXZ`8{Q3xi-GKi6H5o+4<;iO_3+x0KiZ!tiFulik8(s3v;6OOO*Vxb<>Q1=({X<6kd z#DLdgHYg7l_cfeMDB!dnD~=PQ<3lXhEu7cZ7v|ZMnk>Rp!)~|Tj%=%c4^{bvfGDRo zv4haCe0~jwS&-5O0{oJe^bi#WVfh|zjU`&f87ejh@yoN-4+BaGk54g-X(}5!nKnDo z=3^ZdRbkyTE9r5sel2AQH_{3SlWvZzJf@+@(GBO;{#Q))(FsgVnC(3O%3x*7|mll zCE&w_P3x1u!Z$kjqkc6h|(=yE%h5*!))dIu?uh z#YUbURGj%^6JxHb@xI^SR@d|g>Vsl0vT5K%v8!}i7ILKD4Z^<1UJu|WHkQeNm~Yleh`ch z>LCa-TjndyKth>m3SwC7z=VH>%IF^E3Y7I3p%S>exmirWSz;y?jND%=;+amVr4j_1 zbQ0iVWa(7Cxdy!1IbDOjSlO^~Xw%+#41lF~5~8Kj&U7UkNr|eIPf{36*$J$C3~^ko zg~Z(HY}q=kRJR93DqA7JT8~XtJfCsd;OhkCb~FV`*p>}U$?iJV z!@fxDZf`p)Ayd6%@}s!6%Z~s-%#M{dG1!6@#@**q+xsF1>pn#y!rTN0p)%U{rI{WA zsPoZPIB0fqakkuVpIrQk<1^C)=|@H z9-9nA7UVlDRvc#xs0j(IoPv&>o0lZg_f)lX*0SaY%fIGJrPu)CO&gI{0G(ZcX~M6u zaj~QKaYb*@FiQpVodlCQt6fr2Y*l6lp{_0NxOfU|&P)(j)ku3^SiK|GcG5fo2`F?bO7&WSF{+V=>xXJRWOPQpfy3bG<$~>SqCTQsooRj*O+X`eo<$8%;h^f zy$0;lLsj+g17_$8r?Z^x7%lp~t6|p<79-E*Dc<(dX8RDrf)&gJZb__*FXuD#lfK0EYDFyB`BMwfTnF>CUg+)BNF%KhCmKI$j3ezs{l~hGG_nKwtsN04OM(CRAS%HS`h&PTTYkO|79z4yrz#eHezOYk0*jFLlZ_xo>YP{e~BA(Nm@MJ#=Mv=BviLkprosA(ywU(x?PMIeN^W1iwmw zV{-Gy$IWnrmq~9g)XjNb^CfiiJT`v@4IQ=mZ4&k;*CfUsQsuZ16Ad#Dw|3GoPqG}r zuvNt&<-#0b36O;v0i?o*Or(Gw&Y!0pgyl7!*4^q^MM@%7N2`^6Q+XcJ$$L>94r${` z^M;UKHG-K!CC#Kbg`n`{Osi@WE4SO6@qwg+3(eMWYDL9nquS%VJ15yGN02mV1*J<% z(Fo2&6=WhTR$FnC&j&`;Q+7DV`le|gG$?RqhW-od4ndp0G%pP0F1UjyC#5phpPDkU zQ~&^9U;5>~%?bs<+t=|(J(KM>(RQTR@Z-q&{^cyo5N|+MxaO91>vE62zD_g7PB&m7 zrFBtJYI+)`9Z`M%G?tBk;6-di5fdh>NNmPIpb9hHSW@;{c;;a%NhEQ94%R(hY zx=1J|Fwwz!lCPF7Y5-iyU5aWtMKny-RVM${4i~R!`wgbFJOF79G!lg@w;HcOVJ=JC zKqruRp3dqG4Kc+i-~1oK6%@m)6YB)c2qhq-l}Ukgk91NVdrM6ZDF7*7x(fbs80*$E zmb(Wf?$rGQV~VSWyJ~?FuI1a-Z*TkK49<arHW16GNhnWnIR7reP|M!xH$9gMxsD5zI18+m9PLGfm2sTzy72 z6c4v`qd@1~CylkV9YdfdQxv8Rz_>~#x_#8_-EvGxm50BCLVagB@L6xt0j)6_*a81S z;8$dA)vbpEo6-vVWGkzm) zy)ju6D>_gXB#tR@q?{FyXRp|ab?{Sz!1RypHL`(1T;uk!$x0i}QD5+Aw!9);+Q6*M zHLJW`xIns|Ikr%_vpW{;n3iCw@P2zyT4EMNmMUCUwa)UhT9WF*YXo(PY~&T{&;lZt z_Om*tUK?FVlHlP%&UnggO<<`XVzm+yV^w7S8jxVaIK0$YQPvbiW^_~)2T-WeG2U;|MU2?Rh zDvqYW7xV-A0)K#;nXT}I8utSJ(>zb@#qoGe zFc`8l8kT5kMu;ER>G(4>Y(*oh?ukrhrKxv^&Tb zCFamEY5_5m(7V1z?>f9RI^{P)-}3sWZX$}xgYx~WjM$}Q1!%V8e7g(fR?^oRm}C^@ zCkruPdy|jWSyYKlTrrZzdEEL)8`hAx`}#7g;y2|SFi(2YnAb(?)pJ6PaeeIcVqU12w*Bm44fhV|aBgwxR+h4S^Xnr4! z1yql1%+5qLBk&YZUsc+scPRu^cN}DHVQQ>v>-dPHrJAhQ$L^vAUy}@+hSI=P9W2T+ ztUE&YVmGWR*mHEFD-=8&=M*jIrn&|Hn~1kDKfPc`*(#UYf~iEoW6DktX@8&#n#UBF z7ShTHCH&uUc#ms!(!ger3aGvGk;v(E6$}lI)*K+;16NTRiY!w-P6MfWg1Lng9jYXR z{N!+(fNK!*#?wKce-rU+?%hcyT4u){M-Y2~UlPGZS+KLPre^@jET3H8i*bY3NYF;>eNPR zML86?`T^o87O*LM(*R^9fnGKK$=hI)yU+feUhel1f1Hnx%0Ju+PkqeCe*}Lu0DAX% zNYNRH-c~nX%OwP-%B<-NIF8L_NxSmZ^w4^Ad}MDnC#XV)!#bdFCv@_jzK0WI{=nPC zmW8ef*H)cK8H$nkRtLNrjTgSICO*mc4wYNmVR3k};&~tGaO0>+*V-YiXlBM*3Wxp{A1YX`8#ip)06XrU`$NU7m-yv_SMl=5>4hVEgkEH zDyxmC zl2pGfan^t3Em_|i9Z!Qxnf=y+gZua5jK*%=1EP#37#vo|Z%_eAZsGzO%tZY?z zytI4Z4*sB#xO*QvT-ZuO;Vw70_)c8&zMQmt_>84yOzCMf4^w&RY*B0)3#e9o3;W|8 zDFG=Z4xx&_XruF+Y0q;e>U5nNQC4pNbX&HqDIGXIPc;No#S>wd5%QGu|DkZa!1eza zX@?3Se-ipkC?c3#1n3*XaY3xq6f<_qWoZ5N0^cd^Y)$oC(Dg5{{neasyw>PIFt-}V zpU7YHRx7`#e>!p@^GqPhmP@dEpWHPd*Emhqu2PFMijS_*MjZEM@AMl%w|VS;B7cbq z0O1?Ez7>L-1#Kra`Y~OKt`i+?PFBO*fr&6j>6L6KS|kKD(=k(42>$=<7F!)&fB99o%ocPU_aw|GetOjWnCQ;^%>!h6@>skHGYa0bm zC*5u5xr67dFppA)zwyuY`{AEj?5*Ry6N0IfWYJ%~N%NHOHx1eB2?yNppl5#+o1T%u zNFZre+hv2rHz1iCt&5GNyeK9kDkLFV@(tTw$w{*C#(BUIQde=>k*V4hVh;7w+ufI4 z3)1mrn>E;;z@qK&B2U2X0tu&GtufJRv3qyrU{p7IXwAQbd6v?}Yrww{^G8*9c)#z( zT982OGSVDS7;70^)6NEZusdXT2TC8^4zi-0%(JY6_FE}kDp(@~ZR@W0TYYY5m&pj} z*035%ozr&WA?Hwb4k|Ryg8d^35{9HZ`9)@S-Y2jcTGh_+(_nD9|GUH?Eyy;)Qbeks zw=b`s@FEiT60vxIlz?J&1>#LY?R2|}{E$lTky82>cL^&eaRgteSxW}Bmk%FazW=R~ zy;~sp8qk)ZnQx9`-Ryq@%t?iSyooq)udZG!J*`iDa7&9-c*LDMi{Z>oKqE=#5aYTl z&50!dtLUr@I$Lm=dy~m+6Fcru7?|3y=Mdj7%s9-HcdPwZ5W6A=NB!&EOSZev4?b#F*o4vJY*Xw* z-@mZACF5V%oE7%LjqVDXuAr&r^loAOYg_)jQ*!5N^dk&>-c}_ze1`#iYuud5y9dVCW1NR3~hmHkA$i7 zD!q-%0j>gAv3XIGXm3X)j&ejfm7l4;#Ku+VDuZ{ZCY^2&mF1yhROR(S zGDNqLyQ(v(%TF@#FjQhLO$zAL8ZA_GXONvOXuBQuye%mg3EVZotKfS4PsaQk3japM z%f!!Z`k7~mT@_*%Avf$|7hhKoPUE?rD#g!1{JxE4-v+Y8tNya-d^X=^UPaT(we8~P zJdQFY;^&tF6W`EzERt>P;u>7g)n6W+HU8<}KHT!0{>a61_2WAlq}1;wwh=MjN?MAJ zl`0aEu{7<_RpDzvGP4xnQy&uvzv`y1F+=U~=iYugLvGzr+590Pd>;*01>eKJdEQE! zVV4@#nB0HVLEt>m?4b5J(H^(ZJAONpoB}(w4arSPJ~J{%CTl7EhaS&x_)CvhX#F>O z+~t;6`7b@bUhyw_Tim-Txst==Bb+Ib;Ri|NY6Gyyyws+RiaB`EPfvm5 ze62m0(16d8hJlqU49qNq8I(>AFh##rG=qdvLJuvAf@38Lf&TY+)Bki>ox#2_)Dv5x-HRkOEa z@xc)`C|vKBy80NseK?1DTY;gDz~Y>|dk+;KQZ%$>K%}RC@NtH^SmC~Z@bM4of8paV z%B`!)rESXp;N#&dEk?4~(ag3i!zkcq=l|g2<4dT+kN*=N*IxWLJ}&$ZK5jEre`P7H zlv;c>;H$KAv%di_VTYQqDuy_9~x!cwzbsRyoz_+L^I<`hSI!V-fx*PVR*I z7bkzp_{PcGwf|3?{H5u(C;PwS}&I!S0o0_q>3YnSUz>8*C@@ zKSD`cEdHYGEEAUuhTu-3NfEeM>A8+vN5uq_GCOA3B}eOkzt7X61j3( ze(Z-wj!R{GX%;C(77?jp7o=oKl&qbBtXE;a&(oH-Kegk_duJGD6DK&{zAsejV^nciZ}|_qwFkyd_0`HIP6YYiH=D zv1j4@c^-QQWGH2YwxsR!Uv!?dG{$kz^}QSYbMFWELWa{f2`0})e~dybn&{)@X^@<` z)W{H@I9X4jL^9PV`(Yip8nh|hkPgcIJ8}bE8_6^h6ZX_A(k?w*e{#G#Z_I(|)!T#$ z`3N%?{p9)t@AGH6RKrMwBUdQRY3_(x?pyrS@R}F^ml`Cv8ozvl$4TkvdXAOq? zK^i%z9gG?6|8BAC!#ru!{RHHozN=%DPltQ&aQVkBoE%k5hg;t+nhxgwBvZ5T zM`f%YdmcSj#vN$Nj}jr?<2_~C@7vu<2q5o(Ec!>Q0Z6dZ&=sTwZ*|q zO4+{a7MsKxnm+aTymyQ*Ii0tz*bl|$+-YY8?V+0H-sKVZ|B6#Uf&pqRPZt8xi>;AY zOa%Vt4|-6xJ{SbBMg0FmpS^K+)>-D6Xf6``JoEOaK~Y#0EwC;?l5(WaLM4-a$+Ub&+wXbdJCDycVjIk*Y~vs;_r!}zS}*uCtAgqYaLCSIR&9Br*WL8Q&iLO&cU zJfNdWWpXE4CY#nkf}uB(*&jm5FfYt>VxC%tKdKJc*o{Y*7Or9mw?x$wRYtZG9^V!x z#)QUl3w>`s6>h*We_AWTRq$hIen}J5Vf+@BgQB+lkgt1?WgY~R(LBj`sqg21y*nD% z?bn|UuE$JRP*dk=nCLa*Wga~cSUbmZ|Ku>GlsJxPuOmdn6uR4FxY^|Y-^}q(*%Xnp zK}kOFjmibpem#dTcwRgl$D~T>Ib=U7`NJ|#S;vj?d-7c?NzFRpBf%hJ|L4hXUY_e zOCOlWE!jn86k8(z{7M1|)6p?UA(d`MLZ(Q7*yl=ho&D3A)&7@U``EsfxH3Sj&()`j zL;aC7qrtIT{NWo4{5vm-mB$LvirrGY`s9x%r+uX)SHz&1u+Q_20(PE05fOVL2ilRKIdhR0XQZ?;=K_-CPs6O&%%eCJQyMV=3V$BX4f+?# z!Dxm69Fvn-J*r)C&pjsG{FzHxv3xc&>;&niulxLJJ46!gGvgQRv4@oQ&KNk|!F30A zMr&X@fsgD`i-ZtLn(5?5Wzx!a%(vJ+D_q!NQ7mAbRfM$^^OYcI|ELyEM*RZ(+xXqZ zz4w`Qh}947DlK8sgZh}t@Cmy}&Q!G;+F?UJC|$|t@8T0U*Az`{fSB}GTL%`)<3JaJ zNt^UF_2FVXo-!RdWsONYKD+ATP3geE-j!_g3c)i}?J$@=gB;e#lK!#1X54jn5;lJYvb@s3{P$%7C<5 z=&dWcf&E(5+JQtlrk`)HoV@nIg3PtwD3ROWm(9i3ZylncTD4^b2HpfFkhfE3qHwAB z`}J%ZA2lOHQhBPB-l=$AdZ{Dqoe3?Vv4F=!`=rxZoKf3LB8WNPew0Ct=9^8~@C>Bp z*-uEXQP#mUukJnasZ@FpxvjhSG93jmRzgY0{js&V+>Cq5545zANVUYgJn)g51F{ku z`O_;$?W+D%z#vq%4HDF2^{v>24+5gDLZBc(z9H*f&77xh1vr2O7Tt_<^}#yWL)g&b<`{ zW3Y$QZ#c|oiq)_mG>yi^T&KI^7nYHrIrB>@QiQ(}GQifKkT>uQ@KeXg(nPAjtv%5G zw1cGO;40{}R=3En$H0nLNdmA2hMvbW9ANs_n&1_sW~L+{0$oCJA;tdqW2w51Ni|@} zo*n6ia-G>X_rtAv@-rniHwJ4bVBsrLhH}MVBHZZ`1Q$k-I~`8Kv~H4g<6=EzRk9B; zM;>B`iZcU>Xo!TO+Gm*oX}?5djV6#@q))pqtS*5N4|p*Gosv|O*nY^}>mrUB6g%|H zz~jSyY*B3t7aoB~Vhu9K7PT>rLz+fZ6MsaloW+D|0(PHRkqbquk6PopT`lxCOg8w< z&YVn&Ov9im4tw7jr4>_3Ws=wI`n#R&+f3=uPpHkN*mdbwm?X zTN$O?yXzUm8=$O#kAuSAhwoqtW)6~#vT*XZ&k-NWaoc)hcX!Qr2-7BknKe3bC3>W$ zAg(c@dk(nH(lj-(UH&#leo+Xi6?46=KUR(74583f2f< z^O`xR=+&_PD>I(q)y%;(pfqN-YlDv^NGoGCew~WC)xqh-c8IWpF9l0U>pY#>sc`;7 zeb0`5UG1I8V*;Jf4~YNjC8#mZUI#0!>h`BmB12-EZCC>hS5U_^vxA%kmB)4UZCup6fWqJ;5}&b>pZ7QC zyvIEqN|XlOZP|>L5{jwXFZKH)nVSc8+Zx$)Y5<+_B?p2V&%pUiNysTjrZh(%nRIfjl9tw0>=57Nx-rz$VYdX_h1&ZV%V(lb4+1dWsgcgZvW>ijXr9updCImeZ5|B=AP?D*;T| zR%ots1g-W8SP3*KnBC0TE~~sbJu`tOfUZzdU#)%k17!_1f{8KtaJSDE99TrzA@GWW zTYd;L^ap|itt-ZQ>z^_s)2A(=VoEv-#zY^5!j@J*GTz_zxyq}OK3Iwb6M-)JC0wCj zxz^r?Q=3Z9oRQ`6rq`SsNuxdc=>MjNv(KNrQs2^@h_2i%9Wa) zw`NwANq#8$4`Fb)lc)O&c%iNQVaC}n@w05KgvSDi|5aEj!UwdFfBwU z4jMDGsex?9S1ggSRexhwxFhP#g{8$Ehcr$|_Nj|X?Fn*Y zAD&Z0vs+&K%&eY0|EIcW0LMXRh<@pm+IKy#c@<9!J=hblm&eP?N3|;5Kk~m!rITQ6 z#v8*t?0k@-06g0dyasydU;zLDC!u_}Xp;~83^y}OPHP@|Wxe&cyLq!~^5(n1lG0~4 z+cFB;z~jCumqe4R4SHNy2(=5T+W!%8~8CjRF{khCkm>hamwjXDxJrxXXhVtZ&O4PRl+vcvW-<|`*2>;uX=ozS_ zN$MiU^c=wsQ!LE?$8`?=0Jmq!wuBdOZ`9Fms8FqteyuauBV`qI*DO+dE}D z=DV+2$6^p~%k>pEbU`L`3eD=-{x5baD_De`CVS&V9IpbuYL@ZS?e|`k1YPTHBZn!d z4qpOU=4I}UzXi;7U8eM^G}Th$Lrr=q?$v-*TUGybUJ02!Y@Vyvn%+1#k!dib!-7*b zUvwvUR7WR%V{qKTq7?uCwfQgo*!*{w{;~PL4{GQ%4q#xcVazbNA}Lo*yL>%hBrg73V8d*%FY zTDZ>5D%ez)@ZA2%u=({`UWjjH-9tTlk_J1fLySFVM(d{nG30Q7Ycm=-aT#vvtUxo{ z6Vg9l1X>ud(Pt-XaBt8rLv6uwOeOHsL(p?gy7aFq&Wv1=*heNzpQhEQqydZM@3p(3 z#Y!K&lx8kt;-gJA5`?bk=C^AgNZh#1w;L!#JQ#9K5KPk(XAF^1O3{3)HcZPRr^Y~a z4zg^(`m4Ca+aTrL$Yh4;-vOmzg>uu^u|}6nXzTS&W~F*VwA#})R}R1rozzt=(1*vI zSVj`{jT?Emniy+Hvw~AWl{M0<%#?|okRjxq!&Xn!NuyyyTWctB#VKRMiL?pjKtd8X zgVu$%Az*6PRSG+L7{HPJa6TkeJmJ-fPJi%c%Z6tr>8jn^=|Ws?@c#8?(Vkbqvv2Ye zt#hcGNh9N@`f}s_7O>i%=kCM{K=_oDVOTnO8}Y#QAbvR2w&DU_{Vd?qUY-sSWu`f8 zBJKB&; z3}Y7igNoQpSwq!Cf(A08kmnIoZ7sHPM;fCA_^-d8yO{286r1BUYn=oA0ToeXib+W1 z_dJK{tkLY5{H&k71S8n0)gBw%^^CL@eZTUfTd`7u##4DqYK^qt&yo zW9K2zL@Qlg<21ijp$mZV-1w7$58m!JlK4kfsV3yco-(%5r*767a{+wuXo-bH z>@7Rtp86w5kSZIrYVm}WH1jQIcCxTnw}cn+Hl++y*r&4SGH#*YJyW9ldEeQSlW%! zb*RYjoqR=#AwlE6;VDJ(-kw-V;PU`c17t=#NU!-!iJBeX#wo6V5 zitOkqMDU^Hku&5xoqYpJ-zF&3`F3HGPD3G}m~(LPMbZwoFErH=XpHCbb%f-V4YXDq-~&Z-quezK1l#R2tKep8v+VFtD8wMarO z^g_rLP>*|*^_7%1oO1HY=8)Z?dOH-lsL zn~qypVFiOnxKR_fr)YLvF~L+F)AZDs<%)gsr`7T8FF<^@xbTl%Qk1|mL?+dl^~yV) zxqNZNi(91+rZW6(xSVVaKJ5LErziXszYR0h2~qVp{11 zsa4+Tb}?nGMC+)X-yopNx$n}@Y0lugqniW@S1%R=-PMWW6Oq2x(dn6PLJ|@cRI~t) z3}oSa1cV!48E`MWjn_W6wwW(noDogGQcMthCs03d6`7ET!z{^^%xDqKlnV_Xr7<%R zYDY#Ra6x9~sX;X#PzYJp8&5Cel3-mc4J93|N#9)UJg1??#wi|}y&Vd{orY(lBwrMf z!aNFm3rR9-$kS6Av9{}skJ;A(P_D;q=*^RQU-MQ|wwlG8MERz`CvZLMyeAll*&k6b zU_Rc&dKEkX5ua4Gg2hv=vD#aLB0dX4oceCF1&Vw9!NU^|yl`UqY-+3l=k8c`j3cZF zk6}{@d~Eg#pW<7?Mt0FdxZ`NWbx5hX!0(MxM0B&b!TcMFO&CBQ zn%@$fic#`W`DaM;B$tTVc2Eon35Om%jFr?B8Ssx}abKGc#{x$9&<_?57RPlhy~gV` z&3&e~+C>8uE)E=AXq%4afuN)#NzhmP?7f8vy@6cFRA3mBTg!>PBvnm zgqq$)TqI5((YFp1_&I!q9igIo*ybz+f9aC+?A7iYrbQ>(a}qPMJ1G362>!A9KuAc6 z5{|=j&2oV)^t0h`FzSk-Kr+rdU)*L|4#Qn?yM~jRuqCprQbkcL;S3i_3}|I_8B9^% z^Dk`>FaMsA4O1wA<%=T&C*c&o5I(-N21RUWE}5)=iIC2G-q*tVwJ~gpZs@c|_`74Q z(uqRqIt~^wk`q~4;aLB1G>9%ytO=#d=1$Be%D4zW<@lxP@2DUoN4&)$FBkqT*({%% zC$$@wn>BGRm(*QxM0;k?a0fDA#rdfcHuV%0;4gPan1?QxaR5wDJAr7s4Pg-*o-NWY z`YjcU6qX)0H3f)KRXNd*o_f$OQvjDy=yE7=f^I>FSaWL#P_=7|rwOV9zm6p%1*vxPZS;p3R;VmP+$LwfqhF%}7Rf zJl^qrRksnY62*#!rDAgii`kA%*1iWC4<1Vh4)e@;d~?4a# zHuE$>2s{^BEzN?pj=(*1hB2f}VQ37K3G|+d$H$W^9Kx?#) zaifEhDVgA5ARpXenHjW%mTF{B?xE-#EX?t)%TkA)fG?ch2`GKO8k}~$TrC^ycN^x& z9`XXWAGAr9x=X=SJjg@h3CEHJh~Ji@>tMgVnsGja1dszQpJ?1z=z6zjwhyd@+@6k~ zH(1}C*k-Z+m9;O0tf?nMZyPT%b8sTQiI1*cL3uvUHulIB?1{xRFt2 z%BhSW_a=@q+FJGNpW$>A1%%QMIu$-swA(Ixa9{oM)7Hzr-jP-1@$GiK)7pfTbYVcu zg`csba+<_-y7bv#2dERmQlu*FX~#0`+TmviVrZ>(^B%sw}Uh*)da(5 z>?-L5kP{2cZDuQzO1WmRBs7m^U~*07M=wlt*U={e;pFc6x;?^Y=kNA${JLb%(x4IF27s_UXRlZqK0JKD?O^~p8%2L^zsM6ah0`9C zGw(higMGCzd7#p9E=%c=feRNE20;Awd`ZVlnkvWo#PKB0yOm^<)hKGmrM>*iet>Ck zLRJ0za17^~S(ccc3c#yF4-MABUb%S@fJfC?K_A2MGzP?_sDQ<&+FM3X&1Qp(e6ru+ z15ri!oNUKw`aT`47UkxkRg&$jeUE6F64^t6Z0Vi7a~I_Ki+ZCsKH?RFuTIL*6GMuz zc%LqZ#R;-&p9nuL{n+Y& zBf-*2f@NqqS8nGm=L701p|!`6l=_aI`?2xp*VF>~71TF0tJHgbQlpnWk13F(%V1t# zvE@cAoJ>YRom}e@>pXeR_ijwjc04>O#d9_PX{>al9|J=3jPMDZAQ% z4}J<1qAIsBD9R(mnTEx?j!@4&8L5uoR@z3>K!zw~P6B$ni9M@Hh|Oi9OmM1pH*$AN zQHsKasHBi4OFWvz7RD#bH z{@`|3KceL&|L+cyz~nh9vtJg~-)EzVPLP@`2nX2kW(T#>j}Z0KZh_Z4MB9ykIbtsS z><}R5d}k&IfK-1fRfe|m-Kf1AUYz4s-+!OrB4bF_iGiR3H~Fu})2i#DZ$?|SlQ384 zwJ-RA=Fq3IZRxlGITxwR2sZpuC#p??U@IEsr8w=dQ5hhRDZ4$fH)B0-e}Eb|%bG#H zi_(Glnfj{&`n+a;4#CX}*E{3~0>f0`(N}chsKEpiYtmGoE>j1BGRf1zl}i+!bl07s zSEH8ejG>!Cy2deg+EQ4W0|r6lsk;g#90WZhF{Bx_@m#LhWCo?l#k8aBonHRBbe=7{ z*g3?06(}+9<28qT335>@EHkB>Gfd!ZFUJi(y5b#vjmHiNX{0`4b+*;Q)rmMB5bk-s z4H0o?!h^12oymmuNHK<{JW&O~o6@v7QR52>twvMR5O`qzkhYWc)ij;r1l#>b>MT+< z8-y|GK@sEa3c8=%N(jye_w$6HDziy(j&7CEwT}+kCU@eJ0MA*7?n09wfIm|UWQ)aG z)>;H5Ln#TJ2Jl>XO2~l=$fsSaf6Lyw(UC#!jXcij&@T9ldwjZ*jd!XnZ$ET7Ggr^@ zqFp+s%+nF}oclE?ARl-BMoT;L6yuHYyZ-llnD^v6Q-4J7vt0nP1F1{_KDchq3ZW;n zWoK)<_j}Aadx~0%CtTZc?7xdJ2MO}?`cd>2bsZ%=&zaI%%V2LpVw+y*`*kU6oc716 zaZeB|8HsO*+F`KJ{*{%Q^A+&<&jiHRVqjUB`sYb=3eNZ2yN|uIr@Qg-h!$?j)00^z zM|DQA@C6y1_PE(3!)NWKcJ*M@?F{@qt^zjCxy+g(04p_)Q_ znb=O@SM5R;MGE+nd)`>WdmGlDhVrx1KRWXi$z@ zSe|^_X@e>(2&&>ogR{+AEK5P%`7>Lq*W^jCC!ih!(DBMrGFPiG1PD_f|Iz4myY0F| z;z!qJPe9T!n=6TS6?k*XY^+gV>DPA-g|Cw6SAKi2-u)xs3nuQJwnHed_%z^{F>$Z< zbz(cw2{G-VHSy^H2qJ$13@V0=tKH4#THcCKcmjJa0hlk$ImPd2TGv%fU$ZUoclevg zT`CcJ%=r^s3Jjry!4GJ7qEEJ9l+6b{JI>GgJ}Ux#6xqx@ZDIsGGb0MPLzhxS zH6$Tk<~hC6vNiOca2_!&dyt_#fk`3zuTGflatE(>8Vpads*T|vAE0RdFFD+qp1A2G z^)^ZS6~57SsS>J-#Ow!!Mn%fwH`4%k+)JWVT;MC*nFu{-UqO0SwC11dC(%|+K|t+` z)oC6}C75&IvR@3XYv365lm7^^g@N%vqneL%cf?Vi53;GeUr@Ywj-R!q7Go&7Jj^}O zSPKhWJR`RjTNV^HXy&nc_ zeX#Jq4^K|sQ}+44?%BoorFZDRoj+3cb3XWe9KF1p9zM5qeVskMZ{>VG=AZNFu5a}C zalNPMzEr9`^joe|j?v|iW8P4Pn4{v@n*&hFr$JG&=X~9{dxAvto zj=)3ODJS0wyH>X9&!pm;_Uscj?ndUXSIJw13RM!B zV#k_ooSdZ%Rl$~OBjw$^DuXL3}h9VlQ94X@H?3#hJ~2 z>NJD3Xkv`3c#4Yd0#(QMH7GjjWwR5E??yF9fobBumPUqY;({+9IsEgM#C*pKT2OD) z(FBTCB73k29At@Sn6jCF{?6BlC9H20DODK(KcMZfE9v%F#aHqypC z6}r(6|6O_@6ny5{@g5?Q_T>)frEGEK=Q!6j*l{x9{;n8lA^2Mo6!7*D1;81T-1+`( zQUqZPp5+&iq&mUTZ@##GrQ=aV9A83_Gn;D#Vg{_Hfp0~zr;vg286M%RfNG=B*>se( zfniO~+GZ$d0pY~xyCI@lZ?1tQxC7FpEkgjSzE|6ZnBkO-0B>I)b{M=$!-^YUO=4L- zi8$j^)t(FmM&cvZLs?+34$X7Ckzf<=RBR%%z>>b|HGhVP?PT~3aIm=EE)_I9xXvYl z)_+APkCQ(hL>|$**iDH4qTWUjekutyxh69(;6KY=(N*hIUFLjmCz$& zP+oowmlG|ZXU(X?nUz`)m+RPmQ4uLal*u+FuwA8hDbYpQS{&RjCk~Bx@}y!uu_VQtO?~Cq2IB z#H6~&=<3E0(RiiJ`D&jzD!lHLMT1ay3P8W%$0c+mcEbwbU{e9({^KCQdi%p2D9y>l?F^_NC%?(^TFgla+hT&ZJ z2fqIwb+_N@KH8rtu29WyCu`@|-P}N9Aa0*e@5334tA8lsIt;3?OmVgs5Y&(pBsHj) z#|{sKp+gcELh!YUOvcQs#1bIy+^ja&I_X>K#)=06lU>+2!|!Bq>`xw;4oB#qq6MT@ zIm3Q000dS(-|Jg36*;A6-|ZVyu8+Oa{}%Ui@yo#jcw6Y11`y^hS6S)$b+aqjTVUy+ z7UEfOTf1EZ$*3G0hRdCF7KjJlHtJn0Fkgxprz0T3nx<`0rM5J18`W--Rt+-K#Q7H?9wJk5xAXhl)W>UvetDYSue)=gYwR`3M_bhB~B$rJt9`NrXApumxyPtn*> z$U4C35hcY*TaLe&MX8Eg8@9^9-DVCS4_`hy^CenT%Oao@I7(f zrE#B4bIKB4ewO>xZiZ{b_5TDK1pFIidOqAaz2Lr=I>D!83aXnN<_k{V}EcEjp!n!qgfo0WV(#CbUVM zW%q0)WD@NYy&{aaDVd{;^j#z270QGc-#O=yrP0NkWk3*5V->@AN=;-hd&9vC3Vz}GqoOM=s_6arS@7~)3#%*vsO|< zi@ozqn4=7?1Q&!k#C1u3mnm4IHU{nK31Dm`cugBIS8{bPp^hr_;vl12 z1cUBQ%J+RS*xZHasPc$zpx4#K7a@Xys_SoWPapBV@GfUBP(g7el>J!OxWMU zlUCj38LdG!zJzZs(%L_?Sq|yjR&(T3LZZoF%%WGeKZ==~8vR}(4PQ>TQ#|`+?zLQ7 z(koB^s@fL(7q@XTrKBC>FW8WaD{^`lBEYlvm zhf~EHJl4%qlMpBIt;?JjN=9&5sK zo>ttbd-I{T3$H_3L7!=oH*Ba?y_Xg!$q^EQJsUJ@KXpc}Y+r3wt5bFF&wpw1A#gHF z#}dkGw8|) z^-QYO2H$Lyjf4eUzcfy@sA2tHmxkgD#U{d&D1@6u6uKJHYUj9t z`{^q(&t1AEXgy2KU*^O;VBI(w=js#j${Sns_CV^WQ#U_=-e}f^QPB`&32*q)QWpH%0Biz^}yHa0y z0kwM40zpcHx~I93@;@y`bYi(FwyA|T9qWyj^g}qhGe1i73lNJ?D+!|x7jKJ zF(D*KRu7Z$?f zI9bDL+yb)0kMDOY2AU!^C&X!4n0b@d3+M8)$A0LMm6Oc&csw+2&7qTMx=b=g)?gSU zHsN_}!}N3Ov6X;@BHwSixvg!!%2cOH3bmEzA7@9ywzA(Iw=&Pn-MOnoLoFzQK>T3c z?YYm9@`})3*K3DwI6<7zuCb@tl>=H}l`Ya{>jmtX|M^()M()}KXD$8Oy-L8)T)1LQD zI6Qg7W-;#PL44W+Yf;ecg`D{amKHz<^vS`_6XWNn`+cKZwz*7%fe(PF&gbNwePl(E zvzNmrU*)o7)|0S4>ES)iOsL=C#CP!@VV%UjK>WSe^TF3S3v0`k4Y6z5y6_yiJzC9X zVs$L6@zR`FUSUSY*Dy+|MXn`m?sdRD={ir29Xa0pNhu939v5h~KREHGg(Ijmg^EV* z><*Br?LCt+=C0y@lBAE;6JtRd* z81s78QC#EeA3AQqBCfxYJBaFd@d|PIBW}kBk(5E8I`c(x!OPsccuDc1CiUXHhBH?L ziVXuD_LpeTfg$p;5ZT_IKD_l6n22Q~lNuh?!dAfe8`(Pe7k@rZbx-ZJ$ldFHEjxLT zZFqobOH|zAYPqPkzggSj*w|kO?U_ieRZ$2qrr(A7N^{0ADSt>#-)u= zk5*lE)2nZzSN3cxuAx_6LocZjo4@-%ip|Z9bnAQT)&A%7Xa5H%egVDo40`@^>fQI| z`Tg_6er@#ghM@22zmcwn6!AYN0Hl2tP(LrBMAy@+%OQdN^S;7(xBlnARQ=EK|77)j z1O87KzaiP>zlnR~H+_E6!Tz&;_3{72jWl%r`*A-iuRQ2nH`2LNIMdh`U5`1_OhDn@_&&P4u5Mne*|!*e)M3OD z%nge3W48O`Lz*q8;*gRBYK8oVDt z4=1Gxgar`EWq*!gx>k^Di>Dis8TaamKdNH>QLP)Od=SiaFX3D{)(lI+-FW0%;bQDd zC#zViOY!Vr<{wQs<1e*#)E7vHW9D$rUl$hoPpxvu+isu$L5i+CQy7If7;zwf6Mx)M%);e?(WuFHv1>=5e_Fu{nkmroS$P*GgJjWz(z+kj z+?y+mz|cN4SIzw%ZI$kLs;`92LbDR0t9wunH#E2HFc}&)-fWUGXy=_fVk>vE8&cn# z5J}D~B?Bdv#%O9xIo3R4fBI@1l3f6OJMMZMcgN1YUUDNx3?q;gwv8)^e>EC-CvsRS zDSPwR@X%rvtZQBFZt&P`PkMmE!Chc^1ODlJ)S}l97oOJ&By6gvJxZaR$C0p=PP$mc zFW-1v=yu>}>c{}dl^>9qr?EUIMJ@B@xW|l4#6Z;>H0c*dfUtScqzI5rL(o$iJCCx-7(6m?^k&nSIPkYdAw6L%#UQK`d2MIL`f z@H^9>$Kh{do|@fw%jloD-+w?G_%kJ>Yy}jvCe@Q;nF5QNv4@7V`38Q;L>QhvPdUWL z$_{PW3tJet8PJ0$Sm~m(JVCbNz8r*l32i}G4zl)S;zij9Xjbbo4BR2Yw0J}iEapCj z1CMgcot~lyO(T1;5Q2$0@MWy70!)jGtIRzn$LwV0aUL)e?qKR1}DyNk!?{v^MR4-c=ew|i1DDG97_ z2el%3142WCGHl*i*aEVhw{Tzc$e}QjaoqG;N3WSHYPjlR8C6lcs>2X;b45xcQ`IyL zuQNXT2O9Ow60rf|_knzfafn2NfmT~&s!Usb<)|a?dAEJGkVzu|$K}JmPo&%Q*@prg z`D2JUl!Rj~Fpkt%8u;}69GVczXu`IkEZ)Q}vJCa0zrI$QVtk_wv|wp-fQAiw)tnz+ z3pLDTHByeBAH)(vPTx5=_Y1b%UO*OV=m5H_SAt#7?vuXFB5n&x8mrY`{FW5MRQ<*M zD=+Yqi)?CzMQC>-99T@TPxE z^r%x9FBf5d(BdH6LwsF=DSK4`wA*?SInzxir1Jh!`lhIFwwAM3f0k+d5=TA8oGGR) zV^BIOP>G+^0(TKGLNj$miLTtP(Rk_((r1PE^={{6#~q;OVYNg?CHHP(&c|YIMV~FR1_KnNJ8V! zxRdw6c`bm1!RSB$KGAGwFTH?h-F6V3f##f)Xj8KERt|{3(t8jG@2V1y#%GxI)l#0X zr_|P;enkH<{c}ThJG~D1(O_M*1~iYp!7yTrd&<5=Mmm>sov&wiI7Wh(W7Rmm=Oji#T6u9`)lf4)|cG zCA~~1Jj%9(hRyK2pKpL|_VzPzVkQ&o>~Gk2&?oHsFDTT>?%jN!5P5#?M}%$d-U*U> zaFT+XP}hs6N~Lxyoy%EI8pfS^lnAgimDaKmsL_w|}h0BOsI#~elcnclX)=Xha z$t&k!>k=A|uDEg;GE2*VJOhdTVT0IO)XpGWPd6qwdhuh#O7EdrT>A82QB^!7nhQmPTWl2ZEP)@@gqw|g-5ER9n(K2!`CZQHc$$YK~FUK?Y6gD zXi_~*-`8$1lGQSnuP$XZouvHA-Cn7{yef1}KYC{WO2}z)(mJSd*{~VYni!jDwgt;s zDzuZ=fo4}?AF{(~oYa?;&V1V=%T1eadRd9N+PGU)<+@|N2oP@leBSIti0fH!!794z zw}!R)RWE(!J_7XpI<WZy70)ZXiif*Tx^TcpD*U4*kt00+bG4=(HOp z$s}YgQrQTwN>S1jiG*5ZxLL6w6ANzEjzcfg)n z7o=i;0n6sNu`A^PCcsB@xw&{ad7cOu4Az8kkGBnjv>G5M$II3G+u;$DvP#$^pVQ0$ z3smUU6$I3r3Q9u&{>oj_W2%^*uyAsHoZ5+`jz*6LpoD;ZZXBS&q#QU0hNaX8U&*?W z0M^hJsEXAn^!?2@Q$;xqpZKZ$S3a z8r5fD73%3{#aJ#s(!ANXH+ePUl81k|P|MDUsPh$KA0OwamQ1#lzeUv6Z0Y7$pVh2B zOh{j3fB|2X_nGAA#$TenDyAjDo&8f_>w4S2kCfqCP-Ofmu+d_?>-K)7FcAGi7T<5o z!11^FmAi({0)1>So$3WkbZFIA&kc^Ae)Vha$4g*i^uN6Xm0%Yn8ypP{4vaa8ueXI_ zFtb{+mJD%KcQ4Pq{A-)vdl|j!O79i|u6s4MwlzH#k7U6>3ct&ZV!euG7XBrRZ_KY> zU}LzNi%WkIS|WTnY0``W55~(*&gq@{Wxe%wdwcTeF{cxI(WFjvI6kmD!V`UJR7KH@ z_FDs+3$==?IRH|iRd0h-Gkf&2DpUeB@wkh$6ptbUfUZ0eJ7e2j;0XXG8Zo+OjfLq@ zf=bW*o;ffH8o+B|ruTGKBaHb0i*ujgA~FtHqqCgyV%Tzxn<$I-F+15C4jX7>l(Xq` zn<_Wl@~Uhw!B}OZAVCIpWr<2Ma0shIs;%0Z1H=5<)7s$cr>sKiAWwS_ngg59(<{K3 ztI>e*soIwHWJ@QU21PB-H({L6&Nr#s^6N&|YAk<+b6j~>59eJogRv}REKM4+8;a5q zSq$g3qHOUw0yg}@XNUt&?X=gcp(IxRZ|mXx_Uz$t&}gIrd+9a+A&Yk9O89`C!7?&n zuki}PiU)VbWKqKe|C@d*)roQ0QFZ2!*&J$X%JmOL-MPz7?6LO)3*6lv-$e2{^Cymn z7qVqFd)K+E^FLmLWxCx^Xy3izxaVB^lxN{6#`sQ;Q}D0Gj~zPjT@4Y24NX40elsNU zHG{|nt6-Jp4-2GnG2Q=bG?1XlS$a*cY>!*r1jyO^X+cESQtrixoFU*6E=0FC{2A6C z-Xv7TnAwX+7Oob<`7D6@X&=~pM>=_ykd?C0yy&*z|7Wtxpt+Vjb%)?*gB5SKIyTAj~ZPm&+h{3r1JD zurVeO1j9u1{{XT;O}_x3>q?5>GmS$4gJxffX#iOj+Z!V z)We(OMesX^tKj87uEKp3O&d1{4JAD3?;G&Q{aYKg3R4?38Pd|%UO!wA!S3x{W*M_u z7#;Z7xAxW}HRd(bn$FpELaes$!*6^+5ZG;w8ybWbh@lfciHjp*Tc*SXC-)eBP}~>> zHwqB@A;)GF(5qdD(Y+c8*A&lTC9cS^ykW}7RB<*VGY&NtP?a!3SYC=gL9LmB?K!K{ zZ?pRv{_gf^R4phP2u2!O_(@5@#N3_`u(*`w zrR@gMxS)cU+#n%deRelZeh$EoPI7jC5?zCFA?MvkI_q0#mh3{?@UnK&;oc)@lZAXh z8-M-DM78ymtm*>$g?|~KifYYPu_pTXe$MYG+|A&GAc# z;60%Q*MN{PEo9amMJIQIL>aQH9rwCYA~FB>y*p|$e+eZet*W#z3lwrI`hbLR8w8dB zm~1_wBK@L#IPrCIu3n2S%^?1mEBHGEo)hCGYv>sPfFRJQNCn%OGB_b%k&_oY2ot8~ zL$~NDLIA4iv)d#06z*8Xl;+w>^zY#Io)wgrQGj9l#JhmIEz^0p6L&q;W?51aWK=C$*QvO+*gAINXVdKAmbtMJ!F}c){ZyU5st}zVB1$i}j^|IF*-?FS$n%}dxt|4IL=)Ig>ORf2|fNXdp z$pv;oT;EWL^}^1iilM#|S9OFhDbA&`gC2hh$`PE+igI+-Q#nH3x|3b|UXZ(d=dYco zvuXCoeKR!p=s|Jgp5X)6j2wYYxpK9VF$M>Aq3w$is8%1@E-AhK!keVe2j@0uPQmfl zMtUu%$cyAx9ClnR)64oVXC&rEF60rx1TUy2LXwhENJ)Z@u#N$>Fa`%sjMouGLd zdpzgbu|xaLoqmX6*pen2ml4I9f%$Z<{IzOq;gmQK1 zR7=t8CV%ACSXTORd5&L8oE(&ZBdJ#2qjU9c677Sxw*vlw*ET}cvLtW1naf#tygL!F zx}H9@vEr-}P?R@^GT&>r43M!02jmFHJw%wf<6YAG;$5Y7N%M<$6@|!Z^<>2VD_hWe z2FQH8psIju#~UOEnbw9danF?$rF{l~4q#b@+ievkIZL1Ozo+dY)Esc8W~g;`Ns2{L(}uEpTi_{Dn`Qzvu;TP_CyKj=j{%hzEB1VQr!_Aa0DeEe_-o2T?EIXP z9#YB^8uEBLuD<_U5i)1pKV9OF=9&rQ8L)3mufuIZk;AYEon%-{E{7Ywu$sx_aBaV7Jyo$utuqjIbk zi?9qR0cuC;ZLo)%7QEn_o3&uPjsnM>&RmwRicRE^5Ce-6;|q$}>kTzvyn&g7>X|O~ z>gCKYb=3%m7FH;*XR;{d0~EUB#E~DXTY>jjue88ucTgL+R5#e@F&2u2O3>%$@;vPe zmz|(!qc41`nbO_AvPwf*Ri~h0;fOB4g+?3rfC@|-6O{R90uMbT1E7Boo&RNw0d*YN-<%q2@~QQ zP+p1}4JaO<@FX_uJ`Glat5z-P(hC2mS?{cdl4j7Ru$d5~0(8a}*?=A{D<+y_J#j9L zu|4hHV5uqmPmkY(5F8UkK6#a_j zK1xDG3b~whbSHguEGWS7q1QkbFsP#L$JpSIWDvyk4zZ48=&}e`H*6pFriq*{By=8a zj<2xlPZzD;F6r{}LPCT0GZOuJHymGI8HmIJ1pph{Y z@&U@5xwNWW7h=Bwm4jTdd!|Ny-f!$M*9oJ@U``Mm(^xax@L59suK?ja`N9MBCIecJuHrva~|C`8rj z?zV9!+pSjPuC5*qE0BU5;3WmdIL;I|Jfp=y$J8tT<*cZ!xe$L}F=8Ghu7eijjx8Ug z%DwE1GqF0%1Ba-MUpC}dS~iA$UR5$hrpzZ%to-tFLQcgJMNmhpGk9R5jz%EEQI~4n zP$vugdZ_8#g<^A@*(z$`p?m4<1ID>;H^A(R$9e@T@?_rpW|yNlg|7gN2+fxWlV_*nrrnkuLKpToPOrMS*&R3n zT4cK2&)TIRwsr#=p(~PS|E_5P2|Tx|W(V6+hp^TA$?yK~5;UT)qVc>F`|eyawbBwV ze;Z#OPh)S^xRj}GHoSD!O(1k90hd-96~?}`&!bNo%UL`EZc*dfQ`YT>E+S4IzK%uK zz=j~envzjvU;VSl5or1E#HmD#$yzgDeMy z1}Xu~-*-*t8oPL5PBr9eqblgP-9_v3j2qI=={@BIq)UPcDs?OPjGM}&&~*u`=n@W? zE}a~H(bc)Z5tOH>79U2R?544tF9j`m=8xhOX%ApOEriM!X}%Y`&a$kHCDvq1+_|Fz z9hi7@(c)BB_Ks$zSc0Fr{Yz${WIbOHO5oo&@S|?5=h6_G=bF&a;*T5DxN5=wU9)0I zc+P}rav9oFN4>wVWyh4bv*sG2ZpT>ep{$*|IRZ8QK6p?b=)1-;PNp0-@f=b>|BavQsrp%S^}eiJ83SZ*nrP4(UT3JJ>nJ8&9Ox7fu1DmJ_!1EtM;IEKkV`?dEFGfcJEKPgiis)F z^;9#1!3%5RxfBkU?@}>Ua?`O^C2A#x3)wEP1qj}* z%+Yd4wPMO`Q4jg|=ujkcCF{!b`lh+Zczg073c;bp8bv0z)`r%j zjn(6-79HL17=4xsF*|XzgM!UzwmfLBWJ86Qa~SZlDtN{XuE@iCc9Tf3rF9imvuz0px`k!lFVzWa)_rj2l`1n#9R(W zbg$D|4qZ?yHrwAu2N*;FS8OuKx7Zi)K68bBB{hC447oi8S;!&>4QgDldsc)cSZ<~G zv^FkrinwGzXdFKVwc3=2;<#=t>LAglMix6n7#BJFLT<OLkCYj=EC^i>d~CTTsvF?l5+SB9E6T`CJ@{#JTG(gM_LNIenG^OsbN zknUG5WJU`pJ4_+_Fkk2DoKb!gwOfGCtl{SChFv!dpkCWfN%5>;o*$0x;}n%*QNnF& zG6@J2DHFVIgB!XXv|6d+^vQ$ztmheUf`ABUpDfqp;2TfSgUO3+`O4R0^{ zZ`uw%0FO=(G*G+mAhRqbT&@RPp}*BrR$!d~I@Ymz;lWO{;1#kdYTVbmvIPi-*g@jX zs9$uB1H8fzihO`Vm#;3*!;`i{eR(MGxHECQk89LAzhKdpGUv19 z$|+hI(X0d1HY%2Gqt8lTNpGK;TDrEOB!8O^eZzDiwQI^2^qx!TqzbRkUibH%n%5YT zUZP9$!bEEJu7Y-ZE}!FCLa4G`1BR}Mssbpyj+3-li}M|0J+0q8nNmA(*xJ#`h3t%9 zcj<0A*waE1Hk+{w;A>d5U?o$uXfMb0X8Xb#QOZ6VRPIVzb%j8+O9iti=beH2QH_X7 zi4We0w^EwdT!S_Ux%lJ&;~WQ*4L(T!vsB#kojlT1Z$zjj-{wQJyw-|}5QSib38R*k z9{_-el zUEWGuU!BCzJEp-DVtMDRZQ{}ls7dc^@iUPvaMQ0Oy!CC~^~wgtfP>+=V?4NlG_wNqtAJ9p* z&HcaK8uyP~r1l-P$%@aQWQIZ$Wt0jHto~j$>}3N45@HmnZNG(^3z*Gk>^PI$dBoOz z3Td44BPhB)D>8J^R8-`$Tw9a960Cc#_2%NFzLu`W(tF<2fY;L1VY2e3p8IR*5mjLK ztmx?~{sy98T!#yUVKKlMO>rWxc-49}9qr{NSF(2)<*h6n#;@PJ9qbd@`+yL^t&3(f zdxto{r?dCEv(mG+cdIY8_YQi;r?U4%hkF~#aNDxc&9)EfK7*ic1UN*o-Fh5yeeR)M zsB5znVpv5`QL`8k#R_Wpy{}3jcW6K#wxFE+C2XSGSW7w}61*w;i@$UA=GOlnB#e9P zjHDv*Pd7rmO6$iB5T{hPYz`1_>k)Jd8n1?o2TZscKVBa(ndF~r5P2P@c)RgrpScSm zWF4D&fT+V2z~_M516(9rVCq)54AjA@2 zLI@eZP0n+JQ$W@#p@9vB;^Evc0t-~5mLL;y9l#4~5g?d5&g(}#dS6G%W7mht#|{cw zi)``fUePvQ0qj0x5>RqyuSr2Fs%Xhf$NShM>u6@Sh*ThkRLx(7Dt9+Ebm{B9VA2-= z0Ni`Mm;D_$2Y0{j)J}RyJ@Lk!kz`4q{&_p+kL~U++jczs9cOD=aruP(?KtMWmEsD5 zX-iF8^>fG7kO`B1BpkK-=wyG+4RHV4a=^?>P0thqpdDJ=R4m(tRs7ZKo748JAfgc3 zX2Ia+5!&kmn=YihOPJtjLmz_ZNoqdVC+>}nEeVbZ7X?TxFR}rX7PZ#Ijgc(u49?P3 z5j%BYed|}rRad?E@A^rnVaBvh`#rnB@{|O6#U%$DX@@@0trEt$0`3YN!(Wt`?$*qIV}nl{nsAQ(fgE}a=?JI6AZG}no|TVJVhS* z=|@n0uJEwr@9cWw@nZ~BKvogs%|A|RE_~Uz5TGM|JS6lOuVLc?esG0IrAU)FoNFZf zX6kk9o|8i2yp#d&GwDV`j*6Sl3Ouh4Y$s=htmLhLhhRIoD`a#2%DU{IJYEJ1d5YAh z?Z?6repxeh&og$KWwI7qDNH?QmO#|7{H8S*1}5|HQ$h<)vD;_+7rR2eHxohRb7gDp zy=cQ|{m90ADC}aAtB@*>28m;+zH6GKG60GWtS0*0k!VbDT_=xA zeq*J8rNXKH^8Y-)+7g0@7dj4IdEw>^CQsa8B?i>DOBxYHF;cdm$f65I(Yr;CB21S~ zLh@3OCIbqE>j=-bWK`&=9|MEQy~8)G7;PDMW1Pq5$OnqrzoCt)Gec^l?dM&W=S5P7 z1u8b@+9=l`!%o>O)A{(quiUXE`TB1c|M>BnH)p5c{P_Cx?CZ;`iywZt`Nz%e#p@q_ zIKxJ4uD`_%Ge7*`-h=+(huf^;)ek>hd(Rd~GfSS1Xd?(E9#V`!Bf_JFoh_(tDoGN7 zsvvo|D@*F8oowvcxfQmwfS?7@T+E?J6_vCG^l{3}19PDH8`}qWE<$Y37hUaL3$4t> zVjWcUJ!cQt=ZMb*E&RHeYgvL}>*o6%W{)8)E18cxV$4cRY%Lzv0-(YM(kv&}m*?bF zmrZ|-oqJ)nn@xurd=gd>LanJ6aKpAPVm-}eNx9e!uG6e8iY57XO$*f7u4TT?sSp0- zKl=0JPho+7p8Uz9Z31EcJkj^r#r3F~37V^r5b~9x z8M|hRgR(0{z7FTn;b663_IQ*T-tUsF#y&s;GP92tK+r5%4JRmP{qk}PNu`Wn*s1Uj{( zXC@|cA;mn_)36UIzzQ-d>Izq6Rge8u$`0Y#a0J0*j~Hy~L1`uCCfh-1>xE0J0@o z0SIVg)x!9f6C6{2_u-eO3l#V(qk`!x>7eQuG$x!e)qDax=1N|?V_9w3*18GYvE{Z; z;BPE+cSKTJLn)MWHg7UY;r{SZ+_7cCIb3=}5?0~h7sD0zBKYDR*GB(ue2|$er=H{E z68s&3RYVP*?LSkNlYBmYq1!&BH=ZC-t6plicBoyduM~jS5cgW`eh5CJ6eq#kk0b{& zURafQ(vm^=QTJz#gK_9T#_wst(7*J+i#($WQ*vB)MJ-*)0HRh>k&s4${J6P{+9f|w zWq4K>R1wQ%=29)Ub|sn@(^*v>b~kQUCtU64?DR5gKXdGK6hG@D%u{wRt@EsM<{5P0 zf^k1y(+1F=3#nLs97)W;Zzklg0nm2Ty;oTXGyx2a+k;~U?iMsGZ6+1FXNnx<5>a07 zd1j6$hFAyaezDQ`MB(%%I;kuXt;4je=kC^QJ zYXNo{<^iwb16?|%LZ>`uI;za_%k9(v)C!{a?$?Uh)2s6?LC${W&ihCm6yI(piam{n z?!gcNYSB_U17*(dt)=az+=fX4m4`Rbdw%;W*EjKG9s((J)@~7@JF9|Z|r{6N#-oxmxKs;}6TdjBPdwgZ*B-vxEqoK|Q}K|3VQk_H~y=Vm5b+V7$NU1LZiUGLa3c|_8f-VH-&4DaOe zdL^Crvuz*iTE=sCv3DtP?SJ}QnD^VimtsV&q_O{rOyP6M^p!O5$xcrLH}@20;Y=OZ z$JQ#NF1Bwah@<%?9sE)dsT>J=y#v-bL|Af%Y|4S;$m7b7O zpSBYJ%tbMyVG^gW)}5qO5QbIUb|tI&?}$7=+dHd%1c%$f9a|oZlKVr(jP&4A95i_< zEk+m=K|ty~fS(<#tIYk>;2tle$5&cUqoh^(%V>`HZ=Jft47;1JTeErX+&Dw9Q8+c$ z_Z1L1TR4w~yk`o%8J*`tTc1OVSeKzli>$UKa{eb_@UG1?8u;a@N7YoDoEx$lY(P>1e;A>)5UkL7vhIAh!N#{v@T4KCghYnB6 z5C)q`HRX8@?i5^5$W~vu2=;xpJQb6^S879b+Nujg92$}UH4L#u=kCa*{c_mKDhd3- zCbe3gG9Os5%vjV#5qd6S2{^_BfJwRV;M}q;)4nh%y@79C0wE<+W~k%0*j*X;9-4n` z%3g|VnYTT0WX7ne6~pdaSpCcdofa%7NB%EOpTEx4FNvC8@24Hi75#GvM=php{e0|#_h@f|Ig)> zG~Px1uaS#&p<3~dmvz}RwIw;9&6rBSKqVokw(U-Adv)CtHB`-^6w0{?y*4l}IOlwTxddPyRl-qEru7=qc5&&U6ff)SSrIttg!%aCt2_uZ{p+_WtHEIi< zR#AMwk}%3Of3Y)b*{h4kP~m!N4PsM*C1GeSi5s3Rm1rk%8XKCdm-RToSp}H zA(|Yt+2{e}i3H=?A!<2e!nN7)k1!eepO90LH(Ad;slonT(*oS6b4YDb{pk|rN4M&n zERRcT+UvH5?@!kSB>sGSpMy^}YT68DOvo1~CAOImUPW~QUg-?i%L?C`u?#Mu$NKO2Ua$X(#(CuS?nfMHwJxGK5`1>li58m{awwq#$_0hCG8?6w{ zeg3;`Dqx>|@w6Hf{x?ZUZ(h^JNA$a+hKk3KvAM?K0BE5}ikl?spqiVSB8G!t53c?x zI+_)dNA3%+pNtYrqKwwszO=Hcp{={UHr~zi`O)WOOkN(_CnxZY!_|qkMS!zK>%uIo zy=c!(C*?C@Z=1IM_Pq23A#-**n{mO-GNo(XfR^ZMGe-KuLOzfOSC|KP%^{t{%RI6F zNOlc^R0#svslP!$y4P**$ix+`CH83@ldq+a>I<|y>=Jb&h~K+>$Dm`(%a+=pQ&jy+ z@SJ_|vDt!u4Jr@wASFJuh!<&@n;T2iLR-SMXo&qOP>)n_AtpVYcdoIy_r&>{xXAlv zXR;UY((YDsDewk<$e%YW=zMFL<(B@pkU6-!#~07{!Ka59=9t&G`g}UixUFY~H`j^} zSsS;?5ut?yXTB9G_9K?NUz|zr^I!E-cb<9yFiuTk^QiT1`aV=o;0{l77tauv_KSOm z{)YZ-`^8ze%~ak~ddEQ1fa`!!lL=7A`7~T_$Zw)r-hay%U}IOYo2eM()}Id|4xfw%sAYW zC=f4a-78$yH7B$d<}_$bIvMAU)Is?hBY91TDZXNz~9@W2`E2jJP1y=3C^3Lk!c@+u{K z_!!=+YxrM?^CidoE@zu~QJ_`p)prR6ro@+E*ATJ${5Xmnetz=V$*Utv%g>H2Rijwn zXHl##eABI*>D0`HqgTfhNV^7rst2iZR|4r_i0lrr0f$xIO0PtXfMEn~)ZI-2-f)Ov zazp;Bl#2aVH0<*fjwuPkWAE4R^t+K=(CPQrg!J>OA1!G$zU!3Qn6~vk8-HICQAw+h zeD_`!b;-6;$oh?IGvcOjMN$|fFI@rObQuH9O<5tu9HVWa1IeS|X=YMntTOsU8>#4= zow$Wd8=Um?r#k8zd=DXjw0gGtoDVu(Q&?&B@*#a$57qMpV zDyf^+UJ2bPhu-F2(Fe_t8dFOR`(w7n!qu6+P3j*wto{IJ^S+)LFBn2bU~@qiVRG*a zPIxJ6@<7oi2TUieUg(xrUyuu-YsH$%!_{f6`s6z!d50Wa3#=Eg{45RF0{>i~o~yqg z2kf2s?ZJo~yqjtJA7N(tU_vg-s^A$nR)H5YrW(f+eqjJq_*33ONBKABZ@vKAIG5xB zI)mO@Lxd?MRmi}Mjsi03Gg($jmOO$5gO|DOK1AT%f*ZY~hY%+8Zz1|XJoYQNoDqo$ zwQYbzuET)#-n$t^M?~>WH{IHIZkUst-Jj^3z8b;u@ft5z_DVH5cy*9A+YK*yK~=FF z#dK=Mw5G0~96Vt!56BT>5`y|tFy9&?G>w9!`lKcdeInBRqSC0;)BKGnmb<#0em)Ok zqiPonn@Nz+;wDYdk^AVW87Knt*D~*~tR6;#c)1Imh|ciyv|3iX z5^^O48+5_$rBi3y^i&c zi@ZOhgSPwuo;%8MfHnz<=n-XI7yxjFYi;j2hJNyTU1z{4kX?>^M5j%AjZjsrWoYN z{_Nzz3cceANI>{S=z-ao4QbdI3)T$u2qs3a?sdr;q?e~jU-Tbdk#VOGEZ@v`4I zY2j_J%4>MDf3?~t*QuMZpnniy*$$r}&b<^?fTMZ?B$%52pL?|iEdPmDyodEn}|G-@{ zim_1~tvUJmS{1EB_#{n?r+MZ>l&%!ZVCX?NGq#WVru8{S2hGAB{2f~oz#5%N1x>x% zPl1^XsCZIqrY1Q2CvsY;N*(O&Et~E3tlqNOrlWEnL&K<$aBcO(+AOfB27A?^GQIKa z5MlP&A68$qZIP&d<8c9Xz90t&$=@7?fE@Y!{h{`Ne!gur#6biMe$R?!(9$srH?I*8 zj%IfcROQg^s-lKFZyMLhGyBeF4rb0FC%Y0QjXSfPWmz#-o*^8Fo&)W$A|%zg!HG+& zE@ws*{m**n0i8J#lK@pLy_ej7x{?PJpW7bEQ#@3 zdC$~6XAdV2Qr&SeA6wFm(X7!Y&#g_>|xH$qMlANSw`C#Yd+T}(by+k>ze74&;Rhp-=`kXAf-4N33)hh ztNmj|;;w{+oy)#?8LQCB3v)$tsquI0ZE1-CnwJS6cb|~RPIpWsT9xTe1}<{8^`0^~ zOWPmeK66=GAzPPvk1yb?`Fz}VI_{v9+tqtfF7>~QF|KA@<;}(Th2++L8sXVzmNEO- zm*~?o%k!VDCH{D4+0XcXDtoSx)0G6Y4cB7^%rz7#KKcQbgH+Ly8KxSf%1jE8rqw|C z;G2qx8$+|Z$=(Lr+hBVeY;S}8tZlF-OAq&K8ZmBM$wjDHbPD;;MKyYUS>BlxGd_P! zt9~I}|Lqkk%72`Y9RpEZKzgWT1${gm3>FYzi)N2wB7;)36EA->Wn0H7?I%-i8tp|h zgAE2;e@!V!=8!zW#)%qJ^t6=(k(u$(QlTHg%a<=-B53yi`d|NxNJS{gS;outUxeTK z-K$q=)Bof2^*2yjTp5kMRB#n`u+~I+ME;MPH&;zhkM>W&Wgp0vwuU%v_wx6@{cYm6 zxdMa^?!fF^GBw15sA32-4qA=3IuZE7@Klixno`N<3*%tE?E5NsW>7mp9Y8uvKJ3OA3{?) zbZz&${#3(ZjFKG;?uaxqwL3~EMYellTDxWpB~^DU5AtI|uI=VMn0KNJrJ&aQLRTkU z!gict4GTJ)Ob(H`Nkz1w%5fk2`7RqPzowPOexBCex5oh<0lTt9HQh07>S+B*_BM9= zcQ0b6J#foJh3Rp84>)f-(%(sIGU#q7Sf7@}Ppm9GAC(FJT+VF=_EHM}Hu^zC`Vnl*Ev4fIj77h*~K(vaOT(5WQ1Q|YEI@PkM z4Nf*>xL7X2!hJ{BRAIO}a3ohjt3e^xZ`9tbeRoZplZE!D*sxh7*EjU>>koOB!~OYB z3e;&U3PsnfIi(3ZAUEhc52MBmW4-4i}@mWu^Un*jC5ioguS0_X+ z-*%|@Ng97=n)mZuYfg^N0+gYzn7b5)sTs}KaYC{~@O-ms!Ahp=dAjjD?%#rnJO#gY zy7U}|uy=+jdq>W0E=jKVJyV(-{S`VMV}pg`Z5EZ{j63s;!)#tV6p>(RcJEs&Sc>X6 zNH9r#GN80} znX~J9T5!F%*>!Hsrn#|raIHe(eK|IXxjaI1Fz~E0Vl7=Rp^v^jX+Kl^v?Zv71vAY5 zC{2}Z_U90Bt?6z*{Z>@1&of#SdWe?mWjA^UJX$VZXm0Piry!J{pcXvA?mnzfp?CWr zbky!r3V&K7s}uV#gcC(96?|L!Y^KMze#kzXX`jvXv$TrHCz{RlWC_ULC5{r6=3_u^ z!hDz-o6iLWvyamHky7Iwp@^OuqxiHoX@Y^~IY*Is-BYmiyo$r~)S3;0WyiGBSH|wV zvq)CDI7E=Rk(SfL6q*D(1xytD@KBRnW_8JgX|7aL;(%eE$#x%W54fom{XKa_xqJ{- zqMlw~_HqbB-;Ygt|8e(zO4pZ!PNB1Kq;x8q?n{;5^pv;Pbw~D zBs+RMqtP>x?cbK;jlph^#Ht(U0BCBM^}hFS;o#EUB&8wH&C86NsftIu0BBqe&gFAH zr|o({@80l^`So&rD$|mibeYUZj-#428~AIzgtrz+qOBiA7z)hKueC@-E)ky$8X2U= z^Uz`+Ee(~%{=AKX=d4WpZ39>ndg5!3q!lH7%Cpj03fp1oS*yzW8;|$dPq!fZMl`U!pz>f8QKS?(c@!WNC zr-ECt=oV3}F14@TCkH+nAK9pGi?BJGVEB22kKdhrb@q$<Z3R zBWGt{{Wfa24eNt4HRNJw7W@@dT#Qm5%rbN#TPmH#wc6IsJ^8eZ(&)!N5SuhM>*QCE zLlQhuKDIF1oM7f-xB%bgDLIk;yJi^CAyk7| zvng?>w$U?f+`R?8d8Y+p1GiH2%^>N&$Qx}x1OaVA)xmfraJUalj-M2lC!jdE)NHw~ z3Ceg<%fV~K#~CrMI@ps@d;T5@$$y}EnWIwb zC*Z8vUiAQv=180KmQw~lYPc_hnJ4c2>{cFrgAujJ zG#@WdEHLjVWJ{a&tj;Hf1kaIVxR5ihz)6e?oKO{%#jXTS9&~GfM}jBVe7MP(P4lmB ztR}sXnh9P`XTW%4zLjKH8iJ$E;eBiSv5rNF(gnjgP274whL)rp2z71$Ayb0UtuOCy za4@ekOmlQ92|-ux{FzVgj9bhKs_5YAHl>UUi5u9hAMQYq*`Si1gE&O%Sf z`U&9zQg^I#YED?nD@1V!;8fOqp+<@nrbqZ7<7`?l@8xCCQ9x`0GelWR=QJ&GX72T{ zIe2|{ZAL?GLvDj7tw1L-U6 z78oy3PNl*RWQ6Xtf@@R}uc#`mxQ;WPJdhNXOwlaZ%=P1gX{#x}Kv-EOTIDJP89KGw zd@ImBXYMOMW7XUb{8^e|<1;H#=*DJfMo5K~1a3W79R9X{z($cHbOUN}wg{Xvt(O`X zqJ?BIk`O7eSeVpSs$3GZ&EVALMc9O4R_cKvK@!fS5@iA_kI`802f`}Gg`*aU+f`nk zR`3`{$qch8@m!=R$0=;VZ@noTT0FunE}m$^kt$f_vDQZ&wk7Zh-uootyoQNkG}}c! zcTN;evBIx*oSFR=FFbI^fU9A}YA|i9**OcD7qm_ad;9(C;66?6tzIOk>Z0^%v6wNF zkPL>N%emIWalM z5QaE>88MiMq@_-<3b7IKP9x*B{e%_1i$;@lu^X!qSXILUjy=5HQoIqWZbs$Q|Hng*=^@)o;1IH*1-V4j#=*^i)#JaW@I_LT-&+=V!w_9tzyN1>9sD* zrF;~<63C!o;s9RG>+YQgj68bN1WQu{(&0!Ug5c7c){P-f#QflV^A~JkCib$n!Hkm| zP4)1oM1f2oIhp?e>k1Z1FOeG3xuj@#VESN z>q(=}H90HQDf^bP)Mo}cRz7_~YgqbI{s2Op#&hxt^3PF}XcdEqtVQ+1LWdpajQ#oXS5j0oa<8&u>D|Iu=IHnBh68 z0;#sdl~xrzqhsVAt+7B3jFwziVA)9>jz?J+Dt!HUPiqspqS~K%m0l9%>0x7UJ%dif zrQ$hOGy#7u#ixAlC{nJ$NqOeiS{H&X22mGR# z6A92;$0DGYc1jo#SOIFp7LJ2!e0g9op7bho(85Ol$i^|Sp!FNYeaC(pIeyB_o^i4u zauWa#{~7vDnx*x(m}ha=$b)04dyNw(av&F3F{_QF?*H&~N6mR`jPbSLQr@_qY0B)^uCeaH}Z+j5{Srs%buIM7Tc8fTbMV5Zn&~=GB8f?lm2xKm&7Apj2KatJ>7+% z-n(&pBeargt<;)~aDvJa@z;7$+}!*Xx((hxkrw}?KL?(rX8Gh1y0ehqrOsCwlvAQG z&1Ae-beHh`6NZ`ucC6eKKg5Hya&xtVG@#;f? znWUV3jcKMgquZ2Klo6GZh$arI7T)%f$8MfHg89^Wv@DOh?!%@p6oSktFQv_L`)@nw?BbCOiVu&(hRbfi(UNOaE`?h05%SaYsgkoz+)1}iTKZwhy~JyL6um{^^TP^ zjg*pl)7u#MKD@>d48QuIjVmCS?!<$$+-US+XcWGHW%ElJ-DcecGwBGejWT324=!#l z140)|GhLq_vm*Wzki$O9zz5sV16d4gS`yOx6T2_B7?#OQG}qJvF=6oV zqF&ve9_vaci#9)BT08x0#(UYSO7Y=CaK(*L=FgjYB|mz>BO zuHc=6SV=PhhqR6ssz3oW0BJpjL=ebw?0PwHyd255Q0|76;`2->u09kYCpTIaFup-k)OkGWHAz})2@X4&*&TV<^cDnuB zrjI>geYQ^|>mv5yBOqka;@576AGMp|7Ji;C7HJF113LE`NC-a+4^#(dqAO8en;WCR z=D5&e{C~8b3exO zrvZALacPuZ52QYRAdBNcD=o2pSsY)p!b%8 zntGjK6WiWb0CjmB4FVw>u)C{$r@|aqT9$)|<^j83R3dmQA+%iPtbJ3EC1JN^*|yzf z+qP}nc6HgdZQHiZE}gQ`Rn=ur{c~^3yxg~$hx47CUuH&}$cVFJ=U!{=<$Y8AdK6%d z$I@q=q2GJ+=d(b(Tf{6Iyf2Ry^xAsG^-z571fORDcE$}B#V?|aG8aU*M{ERw+yz5+xoTmpIZrI0IKCLf-uUUEYFMbEqxq7D$ z=Dx4MqOp@D%owH{Dvj9&IJd<}A(b^C_{|hGH`)4wStii-Bx2$?Y7+BjwMpukvhLKi z;nl!v&lwr>_JTvHzkWpz$vjQe0%+ZtHdHUJMftl+(yf!Lb%EmKqEO91hojz90m||- z)UI78@SB*nDToR5!!osUC3I=^)xpO3dHsI&C+6BHX3nZ!Aw1XQ`w z@h`Y`gELN0AJ}FibS2G_S}pC5s-$!dVU*HLOTl%qsjAJk^VBO**~+Y^&QsZw(4h-7 z4=!}l^qru6)1ta^o0g5oNUxKyG^UZ(4cj9=yY_Nwr== z_mMy~sd8p!^r8~e9A!7$Yv?#FeMeHf> z`!hAWE+$1?YqF?)MM|BySENdM&7fZ#CYlP`W%SHkGc!ICii#Ce$CDG`fE-GGx6!t- z`u_CIX70ue9+Pb_lk7~@|L#LcQEX29toI$AOeAIA+%P#CCVsJTGdt`Hpfdq=Ye+o9=@pRpn(#FleA^ zi&!^ z+t53v5ybs(FJ?PMU<8hHST-26K#=*H{RQr`hK&QA*KVD5Gjl^IFc#|q-pAFT@bC~{ z!?B~%iaoB}2u%sHNIp%H95v~T4tCT)w-(h-xTG}lk<+`ETumP?P>pU(Cy=W?Qx$7{ zX>YPcy2uSeCvN<&Gis@Ojtw&YsrI2{!~!mtPJzUriLy~l^EHVa-H(G#yGg}|I27iC z4@rwO9}q$qFtyd&>SEeq=x_OvoTPCVnOCM26^<4%z0*Bj&Tse+iho`V;0z1%-cW~0 z=2Xb_SI93L7W+1C|+OT z0-xiAhf|HBS^0xOjj)UwmO$oM=8K}5?Yv&=+bA{=Dl-o0B-Br{UYd?}$xu<9TpaC8 zG>-<;3LK2xUWqH=6N^u_b+T!+f>II8v5iAX6$^^i+0|uhrG3N~?Qx$_2{K@w26~ay ztRK;>Jz9s^n{jO}_+?--x`A%#ua<8zkAI~>rnkhPA>P4ueLZ}!Z!#-39mm)|coM8T z*bCJSz(i3#Ewnt?!&2+Af5z6?`E;}3(8iQOR~G$9#Q1Hu4%?QDRMLF!-(WU8vgzB) zIyO7HAB}6H0~{`?-HR|{;w&oO&MS6kN>IecjR%N#F9Iw zN$(nhbAW@BxM%xc!!{P*r_9WoMHwI%zQhsLzSd|K9j1>P^#T@i%r#BJGIp9@-`QK6 z4!Of)(lN)+Qed&fg0QC|NE_ROoQ2cG;utJS_j`q#q*_aqerOI}cf4TB& zy|vBhS*_9_FK^;vvMuUY0mzwzJ9+x=@VtU;ppL5N;nl46y0wn#p;_=G7+ABXk)Pfy zGsy9Usp|o4#Eiv+R&NPTz%)I~?2%nw7_#sUo)5NaxwiDoJ(q{p$vFJc$1Dpv7JSgU z8dse_%@_ z*>-63QUw=O|8`aA<|cT0sxmTDqE7#Tu7pe+?RT4*p=s(L;5sm_;h-}I45D@xZsMpg zyk<5Wq{g%?lalt$xlY2v*Z1n^>2{4`UckY%pr*Ft)XE%Cai54s&^GQ^SHOAO!*i>f zQqLZCKE3v3E^zY~ZZawF$Z$~k*0XoT#$P-F>l5?-EMteB>J1B?X-Ko8TG`$^_8=&d z%FZ=6P?0?#s)&ioee#X=>$c`qK-+ZQ7sOs*j|72jdr<-E|k*(O-0+@!cAz(IY z!Lj2Nq08Un_3uM}Yif?U#Tle=K4J!SNJPQKCj`Ai~l{?A=M{=c6{|{+#(sN)8 zgsygxe)S?#6y4l4oBVN(!6uwt(*rN~5OM6k=>8x}BO8M39<9!t5?!*}onDYSR5m|* z`}+uZEQf3Il-39d2SkQu&p0|MRc-uARn()_e>JeG9P0M zVC*Y1gcU&(owVmA?d4s~H4wJt5pT(d-yiVRH==|I;hnq_+0N$s22J4Fpg{zwy4tGUhK?;gOgC!iN}hIqAn;F9?cLn)sUub}Taa>%#HapL|da)_}1 zvZ$IL>*vv>=63$I@dW|gR&AQHmTf5*m~2Ka=Y1vHeE@25cyAAWyVhW-#AvV8yaCVrd)mVs8jM_Jy@$p z;im4(2(oS+&|x$j+PXWcgF47k$9WkLZJ{T^Ce_8oht(CDrmum%SoLYoe2cG5TQL`< za>D7-(O6ML=i8e)-})m$ty9?y5|aI1uU&pDW&6fE*2pMc%fWtlDCFX#W9{wR&XPS8 z=5t;Qo9^EjQTC4fv^}J1?Z85G_LavAH81(iZ+wX`qHb4~k7|&g^uWzq*~+2zS3@+` z9>F(yYmm(_cia1B1OSgE%&Bc0s@(ebjNVb9tMy&*_B(8-$w?#dy%l%|=r^!M=8h6C zQ0Ij+K?$iUVL?bUbnZzi19onAoaVNnmEFd#Kaw#rK?~hZIaADJ7zJqjmWTIL45BE?}%GDQJ0=Sl{qVvC->RfOg{-A)egvgABn7r;iA*jFA-0raFCIxr-%wv!N^lEr1 zu2T_=J5F>+OjEZRrfn+p2YJ^zCd(H#+OVRLx31I?DXw+(NQs9rU)9v!oTO(@7j%Xb z1OJv!0!V0!4CbZFJiE%yN?yd~@W>2z50#GCWF2G?x%vL1ARK<{lJ508q|>_m$${+vCykGpr}&>@=n z>dq?8gKFhSy0Euw=PnMZ)-JVYuqW#fBHh0cSg<~dFh=dO;TGW5J^0u0D_W&a%g7(W zYuwHa)>LMOiRdU@!WIV@h2e=adh9s?rnnHO`rlNGYz$4=Rdy$x+CZ5^99OroEkx2k zTDT#)4|G{Een$^CiU8;5yn?}0VqnWlMlGR`!(VO;N6CUJ>*TGZL}Uc%FlDv^#%mc~ z;^IYYcdoiLBsyEJi&-y8IS@@3FP`n^30re7BbM6r7}nL(U|7F7v_~x)hqp9vcZa0T z<+uNwOjImz(YI856V_4%x4avu8d4uY=@Ch7u#(2k*Myg>$yN`dB@EroC(SvD!=)md zN0^F_pC+T**ar|;=;E|)l^+oZB#hn>EseGpt(-yBZ#bd1>a-E&ZooX(&?2r75G0!x6%jvSiC)kjU z1j0zht^3h6cL;BqelX7|DNtZshgh)5*lNT&jFQMF(2l-uUoin0Phjp((EKkM)}K#x<8`&-|ewCil9>ox)`|V>?3nnpuXx+Gxo4oKr~}z+X@AmdIk8S z@y$j22+Uu)jZP!-{DBGGoThHjW33};bI)ryv@*Skn&Y&H_M9N+8*U{pxS=aLdTkKM z-#iHeWd9Vc3H(`NyejeF3+#}oV`%;|;_@KiwK)>Fx-`L8G(ZCp5CtV?vO|SIXqL@l zT9oTvyfV9k7_1Q+E94o#dF)shNMI^?P`X<=t*luasYL;lT3iU{TG1&GqQMjpb{b2y zO*h-fE59<+5hWJ)Bah2#C|Mu1S_fv5Y9A`yvN1k`!m$YuwhTpcdtAg(3tIlTD zhs*&BUXwP;v)Sp>;54>-AdEv%v1YvW(nk~lq+msi!%1D*LPLBuZ)9Pl++Dua$q-{% zQ5Uw@=d12Tgyx-1i~v-j9J#|~;=xkTlC|;g<+|sukGM2LKLRjU?-*!7=+>KXmRmvh zA15>1d7MqI5^q4`haJ_D&R@j4*$5C9wL?Zvy;a8r8$6@}+10)zNz8I9p- zQ}0GfaI5*RMwMyxCC|E}j$vS!^VGX1sbO18?jERiLHE^e>t+wd8n@jBwK=-QfamdJ zeEf_%e!lhYW4vkHor$9J1*OlWjM}66K6Q;8!e^10iuqR%Yq1+YjC{=A!F}>a>^YlZju|LnL{h1Tz z)3$SRx?j-C?ze{X!RJhBpsr%FAyhypEhG*cUGokQqO=B>~{e(=x06PK6Jcb4|%065=6sZ?a zQ!(fiV6#fzab;!ge4`6;b9Myu4~u%WR;8uIu9**N2Md%rGZC+ShwkmMb;rAX4Hh|n zt&@x$TUqo-yOz*XIujv@Y~k+X_-?S^g2MiS8$jJY_PPw6v^{}-%VJ@-(EjLV7qZ8G z%Hj3K#$jR!PJ6dk7xKGgfRYj`mLYGtDBK&B&xSaZXtqQ#LsNV$ry!IRV z|Nn?XZPTvyQ!5G4g&W58M0z#9LZh|n?2m0Z-kf}Yr;eW;xj0XCjKA~xGG9AM@VQq+ zpE4aS(vgmpC5qc33inGmr6<_cDI9J1ki=Jx?O5F5d1J(DmGg&MyjyfD>__HS{e)X} zKO5yw7o@VcKObM1d287Mg?;FoB8C0)+1ps%Z(kS%xBCYw-kyTi;(ar zSV(M4SP9T|fO*QU4CN|Jk5iZrqXP4Co~BY|_?i*hd1u}?ksjtvCM5>}}e1f?o^OW)_t@PIPsU0>fB7Gu(d}2o$Hp-DGK^2g^jri93cPE@!L9+SOK6}CaJ>Q3|zL?)!r7XZX za0~})T%DLFnX(AIXzUoB+E^ZxK3ZpOEMhS?cscakwr8y=+=l)@PHwl!xA{-VJ@wmz zO{-4e5dNpe90GP>C-v*^RPNie44RctE*7}VM+Cmoi|&jyCdam4hMqH3Orf8n#W0mF zMd8UYT{gI9-FgGnE%@nb(=}NS?RFDtg453A)y`n)MgvTsN%qtRLzx@0RCXDRU|=#t zKsc!y2K+)%^G-Pv)OU%v7)_xwY&2=CK`d5fWjh=TZtMuD#IVe*HEis>MLrS()p%1 zsgb%e{pZ!v?Q{qQqBCCNIglk^Tc5d^^xRvZaGTxW0vm2vd^zni2D*R_}G)4$XAPRImkyQtj2SIuNcp9}ixucrF`Cw#>#aWSOI zw(uDYc?gnv7BS7S->4T7;>1d79c@lHz~2t(CNG2I(*-cH5|CP{EJKA&xfRP6C?t*$NjvWb!RpwcthSZKy9 z&)=;Oq;OpIzAK`DN1>WcI7;-bPHoWx^nG;t6&124U13e@Et`Y-L>xEQ7W_I?S%%Q$ zWXb-N?XBJ@xbiXSr?4Uw51)!cWuZhC(JyqRXPQIy!5b%1G7T(xPFQYn8gno%egca= zL%?6dpmpJLp6vq(2{1uf(x5YNo@~JbIi2R6g+)Q$v?$*>W~n^AQhDv$>p3#oe%M)9 z*iBc{pyniAdMM@Ty>FFGKh5=NSprj_Lq|Mx7lbQwW^NqR)9X%SzpdpL#p;;y0`S5g zD!VNYw;TBBTuXbeIrSwJI&@8rVOp3s+kSD3M)4kaip+iO(BaRJ$*TyNuAAAUa(hhB z+t)90l%3Zq2oZNM%NNMxnM@U(8g~+NP`!Cuv0%6N>6zlLohVVF%%M@!gG(j4^~Ce* za12Hv$ICxjoGSKx+NyTKrF}pfeYM2-BIf7(G61i`4`?>;?Vg2&Nef?xd>SDG|7}SJ z3APPv_{&QiTycRWH6FX7>RA+yTn8nNIh8JnhoCbRK9H)CaY`Pux{Y2?tPUcWpqWT6#p2 z>O59rY>vh|e1~=;#Vm8DwMo%0r+v=M)rn_WI+mkHx!{p1Eo{(#&Wt=oOnGoi7 z`eHxo7i zlI(91Q~qJSIH8oXMxNUql`-6A`KkSM%MIn??;>xilJ?{?! z3@|*Hu<$vra5?8N7;(g_v~PQh-yV%0?oOT4gOu&+8CrXMeLJ8xcXJzY9YqaVT^rkR+QtgN!x*u}X`RX3|yQ>6FL`C#jMSsECMmeYAo7&mV z0?@tIhkFyv6LiOfh-T||0d#>xfGxhK#_HZLE)&A`O#3e@;-w{m#J1zD1HQ^_^(H@s z3|Qb9O8&K|0-2BJAvnEl{cs~HaNrB|oXJJ*_o=$J=Di%f&{PsHWX+`x$P#dz0zRTz z$P&A^9zLS$!!}h`qH821%x30s+lqQ^-nlGu(O+M+64)Ej%$hSeLHq?ewAh~(Qq&f$ z?K18W4uN0p0>@(?+Fe1YeM60=r(+8J-9p3V_}sQ5?kW5&UG-bPsvGtVu5S0V z%$hQ;OY#?)&Elb_Dv@+GSL8mKId(igzsN&-6SPH5bJkN)Zej!o5Vy9JKdZSeVt%nV;r=+z;Q0IE&6&>hrH=nB z`}*F6Ue1HY&9<}@G~2l?`kb}tft?YrJq+f_y^|oQ?`4QcrY<1Hl_Mzm;hxu*ll8a5 zB^+^L^{QtodkevYaqzp-@S*@Z%Jkj+@7HX(qXlsFNeN9n_N<|J zzw=ii_{4!|p3u;)QIOMrkqlJ-VfdV|pxQ>XHCiC)6Y}P#Hvk&`t*Z%uSK5b^C!t{h2DUC-E!al%~5`#|d{( zYg0{LKMpm+KW+^CUT+M(&Jq1T{_S%3zO<_$QvQmexlEe8gUm|jGB)F94?R^TX*J~Y z*4L5&cq?yY48z#3MtEZlT!!0}ecisFsy4|1t7Qw7J5L3bJ&ukwYq4$T$W3wQ&I07n zY3@Ce`<*J;vn$iH=T?3^%b1i_!DjbZMr#jGHX^Ab1czq2sT|sy#`XW&k7ePExin)q ze?n62#b)w*?P4Wh_JzJKpIRH=^_*DWy#F|FSs1#-7PehXF#bnw0gMy-1OC&s@;0Up zpDU2-?btjqzJWd?zxMscTEr*54B`c02*Vh$1L5~{(ofNH|N1x0@O^7b2r)zRAg-Qa z-lV>yjzrtJ|1^0Q46WSlc+zb577~=33q~Z_tpY;BtY`Zhe|Od2Y|&<^%p{gLn%kSWSp~RfIwj<1(%>P)1h203u8>fe{bF+(zI|_2E0U7 z0hZI^X#{&dsW;vKQ0-1~J_%BI3<5FHx9+A81K_GPI9sZ_Fw41`4-ybpE3c=xAN^oIydNM;FKo6+A=3YgNcD|w-DCsSWM zO@J3zgqEh24JJJNI{v7PeQs$GN-9@TeA)pZ$!~zAfK8m@C|Hyw^O^}g(P3_XfEW-O zYKmw>q)G$Ee}xMez+|>+l(6Yoh*gzBD@x$Zl$lQS!^Z6ESIAg5Isf2(|4_j}a8z@I-#u+RVm%i(!k-gM>$kQRgWU}!^S8{* z^)PN}B*9Ti?>RvtZ$w@SLdLovEtY8=II22*wBS&9-S_-7xJ zmb`lc*cHhBgE1&oZYq%!&=@Hqda<<|Uvt@gYWGV$hMGV6oZoK*x($OtG?*O4=9wN% z9pS7Flww_u$@v#ggl*Z$-$xaNdrnODOBy%uG0OAgUdl&B9e2O3af81}5JEL;2NeljP@X66_?W0}E}LUYjyG6qaQ= z1q!E3qcWeAztQFOQKy1Gl`Oy7mQ5w`)#!bE>q&VYg#b~|=VFY^w~ z;s3Pcw=nNqcy$qbR*XYvLkRdWGL@9Bi`9f4VEJY33)G75YT;k;Gj|wEor0OG1nDCf z^m*Q$J4TE#i>V{m4G?DK-fgIe^P^krGFXmS!}71~GREf*ID0yW=TM?$L~A3iEaiAQ zs^pFVg4L8q@R57?Q;V+!w1gYT;);Vq_;A!E|LF?An@v#>zb!`SsJcpvFDD+R4#B00 zMWJ)yuI#xOVWHPT!75zaH@ch3XHYw((II83$mG;OG9&Xs1}!XX#F%61B$fVC!yRgP zegcb4(-j^ZYDDI3=OliixVrMV8TP6rMIU}jOB54!G(yIy-V0#Ugt{Mz1s$Z2P%4WU zY}Vb@9diyub)ARJyE`xHQ-TAAn1v089+FHmu}QtW{@vWt?7c8(?l(u^y712BBVciJ zdi9ypo8SEG^5i$SGr#e(xiFZQa`$uoe}2Y%X9Xe)LLWV@?4(S%E*&_W@2pi`U>8r|&MRvXqyQQI)}OQRy!>*&`P{ z3Z9SX0Qv1HKYcl1@iV5kqv7v}f0`(50k7(DtTTzuF8YjQH<*kI&$xE$A5@XEp&waE z27CH^L9%nhNDL^OjjqRaZ#%%yS3S+9bAz28B(ecfGo#fOyHPVvyGD2{Zqw6QTX2lq zIm-2dP&ey7?to}NRbO4B;Zjpl<1PWgn1rUfB0pg&jSeSxFkEA^KG3FV8A;}yQ6}7e z(0+(ck8tX(Bg^d09m#)#69QDC2|0`_h0TsIXk#pDlL!pl|BF9}84@F7gN(D;X{6{; zk~_-N747ltfzuWJb6p#(B$`rkOHz_zF+rY$M33&j@uh%~c!SE@3t}ElDnR7>CLT6A z_joAA<99KeS%Uj_G>mL0ULhDHhkGa@Iv`dr>%B1`-AQhYUNP7?F8b? zX{=PKJJu&b+Vw*aV>}oteO0?uoWpZAu6jv2R%QSfThZwQi=Rh7`E@yvX-(;)NeomE z0zSL@W-C^j&i;nB$1Y|>E4kqqCQm&KCPX?WR*50)pJX#_(i~v%Aoa0_nIaTB8 zgb}V#z4vJ^tA15q3^7!L2`bY}*{M$ zStLQ*ui!9@7q+P!9!#lG7p`Lm zBb7}z(nvqA-JF<=C9c$yP@<5O1zz8NWRz@Oz=ZP!yR7) znNV}QJLLS#|K_t%wW|zU9N)-CGxE*x%?B>vpCfp@IJ~;XxjwwY?Jjxe^tr8$Zx-;$ zdFOoRmaB|!z8N*wSz3SN^s#_l8{c>)`}=c3A~lPDuJ0?u9m%3T2jTs}Z#7qjoeC-D zhh{BDO+xfccV92!7`lqDuE#xeLEnZhU`8Xbo~+MsgQ;`w0E^JLgWhYpj{~veV1f@0 zz#H~Sx23b_nNhCQdY8RI%k8>d$=nf*sXhspT{L=x&&P&9W*dLl#^a)Pxz41_OobcE2AM~oPqo&v(JICY!8T8$ z$zs9vS-BA{Rq0B{#9=&L5wNQ1=>XwU@`s`}0yw4Jjj#K(te(gIc@KYt-1t=}PT|H; z6!&nrX^cOgx}!P8drjkD+t!>`R?Ed10U}=5Edq{)n_{jldx^^^6~v2relEwV zvjze3X+_)%q1Q(wb?4XPBc(EFeF{L}&qHgas;{$uEoN{F+kMXIc6wad9 zXeJ<0>?(%xU@vOW6-@h_prHx9L0V?_EYQ)2kcjj6o?^JIW5>PDuLVrh3P@@*ajnfA zws<}j)yJVA5dbRAFCu@{3o6P_?0y9R67lXj2Z+ijDscEFv>I#z@pXZDwd{NXBF=+> z-SOZm4jX{*YvuO`8Ee{SeeL@HJc}eWjGO)$CKcxlfcqmdVGqzVzs!q7dJ+tBB=V|R zoN}TmEr{(~t*l!G-VlNW@i!oY%+H*0kh5Qi{shH%-y&vNM@$rA_&^kT@etH(NIg4z ziiCNRQf@E{3i3@xwav^Zh`)sJW_|DYtAbJj5dOKQt=l4J>i^{5^%ws7O1f*$j_@avdg*u8 zu&xeye;U6;LcK<0nEWb0x$2g!yWwx-e^VVR;~gho_V>=59wepr^d3ZWW2%?4Xd_mm z-;ZZvQZ8~jvY{HuKGjdhPGo<_nCFsHQli#T14xs&taI2S7ZtpD!Y}l5l9sJ^^S>m3 z%&f*h0j?@}dA3|R#yJIjBmWLhQTNwd-=Z1?Et!`fHMJ9BNfmX>B13eVExCcluf)(^ zCupO8l{5E3TIy1ZqL;{0u*{idD7HwIFrIN8k73VY2h!To_YBm*k6OO1&VyjvW}DsA z+Te6OXzZyX@gb40_2qPt%@_*Fmf-MC zCf`2bWDk2_oLI|v>Ze3mmiEm&?i9c%5)q+-F_fE2>uGm;okal$mKttC?y!%Wi^b)V z*LRnpDmVt1Ypw~=tfqb;7bSh8{;u4L`dZz|Ts)t#!?z0viriUu?w%?5LoxbSf5Ggd zE?NjO8SN9uF42|C3saqC<-4F9vb=IFGy*FNb!ag}yIX30Q_1pb8sDayo@eSX>C#GXi`?1-i_NO9a0$&w}nsaCrC%=E4NkIgDIvZ== zs3ngU7_svTsR5saV1#igQ7*XXA6hE1Qh<6W;qZoml4%OZp*fkiD*774xIcJ8527%i zjf)BxW5I_rhtPnR%W^$u`|%&7{b}ke`Nc$V4uh?RL8X2~yX~F=TPcY!L#%B!3Pd0* zO$%iCgQKK!PGdyOREmL|%LCtwrp9D!5t@UU<`O~7shUS&Xo<-irLnQpEkquxSWW5h zG2>~v`AMw{?rN_?L#Ou_q6Y>vwV9PXC*q)BcIk{o?D<@xJhYIT%NMEC?wG+wliTPT z!uQ@%s%B3#6uBJK^ibuZs#hlc)Vnj-nbT2Dh6;8oXA3%Z3w=JJ_0&@(UPkZ`bhZX6WuEE!{J;9(5J;SqL21#RLpmkl*Vp<2@LE2aJBX zTf#qySS`SQiy(dBD`MLIdh76=3i4e-x6Q0F++_vVDWg0)>vTFcjJk^Y?E4a=%0Vi z&+6}Q`M54SB9!F*s^3oCq<-xCyyG58c^{T(7pPEur(eG6R%ndpPi>r>Z?t;M*GF*K ziwN$ElNoi9fdwRpV$QRMQOZ>EmuH`6#j_Ndv)99I3a_(< zp|z+-(s_c^qV3Uc*;*M!WM4b6r2hzuf&>V1+Ae+}GkadJqa8TZ?5I43jFBDMS~q*w zV(nbL^wr@s4sQL|P!mJr!U`_VJ7@k~Rr2j%Rd;=q8b$F20v6KMf>zz}GxtNMw}~dH zrJXYi;0rMqM4n)1)jlxY)Ye4Ej;sF&E!NjXi%cCY27(=W1osiVXv=`P)p~H8h|5Zu zQm@KLWh23l0O7j$&&^|X6L%>&k`Hg!rG0TgLLwC6scnB$h+lHbjGmXDH5Ga1S|T}! zgBWWszMdZ5qo2P!Iz4^dAjSw@6%EVUeW+-{PmH}7)b`f%{ zix~U{l8H!Abvvvo=2LVTLj`)6Grz|BYkghuU@EA={tUBUClY_b@!zG#-eIl-gnKwLo!FvKh5tULfoctf^b50; z!n|I5^en-Or{tIOCZ57fLwd<)_H~3)se5WB3!RF$;*;~vGs%Rn=M5C@mY?=F!t5ix zJ1DV_h;Wet+o0N}i&^D}MURl&@9_sbS~0NK+yCAD zKE3X~%zoGRep+fy&+C1-()UJT-wi!-HJ6ujeyKGB1`xDeYA~A0w64bw(rjmh(Xf9L za5y2?d}T-&1$z5z+M0~jdE>JXH?9+gxu9J1+saPB&-FUcxf5KtFbO;4UPtPGAHMy& zIQe?JysUmMB&fCY$MA&Jk&_A$;W$b|uic(jvKRoZ_uW>3Azp13Av@g>xO<-!d3ClVs$y z8#%TStC|a>BSA$0VD*3oV`E;s{T{l4p4iR?D<`$ObxVV@Y%H@XQjAJb=y}+hvkY_9R%%!ak+`(` z)j^&g%~u_yy)Tycque%ncL*{m3m&RiT2k)Dxa`G_K{#ME=-=8C|r3+VG8O5qN(UE z;grC1N|hED!7tu=zBR?AO5XZbU-?qnNZ#+^{IA1!A5?}OM$TdRk`sJG0u1?^NCy0$ zzdBnH8(|e$#9>d$-6Vy{0bGE3a<7%4+v6%kDQ@(F9dzAwTL^+=GQDc*M0UlJR@lui+1RseX6MNr_KLk{FIp2Gj@=|bS!`QP&VIW6BC-{5dk3zi|JN@Eq?OW^C^_8I$@wlc-lsl2Vt=8R55N_~y zoDu2oT8~jWb(UInUYII0qr1_F%wOoI$$`rwG3f06UOgOM0#5PklPCka8!9Vhc`CUn zM%V(F`M_R2u_xy7S5{qH(7*dt^SjnP9ySdKV_rN+oqhhif9PYU^iqIHV9!?0_AOUS znVKr!Ra#l5pdAmeb5BXljShWFMPW}y4s0k=)8D4R{Z2oz_+q#p9xG7yx5KMI=bqAc zbb1B06YJ04%T_n?B(pza`bEZubEJ3T_UHdW993{ zZJr#F^Hk9c^evmx)mOc2;xMgRXFaN7m76ur_5sU#`5%go&~e5Z3I$@bD_KLg%xk_X zhNTgP^$Y&FU!TziVHO6td0#KaFN6ZVPH)f1ABP@4JD&$%F9%mw4-exGyM8YIK98t; z@5d7ACx|EY2J-%78Ul9f6B`>E{jqqChX;kS@SRv$rT(EQl!q<6?RbER+~>c_&)01l z-tzonpCzM*gel%6QX~=Fv=m*~$;+YXDCzv5{oXp+v$6_itg>M95>P{Db{`^Gvw<;# zZQp_zy}SL-@6UeUJ2$)UpB_ig{VYZ89&i2x^4}AMBQu*we`kv6;%jlSs`FOEiAW9x z%6(wCvJZ`2)@`x;%K2Q^xBzGp;0#l6G)=_n46LZYl=1j@4bs+(@`Jzmuu%0(v5RIb zBf0_u`0>Bwkq(1J)&ne0-x>+*oL0R3LPV8~3MsSWWbaf>6g3&K%=$vC2Z(+rip(=L zDc@|GM#~(RfsEDOf(}rkCZVJyG|0jkGCQ&G>7SMN8M{>D6}GTCdYGWMT-)VCS^28d z>efP}AkfcT0+#ZO=OBlU5egOwR4|NS>#@AmpmuSs_lZpg@9~Wi%!04*f*Hm$3F1To@H-*$A^~xtkbOh~c@-fsUJuoDRCqn!z z-BR@!`^O^6La4Y4k;UuOt--0FWb~+fOl7dx_U!lHJ?1+_#xyoV`yAWns<#ZjK96_* zd%^9kf%{zD{qT9X7K_0;V|3rQ@&TCc1<=&{XoE7?QBT#ooGB2D?uhDxs%&qgSc;dw z6_}dJGhem~a{XYomcP-T(Q7&aqIiNJ?x^S!Qv;UeU}s|vTgV5=rp`cx(n}^@hM4b~ z&;V35Eff8u)Ic`)#L)c|QW)%VQBJK-35Lr`VPZ5~T0rnF) z5x`w}+m3EFJ?6xZLZ*Y6U}7!YwSEg@-Si$U zO-^AFgQZ<6niY)TMY*$%m)xu2q=Q;zt985-RHM>1Z=OW~qfN+hl3+hBK4P@y8Kv0B zmO)k+F)q5$?vy0XQ$z?xinBNHQ2*{{2 zi!!|w=LiS7Cig-J?9}+`@jbrh3wIYq_%OV_vM)$I4=p($m|q2x(pu*KgJ>0t|5=Vs zp1{e93MN{2b80oDZ>zKOtsNOevdyL9AW2aYmlcyEvJpYEPGN6vkNniyLM&AUvUnU~ zq7_A$hy{YmNhX`vbn{Ri2|95yLIVW5u7H?MiS*V}JE z-6~%gzz1d*7<>pWfZQd#~=QK6R@1vwr(o{69?@ zR3C%>#_p&pzgvNs`>dL8mDYdu|-67(zA7pu)fw8D~! zT)jN$W2*@!X868;wnIQ-78MJ;uDlyeV0N@6XGpI?5&M|wFFo0%;jP)niqzb$(Qx?J zDBWzLDX>B@$}%6sP;wQ0knT zh$Q9I7`H&zQ2wSThPUs%U+j4>B(`aNJ>X!weZ}~sD~!a@u*N`_NlgkvOqY{gt3)juReLMm}7gt>+rn)o3nCay!KW*R>PR*09Ap`iD7&RQj1 z9>%BQ{r#Z#W0UC9e(6}5uRF8gB04KNV9W0dx13w@YSxJpXRr@i^vT+8s~`HoEp1`W zP$#-bgH;kwtl>flDa#6^0cspMz!Aat=4OF74TnTr*7dJK+dL$$!zO(w&CS6edCJ8` zh@=SzUyQvRr5-XnW&L=!sQ+qM4>^pbH5TPjj`jGfbnM?4h7}%XFfcX)MXjv@mKYSL z?;m%Qn4^qOHny(Um++T=PAiJr55`4p9kr6FdzQ++vl!RCueMnb`|xgech$YP5vM`@ zau&|)UGKxTpz$FVkFmITi6iK&g{j3`_c7N(9%>)g;$-dLJBV>c6*V-7eihlB+=xJv zV~c1{m7C9Aizz9-Rqpdi{y=+#&+T^As-0NHs`3=PAc=Vl!|vUet{Vyf$aJg!M$lES z8*(Mke82p6_sBjM ziTrc0SD_Sk{cTXBge+CR14Rf0XxfN;JzE$GRhj@ZE4k8S={CweFlSkWH7r`ck2Vya z9cm|IoF!C)NOoR=V2yYr87O+k$R;~wd$P2un%vyjxlj&QPaRgT@? zg>X&GmadFmq9gw2X3e&oUx6@^94WumQP%x+iKC0D$(>J^>FxyL*aukAKyAr9EyCu)llKActhSo=a%82Yc`fUo_ z7Y1{7CRab=5=xR|^yr|=SHfP-r@l4e6<{0ZzPqf>q>07;ML~TkK66^L1jc1%s zpu zTZ@ymKq+WSBG3%rU2O48TDer^rTyt= z&UI&7q>2B5P@BKX2H@-Fl*)>jQKTTbh!}e`{{F=|^YX$ss)ADBZtY8jh_=mSzNid* z<8g7Mojt9;S+kUsOzW28Po-jk4rmI9jI}!64E$h4MLF9A&QEqB40zt662h2*h?*fD z@dNT-97@ApXSgR3b^$-1VdO8dQ`bbs?I0w75Jq8hbI$f5^XD^<>=3{S$7p=Cf${&q z^@y;--!CCJtY_G&*QdC1FbX3Og-60RSlg)Efz@~cFP@Y0;VnM!KQ7XLJsi{0=KE2P z;dU#Ojnd%Me^L;X_`6SoxgXP)X@)d5hPE}9x;2Kf73&W#@YOK|tvNr`AB-8(Kh%NI z{fJKJeRArZU2!Ujp^a*i1?&y$!~dz?p4fQ_zML~3(cT1qnyzP1RZt0Ea79t8x(3A_ ztL{82rS{)2QxT`<@g;Rgqo%}(0FJ( z#WKb!<{4RMN^f`9+!O`S$>;egaQdt1r%sz|8+S{bir}u6#BF~`3|etGC2bs1>29~B z(CGk{05SY3(vWk<${}ehnw{U@`@1!v1Hn3d;}`sNa8o@%SbGPlA1KB6eJ5aHrXgMkU3dqJ)iR2z>vk-ecHRZzWPs3n8pp9i;e(d$m@*c%Ky^gO`(;50EY_R6p+< zsm@Db}r4BS*R^?OS!Cc?lCahdHpHbBA|cS{k+j&?nFv zE#A@pz4dW0J#1L_JEZyrL&3tGP(6%!%r2pujgJbt2rwUziizQV?#sQY>@OU`kU!kK zHQd=rt@`2M771y-! zz*6{aiZD3_uz>@q4AD3{jfS5}p*VP?9FD4;FB4}ZR`5VSZ=61d6VKr>e?l(L}-6Xau^ z&Ypt3vAy7aVs8lJwL5jES&fu*_Sm;*30n16Y|b}Tap9_(N|LYn5IwGta?&bn0|6!#*aUOK50(IA0f$ zFgz;{N{VuGXlR%Ge-_Zt9)`emAANvZewO}~>$%)?Vyj9YlOSO0j{vOpTJk0m=HD2*#8_oi zlv*e|z~HW7TL0emfkWcI_Mcn+6XM@zm_2<0UK6*C3)~jq8lh|i5d%J>xBi)CjkyIs zi~Ug{e=7_bQ39zE&(9=dpO5>Kw6j`TkXnXcj-KhQC5X^9t?psku`bGJkP|#G8@X@b zp!B+=wpTbt9r;as>-BAc`1>IpP}cZ%M1Eq@&}7G@Ys&V(?9O&^BY)yR+mfP*zCJ*m zi~$mn=Y1Y$i<^Sh1>Razxu?;-cmC^pA|ek+t-qW|fEL4JSt2(U%D%^96IxXA>OZ!C zxT}%cszs5iI8-8@8Q7^#90jVj8oB@318U=IRBWH<&cMpD%H8MKMAsEa5(ifhk0qcV z332{a}i8VX^K)7z}Yme{ia)gubwET!oP({pp{L zB9@K{_bbK0+o#M^wdm1^p%B4^8T0!Zgh~CMBwWNOp1-{;@(_xWwh9FMN#*|Tf^B@u zuwlf4j&tP>nl!}{UDLtQ5bNR~mpZ8vNa3UIiOxi? z%~wq)DD{a)Y7mH+WsJO!96Hcq;+Y%689L$_u+``&ml$t#i@gDNled>uK+kSN_^*R9 zCWSA7pn$*EmsL%MTSSK0IsXVcSDTL4j&=Tpmc4(+CjR#SeVjatKRho(z~kn9KW~%t zh2LsMYj-qqRFCjZ2;~0!_DP$451ZsjyfvWQ zJRU_CKF<@M#~VYsz~;fiEC+4 z^sHsmAD9sM6QH-V234FZpBag)ZWF0%w-yU7O_94pXCRX9Al4OxCWL()Q=?>e!e{|} zMNHG4ie>~H7G~Whwmj0Ia{68)Ys&PHk?m%-)R*{4K`WAezt3YTtoImiVX`|BJp<6e zY#It7Q`MMsSBS1mFx!d$qVIq=BY_;6&>T>@+U&rb5Y-6u4jAAUlvYN5iTjZc3v@S@ zb3`B?Yo2o2zBkGn01;R~@fmHl*Ye}0bTG?WW)&ohDh9K1@)iW~Ds-;>7=m&;x0r;Q zmpq1kT_ce>Gb?-t>!BMFkJB6t(uRIfFy#HlS&Q}sQuf@?8iht5cOkccm63Vp!c(Qe zYoU^;_Kj?Ak%9o)!umqWufIMdeKQ`-m5<0-DV{EoHCT_`_Kf-dCm)G51Mm|IiS}(z z;&h{!8!6NNJK+wW7eefwl8A79Qi(-{BGk7Y;YD%_xbQECt&nltTcJZcl!urnbh{K0 zeLyj~8iRpr=@?W?G~S=ub@PKbw?W}<<}DRjxfeDA3z~%a6nJpqh|8Yb(~G%F^!D(+ z-d}w9P_(REl>w=4acl!>S6FS|BrCqk-_t_|{uHS6jMeX2m)PcXSqHTNqh5J|pF*_- z%~(s69?DR1f%!S5p+rSfjeOe_y_K_J5UpC)@nn7BaLQ9;G4IKz>2yyqG8v@#%kX* z+Q-AM+;8XzTJJW&YgXkG8(5GU@xo8oDPkiudSB#FZwpqS0B8N^Oy_*V*pBIPGlh?% zBe80}Gt;dk0i`SprX>o`OCgv>A9w9EVU=G1GUX23Qs{xO>0x`QFm+UEu*sw?pZb6c z!ge64Dwzvb!jnz(mb&oWH&`mf0ROTTdB`wOHpc~Bhh@mHZ`vr!uTY{;e9PcIb~9F- z%E&1wRGx|$qp#Kffbz|&%=+_ok^hqJe#@T;2UyZ&nT@RiJVw{Ya|ef6dr9Gquo9Xp zGE|&=Fv1W>91{E#N!U9li7-|2u9LsaZr7XNThOPQ8l_r5D`;6uhxQxYrDp*Yl9+U7 z`V3I&k?;Ed1#et%5ATBhN#5RPnmO;}{QG+BTbE;v<1I?@nK!MM@ilGQ94Z{RwMg5A zm~XzBLguz2ghl0_sv5i5*$0UcYh9o7Xf?RVH@)jfhRYT_5d=H}3SozxZT+vWG!DyC zYdgPK0%Xqw0RRK%xUX#Gj$_iSdzP4i;O~!m)sfI=3R{iH>af5+(EKMWWx^brm0fcX z!f$kP%FxIE%Nn*+xm{TcIqPwXph-j*l3>bT?l)+fbb3%#18=}#2fzV(Zd`L8X6;ipE zP=hR$q!8^};2-&wD-1;gNtD0G0dnfnF5VoDfS>poxadi*+kK+vcSWav>B9D9B+7XFTNmXQ}FRsbekE-VC)pDxaze$a18HEv=-_ zOm9;NsJk_4Ms&=aZnqFu($;(QTIU=fTK6n|RBu`XRKu9Xsy#*12WN@(w91ZcLW4*3 zCo~hdw3LjN%NnoO^V#qEXGgBZAiK1#uZ^zN%dM4X9xqjUct|iYs39$y!T#q}G-%|E zt3USKloPesO*GJ;Y$Lq%xYi@!$m*dYoXLSoM{b(Sv3_bQJ0mFd-zqfln(NdXa+Izf zou19NWtBFyhj}}NUT$S>Wv*e^O}bIPf*r@+w`fTKXL1S=yz%19$Fis99Iwol$(;`L zD0fB?TTd-smfvlNJ(LP|Rf)m5sHc=i}Tu~DDxK5|p&MC*k z+V)DIgemB`mmF)>v0XWf4pFE_MSS=7`dxm`HRMYwNzON%DS4>=J72t=x?{?P3qLDY zRmclnI@cog*5j>H3BlKn$cHOg068Di)3^IhPHf%n_tJ#g<1}aRxCPWd#^%?;qZ7|x zRr>qHCTWfyo0jAeQ_rSZXNjh|>&jNDhgz|G;K6V$fhTWEx28J3LNmzV0XVSL7GUI3 z7SyCQaz4z205mRj2kdJp^#mSKvIUSWJA$F9A1BA#e*6URO`+q$@CrY9Lb6(Yu{Zu? z+Chb4s*mHF3`5+IR6n_Zg16 zc_uPC0WOEZg+qcg)%<-M{2s3EK$Qa4V^+ca=W>p7ux{F4oi8_*@1~m3PE6DGawYD+ za7UIl?4=EgQmMoy{FcRAw~La~L!3d~a9_r|6`)mfg~rj}7n3~PjIp#!u~2nYe&W7d zewp5E`fiRj{P>zJBW8`Y_0%`a|>sw<7;>h#hcVySwKizyHmn~lSqNV5l?{!s9tv}8mwg_&kQYKGoT;~4UeGyEr51=__ z7w>M6ZUh#r$7i^cfmNs2GKw|vsx?P!4*KW@-r_Ej0F}fgK$2E?35kqV97(-lT8qu( z(wMM(f^}>}l#Kb$Pb~66iqOgnp}4BLB&YLS@TSU#&ixr%8)+%Kh1ZaLP`K<1Pc_mm z5H!{zN}@5}eOk;UWDA0N>~azAoat$O5p3E?;_$t3E(MebY{oeT%ntuyXI3a7WD9DB z$6vyIV-5H+p(z|o5ztSL9TaCVZ?DdkQbX$sZwYPn`?J?l`xrZmmgJRhx&HRI2xk*I za$dQnsn-YAg5ULdhj-${@FpQUEJETAYVEr(Bos~;i;#MZ19wSFeMTmDe&T>~{Td8D z2qu%9SLA?g8Vz8Q~i`K1g!7GbWZNQA)H992e~Mga?}va zV#zMzViahnV!B}gTC3#V!%wu_Jt(6%X1BX0@6O_Er$v(VF|%T;;x@FxSg>FlDv#3y z{F)~3tYgZeA|T|)P7C()QKnmIsBiXX zMtk@a{um0r^FdCUR062lM});yyM%9{<6IN-gv1r{}p5FFsv5_a9CF;)-Ukbd%lOXJD9YyA&DA%Iq*1 z{#>zb_ki3W!69TG*Tq@$C+LI`PA|AmicT`D70CN^asG2>w{$JgTJt?PLGIX0(D;k) zbp52hA+uZ3m`GHv`Mh%x>lddUKLG*hn4@%9nqs+^KiVRQv!kxz;0mWxgOQ+>{c$1T zub*qHsxU+aLC~;V3ALV|{JkyWJcu-|T>*#Q3^t?w^zZTer;l{253Ubuy4k}?kzH$d zKe%sIz{E29)10P8DqsBhD_xuo2B~R*D&x5j@2qp3x{BW2VQC7|-J6@;#+q~X@tfP0 zb-D#q+z?n&NnjIai!bxY%v+%-%gCJoA;AO3NKy++wG3&d+T*X-20Xlj3c8`%72KoC zoIV(wn}38y_>xv?^2*0z+RT1v=~#9biv2mc_>Df%eo5_M23cW~bfE&_D(X(+vr?Aj zOkd@Oc^+7I-}c9ZmQq4t@0gDqVZhA8LOV}zSo(28)JR=>|7?AQA`sF8C%k=eI5qb z5Zfkb~Jm>Zf4s1`Q16hsHeU-Jns*FW05gs&T->EgEM}Zz?^v~a^CT;)yT6l z+K-S|yReSNpq!`{z~UF7iD2(Tu=G_Y(0WO!a7;oE$n2R3ESQ=&2wsqjzelPC?QUIG z5p$Q8s)nHTmxy_1(CDbeLL{;ai?p+AJ2)VH(=$8~LOgd~uW)JA@%8v7esC|sP*q)m zyl5s9szyCdZ9FkEkYFG@t4`u*Vaas$pbg7mTu>~%R?+DpU!tai6$CGhIuK{EgAdK= z%Y~|7$b3*w{{hkna+z;{c`<;fLk%t0zk0-W{V1f2ulX%S1B#hd>y6>_fzuM zSMHztM5#ziGko;CI4sDPI@p2r#}!eK?WuZd^}Lq~njZP&EMdu|;~oq(8qgCsAPx&^ zopN210gVPAu^2geE;O`E%{&Ca2%`y)qs!AAwhIAE5GDwk9`q&ypwkOmOt#fTCGL=T zH7R6Lfw&4L^XnWwtw%p3p;R%CkMD7N_Wh zl|qVk%xZ6MhL|35g6b%ZHoh;EN&20(ly2Fb^-mPWE`&A&n<-D{9sFqC%zNDfL9Jd1 zLQRqWXjZo6=iWN0Dj8{wSF!zWx!mf&)3htQ7ScB9WS8Ir4zw*u9a@_wAz*oSu1QL+ zj*erZ7dd|uOA)8}Y{Rg}DlVpV1hwj_4Di>ffgL@cTF$bcB<(mIHtokCo^d&yf-aJ_ zHwdC)@$B@ADeNQkAGXi$ngM^KJFX+(9?~=u0Mt+trvrGU%Zd1w+UZrRy}3J3n8}wf zJe5aDtmd_K0pPr0w9<`deF@}hgaEKP7R1YY6dAyLjdsJXc1BX0nQ&5ql$L2Mo;??l zokR(25>HYL6(@Dew3pYxa%R$IofLEF+i&k>E1MAIxM))LzhKs{pgSC;FrZ*-?}aAc z8(8EPU%5bc*0l0EaoWxxH13^tyQJw14rD6EDC7kDuXrFNZZM%2=A+|+GFi0lM^6DPtYw;U6FpfgJo>Q_bxNG(e6Ig{?{}K8? zr97Kp?W`D&1mE?zi3XDUGkjvE<8^^u5BC_}8#2|MCkB4j#i{LWZmo8%KPz~KkfdoQ z2+IpnLveNT*G8}6-!cZ>mtQbJSWk6QI%pj;-a|TgLdl!zwk0@k<+|NsTDJi4L;j$P z4p^oidKqgFmP6u1gPT3I8M+nh!kQCv7xNdIi3i=}(lq4y39`Bhi>?}ZilcfmJmbWQ z!p?3Mm65fIl~Im^m+iL|he4z6Rt{XERV(Q5p^3I(D=#0rO91(z^`4rDy5NK67dEqZ@F^ybf82i^U$pf?ZvNJJmiR@a z0lDh9jo-u`-M+Wn-DD2GJ@|_Lx-bFh#;0<@of_esj0XRcp}fluLM`~9(S7yUE3<46 zYf9s1PsswT90N#ooVCa-w}Nz*dsUmc+ChcJdmY5f1hmKMd!NR{QcmhOx{ckS3eiUt zXI?DeRIbJ+YUQ}aJA0Wq*!S~KGi0usixLYOYxC4O$2L{i#!^Q(-PceIGim+fBTsSq z5oI5sX-xGa^uB2LGR-jHzGe4X*qZCmC2hkvLsn-5}eREI0y#u0Jrw=GzUPqbl=Sa|6Xn5d1{(&I$lHb&vavS1e-vsh9z zzr$ca61M@eQAjZkCQiOs-Be+|bOo|894*)6Z%4Hnu*sRi{4+|6QBw}AzCN-ox$eSc<=md{j3uKMnig4?LdE*&eHkicE*V)`jax;c)i3EvVsgI_qr9BqImR-hpTHC&*FpFd?qtxi{ zF;|i+4fEW4p3Vqu#`FWWIuI__m%<4_X-7?#QmdU4+X9C#r|+O^Kry@LS37Iaj@-mT z>qL!siEmogJ0bP_0a*H8L5RhfTa{vrft!)3Si-6JBf2s3rMQT6kT@$9K{WLuolJ*x zM7j$||1=3-FwP05dBbGdtcRx2_nn4Qo93-vzr+(ka~EHF@8o^iWM$8Sv`lzQ-Ssu6 z-fW8!HL)Lxp=wNR?>#i$@QtG(&q#kIK82UJR#JGe*#k-fT62hi`JjFXOEcNNp(uaD zU)jsHt~aWVY0`kH!{I?DP^O6%hT}5HJwkG6^Z_MK7@h3ZmIt|4R8_|W-Ds0D`*jU{ zA9Y3a-hfC+CXXNE#2;B&8gEF++he0Vqn5V(-(fwov?$Ffu{3Q_y#{2DwC+C2Db2rZ zpD=fg`lRZ&aUGqaCISP$an+USv4$4>1ithwP_6|5OUM{P`5@!}D&%=)AqmDPkwW{ud|QttS^ROWJCQORz)Q7R0D>x9&w8i^p(xLl@n(O__g!8gbtL>q zL3LOtGJ~);J7KXiYJ)BYcoVQS$3Hud8(yefr!3w)dX7qRXE=BI z<{+de$)V>kd=>xh0zowk6VFV{ueK7Xag!INFjs_w{w6hMrWd<0 zRNQ*hqOA3M%(Q3{QMLLO8Eb^2ESmt2b7M{;0N=#-CTy9T|1+nA7jOT(jv8;DWJ&5r zw_X?~VM*)!A@rZG-M6B3nDf_f0#~ zU7-pRG5z9~7KOHs+xA$~)qcb1%v6G+MZ=jLVD!9z0Dq5loKN=3Y<1m3>oGclEw7JC ztRQ-7CiB*687GIH!VB*-<=ailGi<*@ z0S2=6=TeOY)S9gtu~&oJ?i95SRsjYqvaQf+{(Aa3gpZju0u*~59&3A?qfl7Jik(us zVvr-hq2ZnJKL9!1)#L6Uz$X^pe2ZEo>+N7oayqatWB)!b8{TZ_td!R}ova z!>2V1EcizNB0|16A=u&Li|6f^&dgU05Zq5AoG32VmKnnH4gEA9P}Si?=bMbco`Dvn zp#l(4Qdu&|<0 z<|i9NUJvA&F~wHc>V({6P29!Dk8Yt+E4Q5g6!q^F@@q- z`^jsQX04xN zqg3p>O^GhfQPWHW+PftuWk;JonucED$P7c|f*>WHE&Ql?8~@S3QvT?O2W6uIYj0~l znWQ4ugHlD6_ZVx!I_k2vLTP#e>a=6Vqi z%RuxXxikH$vda*4V3Bp1^g>l!<3pPgjf5cPLEOM3?o&REB>TY3->%mQcPZB*hV2`N z%U48SpLaL^+W?6*oVToi*XPsCXl#}_V>g}3em5A!-`Ca%wAQL<(gdObe^@fq3&Nc< z%s21TTJ>jKwT23(SSMp~8dLMIyVt4K84M;sI*H*(Ay0q!^e?Zy#FL)?3BF%qk32>H zHC|7uLK14Zt6EKG>ok8_Sxdc=I9T(c{gzWii7)WEK5?2%K1m+^tC(o(S--V>(XI95 zMKtRS?Z}iZ3QMn&E;Q6en2xY|B~HK0=ND?WxenWyD?p{XnKh~`3c8n_{cjFUDFX#wyOH8x7ZV@>I+}v*|dC=G(JG{3s%5uJ{CdpS_-u`>bw4{ zC;43z;QZ)&Of?G+dbpKDyT%4$EruLwtF5cr1r9TKJExP!bUcpvkdp;yG5v^7N2QnU+`_xLTGWnTlZ?yUX5{o0g9QJFt5pBIQyV zVtLPMp9voP!P|sxdKI0siOb8f_#k>0SDxDV^zr!kLhuh8-@poFG z$9;oqlx7nU!f2r3)h=V6_NTG{r_}3#;%-(3Zo!JgyhP40#qGYnm{mATPiy!J5I*^U zPt#~ytoP=Y4o?q=&Tb!Cnp!WH#SJ`6im09Q&CK-r)yK0ncrl`~XvNje4tH#k&M)N&C%V>szkO;bdji?r@TmN?B~UM z;JgltB+v~hq-!Kf@UK^O-V;?eFkT(tt^S$GrBuBhowIOheb=^tt>vX zfmi$PApaOGh{i=yP8{S?Ly;_3@;9{rCPSHWJ2wPr$o{*LVR6D)@A<^@J#e}w#=VZ1Dmn14r90iLBg^E-8x=IwF;a`LJm>j!{BwLrqOrGFWE zQUCUTci$35&=9SGSUjUBF7Pt6@qZcm1%609AT_^F{M=qViZu-E7^M*3o&%1cyTf}t z2ez@OUnvIw(w;*jUekW625_NUeQTmz$PY#Nb2R4H>(hXN0=Rfk-H0IiA;GwLrO+qR z8);$mTvWcjGa-` z1wfW;Fiqs?UnSJWNDLiAjeEhQ7{xeOdJL3N8pX>jE;+Z}W}y2ZTCT2ro6hb^7+XTFh@6zdbb(UfHZmNQCYOy3`1{C=TJEz{U7t zqhp;R*g-_tIzR2xFO0otZ?0)iwrl&6?BJYU-INx6z(;OtXF|PfDRb|%7RAiK_G+5yO6+x&W4Vvqyl?Zxm6Kl3vas)Hq z_(Khd+12Anthj2BIt_HDF~*N7PODLiJVF66wT;sy^b|Q%j2acFQZDhTC3dQAHN~+S zXWp{$EzWizNv5Q9$x-^;c|W4@pKgV?ut?DuWIN*`ngy2NnO6ep`Gzqe~OIn;<*1g&t- z2b`-gO%VTSiKXxXgJT839GXmeoj#h~&II9eC{M0@cztEJO1y>bZcM+Q!kIF6zIJ95 z$iGL-ZC-9yR9N)F!Qd}VN@%^S^$2GMHaw?QI^!Wc!h0@1L)jVJ^n=5sg-$Nhd6 zucf~?i>IYef5c(E$!+v}+c$46rlkj26`4!}XJd~XN6$eek$YM+J9FA?WE)q3uJsyd zy1jzz`X&NGkeA#*z-k9723ILHjpR5A#$O1s52~Lt0>0}Pd~)=7_F^uni*itl&+$DI zEB>-6CeXEJu-!!u-f@go$UQpexSnU5AQb@LxX2KE7O`+MYnL;rWpzfbZCvfTq5u~st=d=7OmdJ$b@v4yV$mRYOD zn2;Gm)N$Fw({NN=QHW;DK%2NZG0$XM-!q2bG*>(zQSQFh4ZnT7-PxdbNm4hZXj8W$ zb|>SYL)tZsYrHVYIFY2W@c#@Nn$Zh6>GPA}L3 zn`8fiF5=iY7pr!Fgbg_Z-hYP56D~8Cn|0aX+5v!H>{cbXLH7}R`?=I-EM;D?;-Exg zQGr5E_DpwwBwVi_gki^0zGq~neAXMsWMYpJ=ASN5lyVZ*AKI2)q(Zo89VBIu2J~ev3lI0djF^R zt_b{fzVJ`lC(S#Q+Cq62y{?#*qxU&;^u*7Qd+Tkwl!y~G8e3J9ybR;vVB=889Ng~_ zGI@ge9zVbl!@ANjUM#T-y%Q6&nIX~wPT?7xOk&TSsnV@|)3+!>iao4)Nh;7!R^pt8 zTmBflT(^BMtNZQL6g9&H8(=_D`iF+pSWL%#F*Ok`yn`Cwm&BkpBa;q4pK^7MP~>cX zWW)|S$jp6)j8<9&wlcLWo5rQAlMDL0*+u1ghkMc57R@{F5S(bB3lrF7cA9o2r(`m` z2aj3!Y?)85TnNDvoE~o#n5(iATSP#bTOiv&@^dW9km3gue=8llTU|pwTxKE;cM{Bu z5W4#rK5vI5d_8}VrHbynP9e}5<{QdxM~3l)(hLO5llfY0ali2?RC%9>W9Xo6Ixp`Y zU(>ncVY3?%V#0_Nl_m6AG<>2z!gdegP5X;Bf(s_l!Qd zQfKHyT0J?Ct2aZ<%kzC~UkRAX7 z(m2KVYoQ>e;T=ol4}aQc(K4FOG>ZFJzheZjBNU&R_K7U()}u6bRPZxFSg~pw%fJ@x6YQ`>Y9;C5rRmH1}Cso zm@23jEL>f+^$VeYrsF%di$ag@8RqvwHcYs!PNF&TPbdyxP64RQOfewKnj>#YB z)a8pd1tQIn4}#e+Zjo*bg2eT~9Xy~-rlw_A-O$-QFe2RxR^POrErYg^h3z32-wWe= zA6_N0qxul_=opjBc#!VE7+~sW$=}TE3}h*9R7;l*HSR8fH+b%IfAw4Bzb%lndLtCX zdqp}?dLJ>FWQp)HIur-+@7eTVG7r!%<@NlY?33-NUPPnTy^sUJZa^j{p)np`6zJbR zff`uv-IarDWK{g}J~C*sy~uOFE#1I|58Kj2HZ6f4^~+Tx5i*OL+?j+Ke+ZkWXLFyd zXEm11JirmwQr8rB7E7lO-S)+`(JIa!t1N~{Jq^EaJH_Bxy5|aN^NO;Dlx{{IGmO-h z2T>f5mJ4IwvKtCTSpys50+_RU-j`&nGs;e~q6aF!Ps0RhI8Gt~B5Lzei3mTe?-(%r zzGqE3I;j0?Yx6Yj959#Hw)1z8Y#eH0f;ZUnY|GHk9rD*8#n0(|gMX>$B!n5fa6hMb zAQioK6lq;T(3E^)D;oUJa!VR%kl)oSpvV=cfJtt92KdO|oHO;5gu;!5DL;T2w+qV| zFLCh0*f8I|UFi#wb*Lw4*TLUD)vV{>g^n}aeDVLqk!WyJ*2-aC-_z2{p<`}a8|(0} zUMFAdXb2$R^KO7jUu_ZYI{)1k>h}E$TXL70As9{Ln81x);cL`)NO-8W=dyKH3R!zO z-o8{aj(;LjWRrBXyW1U}aS1Z_qGN9~U!%)_dq8Ev0vQ~eSeSK?#=?9d_AUXxuf}E2 zNwYF+DFgnApl_N(cxq}#??>m8D=f2a<^$G?43enscG9SD!SMglc8|e%sO#=+BfReVDmDu&}uy?>H}nB*B?5d{+j4JBLdINL(P`UX-LIzRN{tQc9Mk^=*Mv zboSX)(Ssr8^qib1L#Xp%VYE0$rB2pIP%*aXHaZ(y8%kcEZhk6KZDzrZ(#%Grx>pgO zcZpFn7}0|=a@hC0rY4eh2f}^6D~I@zY9U)EZA-d@{LKHf!}JOD&`sbJ+rx;H42tsV zZN;#>3{UX&4csq%uShJ?!J~Ni+x+<{3d%i3OXOo>{Top9$XmG6@Pcd zF|oi>O>ZE@iU)h=DtaQ9VEMN4oXjOMk2f|ZD_HhiP-SGO1JDQ8DZ+Ad{C&)FQD?K$APsdnA7X6}^>R>LdZwMh$mU?rLX@sTxLj{=YiR_vx@f_XQ z;B4_f^I#lgod6Tezw%(05I`P`M=@K(Mn73@&FBosgFB!Ad9e9af#fGeU96}Nk~Wq} zv;{B@+!X9e*T#kIse;hRNfU2H{mARxy9Y>G>EA|`-Rt)s4dU38CMq>{;GnzX8g!zX z`M8IlteF%V+|RdkqUBt*8{yK=>a4W1vucZ)`hzq}&$-%hbB0ncg+H1JiXtSfhMP6X z=vM)T9EW-y5w$68T}9tzzF>1vmprEJeqF=q+&|{w7ASU%-%w|4#thH}q`_`aH~&h5 z?K6K4bcOW`-%G7pB^HYnl*q@HFB`o=(ZJhdM3jn8lvMNyCy-U}fBxFy5<#WXVX1<3 z{cA9+Q$R<4KuN7497}{!+QHd4T|#NnpfsbsPLI(qd}P?~R;&WfJ(_%so{=diVQ_vS zwfQJTi*cjcNx@Dg=pQa?*DPyS{hpj*r}+y=X-){!#kr471L5!|vDpAYhEnt`Bbcqg zTQ-w(|KWjdl4Y4cU((?Mm;&cjK3SZm)Rv&@`;ka$G`|h;bQgy6UR5XOf4O zLa1ypXQ6vyILt5L3~Hj5(FAdM*8$QGRxix3HT-vQVzP}(0Y=g;?Pnh z=Cg3PY~{HtZ16eF=a3hs#iN1n*G;vqEu?oYLB_O%*8!pGT+^J5ev6;-D`8?xO%-kD zHzF5sYI0)5;d^JaqnAISlJcy<+mF=K`N_GKiLmFRvsv&_%krOb?pTPMHz%w08T-FxDgruXc@79eD;l4jeoa<}3j(%= z-0E0^RV0KH`rDfsTnvAYSM5+Ye#@67I-$mzNBXC*ph z&e3GEXeMj^4Mi3)%*~mP^^<{gV@c)lMt`@zE9d{G{UveztNq2ADykX$)&8~x^0rDE z7j+CpK+^w^w1>OaNXoEA5x#K|8k5&U$jM`&=)p7<5;Y-5S>mMu4>k2*$*rMAQKHr* zOg|!BY|?8I1{A=OM{fTrfc>AI9dxM^e`>ifhgX_Kkqh%^Ph-b6F5|Gd6!JP}+FY3b z8KpFZ+mQ?>?@zt|o&BEC{=a6wwaffP70f4mzq4P85V+sjZ;l533oi)e zK{|#-*bSqJUtA9rnqnSlK_C?uOg}g%4? z6cy09-s~L-H_mp&*}Z!s`@bAGpCv6j4vObJ_*`Z|wAr~ngGb?xYmNpp`?7=qK?KDG z@h*}QX}b1Tg7p+^`2-C{mMF3H*9`QyN$jLt-SEKQD)yH}yF-s2Iw!vsh3A{VGgio- z9qxUdGWz6BwRmadheABN`}pAGJ9K1g{SzvuYK|v}RzSyl3EMs+SXtr96XYt@?u>Fc zY4M8K4r>XFVTDkI$dpv72Dsu`D@U>*XuVy;f*eKa6Yjwoo3)x_eFoH(Tr>3@71*HS z>SvWexL8a>hPD_@_hlv&USz7P$jE?L+;++yn4TC-aY49^2}A}!mMo#&bx+6^0KX^9 zkg}^PUkE8~Kq>m6*d~dgDvc3+CPGKL8>4c#ZsDuG3}iZ_WRaO95e}?FF?cW^HjZ3( zqHqstW%sZQixKL3jiXAw5!9W9^9L-%tb8mZbB&l`g3qtFfWgSZ;fD>PL9{9DW=ayP zqI;;sz#8b@FXwGqZ;^+}X@hRB&lwT}O2G6__LAtsTYi`(Ug&d6=7W)n=;rD@?rhDK z^&S?Xn4(icXIe~(z+(Dm z#L<*kD(f5pS3Z-tHrzQf3g3tep#l3$%yqkT``iw9r+$xa;rDR|8*O*c3#2pi)U=shkHc3pEk-#l+6?~SZ)z;N z6%QsOXfPDTV$-mjkA{^*Eq(fH-x{i zcH?Hy%nvTIr7nhec+_fxlfEVZ_|07B|VcaZ7LZ(PM=l zmt~se8Na>21aijRq|hoCx?C(Dc|fF3r@WD#zB1CDpDg<8H-Bj$zLdD^TjgNODG8<@ zz~!B0tltWc+jWCKS0%t+N8@yJoLT*DyrgjnJl&&x>d~t9d@ljfC~>B<*!PyyRT?eq zGDWhqrU$=SrFlJ7W4XOY*5{w{k+=~vpGyVwVt;Iaj-7(9XS^i3tov)Wf zv`T3-|D7m*O8k{5x0`&IoWD9t{U=c#s^8Y^7XQDAa>3Z|M0rTM^I-y4YJhzV3S63W z!K(?lthai#&C-#3a()-agob}x(HyKO8Az3b zy>h2hSs88XfQus0e&N6&YhN#8i$$dd*6PXqieRjb>y%=a%dhc5hUq08#?H-H&I}D@ zQ`OoWtR{g-ew7I;ehk(l$Wl|pa<>>$G3fQ5zr0Q^`?o_B?#4zWJ)3)PW}y1vN!tg7 zjpFLZpexY7bW64MU@`=-1RN%-F~Xm`P%x0TWCu1En}0B0B#=;v z7*Z-!cpLW%Z)+fFD#@qS&F(m=+=#~W#xtB}>EPOpJyPf{oohN3m8P?Y_>-;56j*}}T<`W1-`qdDe$Wt_ zNG|J3gR$(Vgsu7JWwqOKKA?2hO^#6s&6{e)@Gutf<6|Z)|7U?)0$>9$d*DJ%H0GnU z$&iLPJ7%KOWW?a9;Tm#}vfvo&>oN7hbgEj|2q6y|sPcwQF!&gDWt7mwxr=fzy9zkB zJ`B($3KCf+I3QTg6Ec)L_)Zko_A<}l71pzB85SF2CZ_K z?JbDHNHy7Uzfyl*YHO5$(YnpB&%`Fq$Dy5MO1y5EfV~09%8vADeY!eLiOJb|yVRF* zKuI_jKMi2#$7FDTDKN@4rC9o=iKJt`>uBs~BON*|JYH;E^nN_(lKeHF307tyd0!aO zt6wSz-FPSzFp5&B#3!yJobdIz!MK@uIkj_Yr+WqVZJLVHW!)r@tymt3ckHEy5x`(3 zVN$f;u##(A5&p1Kk-AT$yeHPAiJTe3VXB>46SS+96$0SwwKCM7x#wLCv60mifmMsFCD7Y4@Qxc9Zmfkbkh9V5u(QwN| z9ZfuBKEBLDcJ+;8j=))~mtV)$8$)?(b0=wgx?KZh{RF5S)IN+?6z$l9jEuYFQ17 zO44pSo$ExNWJ_PLL&|`*EAURQRln~0z65)hQe}1Q`1f>WV<#dH8`!N6px$$Hi1K>} zhv*T?`GH4Zs;FDD#_DF9<)vIiSwQvk6!Figr}sjqgb+MoHOP%E%XPc5N<&Y>os zWavx?vsS)VuZBG9-tFJLC!s)b;&EXDNg&Kq8YC2phb^TPM9J3^S0as4{kZ`8P<43+ zPb-<$Jl&GKR-&JnRRdQSJMUoASHEM=b1%hTN^=y?+&iO3Y1fIrWh+M}61c?58GjmM zuyP(PbeX3$ff4|Tig~|G>3(}e>SXJ+FAG*985SwY`CjhWrzC2*6f8E+!>hj8hio$c zo(eHAUrhl(+z)4yEHm`E$ov!*XBLQ9;RfZ276wG1BLO#b>EL(^$_T~mg4F-;Dr%Ue z_&PAQ=E2Mn5?*a*kx=xmkvPjCPHIWlWtr&*|{1%_!Ov(#DNYoDC z7$LvMu9nUJy>`5%gPG1&-^|0M7r+TIe%zs~{y1NS3xplx@p1rilP96hJLA~K=rnj& zU>)^Q&u^zte5BAF(lJA&Q-AkHLh&K^6AI9r78n+0p|4}YgoLKay3M9hSdpesqkI_P z{BxM{l!_~?MjyEp7{#?kETJ9uQzo`$+%}T!7+OT>av`{R2p;T* zbbvin$$SkCPU|<74^^ZC1E-X62;uoQWv?7k|I&mX3DBMjb3{=zC zZF6u#SdN9XADE!D4yJ9K5xA6r{ z(~mPD4ZRAIqXDc-5*v$yHWW&~Iy(Z+jG8nheSsdwq5a+<$}3&lCnN`sha-NGW<-t9$`1uzxUy`^bwwCo7TeS#=$X#_*m}wTNZKrIhy8NE7CH~c<*4@S4 z`*Hta{&CQmp2zcKRccz-;~W6XHysN)aOMn?Yj>8zbbtqWqdS3`T3umTCX5eF(t_8d zn;?31wOKbY7=Frj85Nu1WLvpk8mqVo1 z9do@=%heu4BmO@XO~%Ve-w$cpWRa1QzMB%?G81LAYs`|foxs+&t-nR*$ ztm<|{P9KHOik;6h`g_`1kkKlYwzV8o!W`C$2LMVQA-PTGr5QfXH<1W zHpLMFVQX4fh+w%V=wBmY_)v^XFFh3Q8?8(K-7KWjkiaD>@E9HA>P8-U8kMQm@M>?zmn$wE zyuH=we^Tw4TYo^ReY{c@`teVyO$5dGzE{SP?jywWj!|m}Pj}Wb`vJu-$NUY%ybeZ% z>?c_n3+}a>@;AwOwrFC}{7lMBgCH@@T-bCzP42huG6W`WqO_Nj9a|s1=c{-8mlyhX z*IZp}(z1I91&|PEyvX7M;2}^xO`7Y0TvR}+J>_lmv$pKNhT5^CnFoKB+L}gMYQ$|i z*1;%omd3dnFpuB%ZpS-EpG!0LWSfAN#Y@9M@D6XdSH}jxYQ>mXRWn= zLhUxa|Nlbm%Ixl^w=>am?KZJai{{Qb$4lJX1oU|y#nZ6SNl#5#CnoY@n2e6aF`!rI zms4wN)_U&7*-vQPF@@jn0f;)Sov70C8=S`7Uw%3u(!RLA7`d=rf%YhVSKIrYX{((t zPkP`0GVQ?Te`VT$b8Ejc?XW+YwglY&$+VHR5Vb;jkj?3C8mQAL>G=fHxsAt6Ncww> zV4-2a3t+ziF7`qSq;QmliV&NBf=rI5Kvg5NE1&Cdq0-xc-Uf%2&FPgUwI=@5zVEDjdU%-|jDIZJ+as~?!#`VvJ}`YeNW z@%pM^8!uyPcicl#+tka;vj!VsEG_>*)7u-W+UhH^lT~hE|3=e^exvCT|3cG8&OgQq z#!_`!-X>Q;WXrz@}bf3v(aAE$(En1?l|3 zOzRJ{^3hn?9|kktxYTCDVZIJ#=L&!+sf|eXoE%biaYKpw{PYz8b1F`A+q zc=kfNQhJ1_n)B>(^hP9CZb~pOjf44Psws`5c2w3(Jr<|9kd7H9LixB==&Fu}^d+KF zFlZc@X*{zT?{@*5i?%Z}(|y<&e<`qmWPNC1t_=M%POw8oK>Gb-?05QI6az@V12c9Z zwf6Om#(G=YcB5fflm*n`ezWK`l{IIOa^77FXmksZqabq-i8L2RmB2l-r2C^$!emO! z^<utJd%KzXsob zF!a`u_T+X)x<%fgs?ydF$6{;7U&VKk3#aJApW=ImdN{#K!=73S8OGSN6yj2GT)C6z z0!p^=M`;j7@5%8XepM!0G@jLjIThOU?1rrL)rj*?fP|ih*Q)}M(Bmqh6)}-4hMOTi zw7RrTuB}f~(0;1HBzxP_y6~jZI@nS)LEntM9X6qFl-A^@)xR+d;de9gGj$1z`b@L% z>=KhO;Wv&v!CnA0b?hS^KIYGqu?3zk2blB&`$uC5kn^ardl#V{!`eZ# zdd3|DB7kF04rtPLtny>7eOWGs>%tt&HOcsFQx8n5KPD&pEx>F15q?WBSLG9$_#YH~ z8-Su0xg6*=1o}sacUFqrUC}wjxW>A7WDNI%-h%<|CMU`#uS6=d7v1|X8#N_OLHFgD znQFoWv~%h8^-<2}sXs^5x=69N9E+2$mHqMC={1$SWAxhg?xqne2npq4U zW<)Ok zoK9+@S`pb11gi<)a1wp(d2A2 zJ^S;8ue7|iP*CpLc=0m)j`y9ePTCIV{j{^&sy01wF#A7>uzd}kwZhx3687% zV`uwM3;lf1i|EqWdVs13OITZ~$V}F1NKsK)fuC>eO`0bFA_q6Q{O-SZ-umVLU!AuB zH>R}5Kb`k#eVz0nUEOGC;_w_jD$MW5n?1%i7FX3mz8>tf6v>2_l$wFa>H;dzq0q(L z0Mh2PPzp5J5m<#_1W#qoi3J>=u({}IFb66VQ5jL7bqQIrNb$?~OyC4%f{k1s#9kA2 z4ZX7J?Y8J~ox)BZV+mOYy15Gncx4g5LAUzlplcBPa?sB|N6kdBTDqz;rYcJ^b}*-n zDUJ0c(H+c|@Yqq>scXB@Znp0$6ARceBB-_fhRxR+qv!YIyDqDLo8{gRr2q{*;f5EG zZ)fSW0;=p%-!pp&g);u%5jem|C*lKS+<+e3TYMiXgcm;oM<^bqCY40tXY_C97Wf%Ms-CaZQQLDnsJ2=H%5*dWA} zc>vc4tO=?}scOOt*B!P+wNj99yxboLeIMYUm+s=>SCP!v;@|rQgK*;i+d(JrrvTe< zlgy1O23a|Vuc)QS6?KBGOCnwzQtB3>_dcMpuB}{l6gbEoB^oCsB86j{_sZEN5M6A6C1OrGc2*C_ zCOAOo_L&WOH~d>pD!t#(N55ZFXxhO#17(%5aIPN} zS6qq(zBGnBdp8Et7%MAec9LP~>JAc4ul;xtagM`ln_#!h=;`8UG9HsSmG_|Yw^-Bx z0!eEv5tCE&$;3STlG#Vz>x01cp1n=Xs}h(eG`4a6*PimEblJM|%eV9|(fFRBD&mhu zdvq?`pW!=J_%f3vv(8Lf%wtHo6C)|NkoOCste6HAT$#J%T4K3-)WppHDW*=JrZ z-k0rX2B2!^kdqI_AqJ8AJm7;X>zF#Lm^wsgJ{hb-N@}4z@LyelDU3Sk!A7BKIKLGx zC6t+glMEOcEljBJZ!rJaNy2&5%}jP@C$NxHhQixmDpj^(_-pY9Bu1XF4gA?kO7#hD zsU!H|v^^j#Z`0*j0oR*uoz5~$p()8244@z-t0 zChB0@r*LbvtHmJ*NJ*@mEFxqH!hqh}FYNOyHOnLv{UVBk<;Ijb<2@WjI!c&Zsb-q+ zKU7g3ZQvl+KEgs!aj?f|6?~Q9+{Koz_Uq5xgYIeGz_SNH_{od{V?#C zgFadJ$3cHcfO2+exMf+;^uMN4hw4i!Udf5sRDo&U5Lm9j{Xnj==43)#0&)ZW3b&cp z?N_}!orl-p2Q%y$cBox;ZC^h56oQ`FhS%8^UI4`sY;*~nz$FsMigX4KSTr3h&IkB} zo3hdgd-7WM#Sq*s2)Y7J;$f(QK8`+rx!~wPf^)~%S{Cyjv(U6mbl}&@SSaI2n%|1Q%(%gP9M|6Qi*@p)-I|5K(@5&S9B>0$(st4JUn|67@k!UWn& z<;}PNLRVOdt)d0*pGhxnQNg;*s&C#~+VqDa*Ynh>pdjZ5@Zz0U-2kL~I354=w^H6I zru)Y#SLnq54U%7)*_z2oBQ_}iehsl33hne?jU1h21SaV;%*iBJ2WSq!S4Nz77D( z?t$~?p}#-*AE_PiB81a3;1Pz+03-cU8LkG>S^!bvU1*5AV3d(@b0=P0H(Z!6aR!q* zw-Hj=F_65i;N?Kd7OR8%8-L+UMgO7kF{|2Y)Hef!RySSQxm0>quQFdM|k)H-V%5%gHwS`01Y2_$TsfvFy=+j}Ve=+Fo(y&tO z8FOhYG%=17myxjLD!5Cfo5L}gXvs#YhX4k>c!nglcLC8zJiPRfucYP=gP!#GlW?W4 z7rMew{+JCn9-~$jPKcf65MiBV7cr_?D%df-1>{S-F*ifDZxJ3UixrbH&l@*ATDFl< z;FOF3hv}+fj*moQgv7cbCV6H-ZU~Nw$ck-3r>r{ihnxLK!oEcH(*owhlO$f5sHK3$ zP}Y%N^@SZe#DK<}1v~kN%l9EhG;TcW7Uxj8f~UpTNcS={Sb>Sf@~PabnauA*o4$@< z<(k($Fw#uk`~__~#j)7V84wsSbrHZTjUST;;A7TBhP)4~)=j5L^hm}_p>aRT>bRV; z|8E8z?kT6==gaf=%j5R`{v2Jn_owUTkayf(pO@uXSF!Fkf-W9TPVSeJ3xaK(nCUM? zV%={8V=qH5H{W;V4$h8faX2`i&NDFnFz5t3R*SzG^ezw|v?=$|L?Zc5=~jim7<93a z8*cx*RYCC8$gqDRb=6;yy8FwoNIg63pGZC4Uo^@)It1-=C>nN;jepWx(Xg<5yF4&N zzs?N|HxKM=$B4LWs{c5jQ!sixF?H>kx-uuMWjMn5Nvvg;#yiVg0 zRWKMPJ(>MFY#$dvV`Rxg)hIf}Qk2Aa;iw2lS>N(O=(%T6AS31XEFk3%gD&}-LBF?- zEQ0tc0$|Xa5`Q!3xFe?sSs`n(ZNayvBxsDIG`|@13M-Z>wMuAg=9E6+9zRvtcZadt zGLV=HC&_q1w?v8bt(mr7e(EvFOk*iFpZI*jOT5;C-wZkdfI+XAsJU>jskifuaSG&R zu*O;P!9`)Ko3u#FK@yq!z}(`I4a7a$vb@*_V9-^|q4Q%V(8>%#C=2IH&k-J~FfllE z31Cc!cDP>8fHqbr-auq8Qr4(tYurwlByx-_rp8x0wtl3Fh$w!Df#qlbyKj7!=^C5*dSam^~}(p8)w8_*GXBjKr1N!vS#kVlES6vI%>h4ds3Y6P^qe zluN@rS@i^{hs`W~!0P0(+c)Er1_&A=hZgwc?3TY+p?nG{6`0Dn(iCc|l1@jg+9Vy0 z?N=Q5y`bG>P5r){Yep%*$SNa3NI|3fM`gZ{!>>JDpl?4GciH9RdKF&Vzrti96?ND~ zeu&=lF~4Vk3i>8f=@qBnJFmIS=`s#V5XW`9as@eqFyv2XCTemZ{Yycw8HXGkn+7Rd0FwLI8;;UWoYl=Tt_mOkLH%EDrX*h@;IVXe*EPYNn7=!!lEIi z-s`;>p}3sfP`CE0+wJ)1ddv~VUkExk3v;PKgoksv{B!6yQp*m}Rd(SEt6fkO?$VL} z4q_wB|1SPNHT^37@iR6?Zq2eNbf}C5PD}(V_rSB~^(58)6#oPPV}RnH&?5#={14=- z4)5%0)c!91{aN$}RU~o23Ov(@+)!s<8wE%O>ET_pAQgH1XnrH;Up;&?dRe&&ej(@@ z<=D*-5wg8IpfDM-0@S|Nuf4Q4IxCFlKD@W0acEBLo^`oF=yYwYjfzmRP4B4%{iLz*}zXY6%`YQN8TG+l-G zyM8XW;53$+dF*797e*VQ_&bymsvvsyxQu;&_;&tI;`^M8J$cTZBieU%N>Dl8pYf%1 z(~^r+l2H3&nm=-XTvNTEr+w-gE?$@+G?FH-QBo;!^5m)-(wB}anm%<#qUID{jFXI@VJmKZ;o6G~cpBb4)n61H!yP4x|I$9C~NxOESl2_Y`J4 zE;Y4yuTmKC-+KQ>c47^`8(y!*KJmme;VzVpk8P|OTUp&fYy}Mxm(pQm$`qQ_rMM@6 z;2#S;AplUI?16=mi5?8MT^edj!IEFY<*{j-J; zj%;UXoJx-DL2a*4=V95AfX?fY>(e>ag$A5d+-T|;yxy{X3&4DaL~}4Yk|zY zw3S6{@X-1aE9~^z@N#)97hzj^T)wLP#j(I4-!2@jNiO<1;H~5JkN{tTS6+1stFH(^ zpsShwBG66j=>zvOCuXreA4T=^whT9cP({iplFv$VnNUqH2NzY!BkNMEz&PD6A3+Vz zj`|zX>eLZ9;dq>#AM+P5d~gOVY-Ai+7ceWU1=|_2Ehij zhCOs;F=g`(3yQe>sdn;aq*jbW!A$EQRSe(1H)yTLk%#RiRn=Di8)Se{FmU-J5L7%? zxHwIMO=QRckWCU!aJwSQ*QuG%Ga#ELC&9QfeXxdTFQ3VxoT6qox?4U0VP zxTu=aK@*dd4Z~g1>qPUa_U2s2ZfIYdwj6Gfy&A2>poK6EQ`zNk`8(4f02ok0N*=xVurP@F`)!`J(P z=Hlp01t8F6<%&6bo<>`GDy6l*j#@7K3>0szZX0Rx zOhiujBAam=){_&OBahyoK{c%~00mgocIyl>J3#8jT<+=E#J=iq%8&5pEBmq`|f4%$5T-Mfgi-JJIhsyVn*q)!}?1VzT(@*FjNbzyPJc^dZ8JI&pq=18`0+uMXA$Gdpr0)h~1xc+(*6 zyBaQqBM_*5@SNf{4rnCqc%HJlxlmN7-g~lE{8UK}L2?d<@Kium1hDt`y(3(PwxvkH#VDcl8l(y;qM5c~Tiz-chK(26pnWHQw zC(1I?h&*)!05D&SRiK(4XbLb-sl9JJ~(e#`pCR$T)WzGS`uZ9 z>6nLDZt>-0p6%Dc1h=wK^_jp(d}?^?S*r|({Hu_<$=)0EKl*}40@qwLG;9zo#p2d6 zp4i1M6lYe#!4UHB&_g9Dky(I{*1zcm&6FnFy-%~RimW)_PG%{o_f9HmS>k8FReE_A zay-DY1=h7-O~+ZP`Ha1kM9fKgCk&f$9w+8rD6d>dm5}rlA~B(}M)Y zzOL(KIUuTfFThoHx$h6*!XZU^u)}c*{Q|oI*v_fDmp5Ay^40U;0 zS!so8X!PD2ca_WleJ!w_33fw>11a=0`k^WI zwjCr7$qrrsnA>!Ssp<&CDr_Ak!Q68XO*8@W9Oh99vp;33{O-LhDDgJ8hi1uU7+ozB99dh;Y*A^|QJ z^#wWcINH9}()zj|%h>!Zmc5+sayDG|P8qG+?I6P^7SlPX!JXC;fj6B3LeIkg70U~1 z*s3D@V!41CDdo4qDo8Xy6rNYz}RA%f|7b+=5kGw^M zV7{hYSw2=|?1DIn8ZrFjO$i(~s#hY*N*yX`Fcd0wLwG(+ybboRIUyQOWr2Kih!%o| z8}xCIg?qaxi(r>+ke^+@=NdqIFw7^zs@b7)t=~ywvVu9^bXXD6mO&b z$6bjB#?1ViB9=5!!3r58wx`Y9ZZ;WM9>)pg;hd1PQ>yOfY8E4@)6~$w84!idIE?$i zo)55pUy;ZJwSA|-z|TEj{vk*u)V$PfwnVTwmpxxF(Uo_GXg?G~6FBMjTu_^%zkpIy zGxs*nH9&%>47D`uufZGrX;ul3+|*4H99hU8 z_fZ2JOiX)Tw6Y!sPNF~}T||%x=u-a>Qsa8SpHir@ha^1Yhj;a|iVZp9WRO#nUC{A{ z7MvpNNZOK#DQWp4i|U9HD5QZ>3EvLyfO>A7;SX~0Q?jT{%NtE0|rqO@sTX;S;E7%M<-Ue5ylFr!szbs?c$=B1IQ)is}-=6VjYcZQM3e|FAvbv{WWKR zER}tMkq}l7vY2lG@k%An;zvVO*Md&09@PsUsYmzzh9V^wEVLY1Q}C!?3i{-d5XdI5 zLSi4qkGaGq8Rflv6c5L3DjV2HTvzV&#va_{VqG{ByXa*DO^$;kXcQ>$V-|cgE#20_H zLCvFQj%jYTTTBLqqSP+e^R&12?1EFV9}lhT5HR5OHaN+?>kpK}Iko!3{yRS`3`Z2! zcViDMJ^yi=LF)kg>-H8~{K2e=1H31M>P(t7;|{naceuv_;`w1v=YIZIu9W zqEgD+;kcvL1!^tmyJ!~<9kkuWius}8h5LRdQs8RRkV;$KRJ!x?n)lV&{pVe03dOkU zYypXUe8PD!ER)5!cyy7>@@8+I&myde8&}TE*J8$F+MnMkRv0$SRHeZo;}N+@A#x3I z*{_gb;%l|)_f*lHM`c%Orwxep@vvQoE_qk{Em4M@hk_<-#Lt7xzv0l|WoqXT&vGo@ zcc~@F$WT(5s|*JF^A3rEd(&8<*@+u&S>WYM%6(ccabp{g;*G@ld_lJGakk{ob z7QYF-68Lstqj#0pqW@i5lm}g61OF4fec0qU)FfGDFq;*={eD8I!)J15iE_$O;Lfuf zy1@IwiOozx?wXSwaJWHyY&kxL8*ibJD%83h(l8?2E5AU5kL}H865`oF0^hb;Y0Nq4 z;JAfoLB=`oL__Owc`A9BZKxeC_w-B!Ax|odM2hup&(b#{uABYdD~w^b4G}vWx((bx z4mcB_8ioQXyUV8}g&s<{I4P7zHAxo$20BL|#@5GZ{8;8WB{QqvU~r^iA;FPtseGS)=xn>P3>m&WV) zvl_9SXhHDyhTK>kQW~QXAJ@CPuIke&jvkz&N^9(5hi!I5-ZrI;mhbMvEF>X%7j(Ey zpn>CCo7wY7)QfxH)>$S~Y<&`}JdZYTCcm)bZ;Z5Ip}EJ|_4j*XTmvqoyM{7%q`{am z_tTs%As38~R}f$E?;4L5aQ;N+DHk=2A|jT-zyi}AEsP39TH)yXZJGgmhOY$`vfQoMRE%*wLCV{M`pr!)Gp=N# z9beYCM-p+3pPIIBSTD&&pH+R}d*NYogC6AMclzro(AuiunBGf!boi3Ba**cxHU3Vc zt2bVbfj9)jg-f&LL_W{Yr8-LQXWk-2>DoLytX`8QH_0D}N$E?d38ikJ!vu#KiKI6i z$VAMm!FPn!(ep5Kr%a?1-q~N?4)BbQ2{<5i?^PRvkynC}nu9%$nS@?E*CruG&$rjR z#56L}(ShRA&>E8%3Wm?NV5br&E=&;8Z(MCSOO}kPSj44#JomV5SGVjI$?+sLnp(2n zi*<0M+jvl)nDNh=Uyc0c+>5)?J`sj0io6E6rdTS#OL)6c2$tx=u=CeNXU>k42)$=~ zGcfgnk@Hh*gv#IBgf%3ivON0WNX5rAE3sakLKY=A8>!v$Z31+@q0#uBRMeYy4MNh= zk&uAJr7+(*J*4!ayqg{g|9$z8c<+;f(rC(SK9v@2#D8Mt{H7rIr zMrHILXsWe=)Nggfp`m2U1R%Kqjz}soR2cC#FyUWVXO=r-h8im<*vTl`M!0J`>(OoN z(vndet4{8uQ}8EO^~oR5?m{flhzg+Ai{V>byMcTGj7h(13?HF%Z-~?rV0Y!!X(F`K2{qGj_8Z zooHSY^xRuC_v5E3=VmNYcuMoQ@thc}TEWcWkwO`1VM}ZTCc=t=;sKcDs)64C@$d>{X^=r$CUg&+%eKD* zjscCbmP$rwn|kv%^RHkS`$ih;97x9DBU(i!k%#LnRwVopioW5-quu6MikJbG- zU+w`51>2AiK3<%+M}lsy7juAvvtG~*aB$wQ+6xN$`w6AIX?9 z)nh5S*l5f)?XvUcGrE(GQV4nb+KBvxNQt>~MX;bY#7Ps&Es?*0Fbp>;_O;BLUSu0Hi z)E#jhMAyoDEr>35z)Scp@0qvGrP4mDe8gcE8@DZ`C%N}!@cb@uOgK72n}<4|gxbpE z`J=EA1*_#`VK@M4bL2y0+WkxxxCt37#Rkn^M#loMJ_SH7 z?83=6>yF}g?#x&^yz!%^j&&o{Bt>Dyf!9GzwB!$Xk8cZ_!|stNN7XRj=*JXOC)(p ztWJq&S(2|PTEEN@9W5|&-f)%2Q!$$G>KN?~Un6lKIijjrYBlr{Y@EJ=DH1r>Or<$1 z_E(3dhn~}v?;olT!oc>7I})&`j0tpqFqDT3r&vxpcL|Mh)GhyJ*W2(mgx|QCX$1`( zl7X?agKY$5()vNwTOEn&`Y`3Y^*9ta=qEddQh9L5U z$M!pgpAC1S@lx1Y%W8yKji``aMeLEZd@%c;*QFAYo3874z`M$Z*g~~B*MVmD?)8B_ zWKdtuon;<1Z#6_Jen z)HI_+^-yJJLaQT!woE^Oq!&#RD4gql@pv*+^3Gurw56gaEJT&oDdoy@@~V}F)=8;} zz6D0#Z%x?o{NAp_F35_uc-FsC^xcBH*ik?#`%#9YR|n`*2|VzrZpH9$RpUoX!!Xu0 zV*1bPoe0w1&NpkLy=Od=(hLv;9`|AMfPXWVh{cL7mZG{kWBXxrhG9%P#B!Nj54_+L)TM5SdrC^&1Zcpdq>7t}E^2es zpEbiv`?Df4Yf8Cb-)4G|&GVMgoEd@Cb{UnQGY9UPR#s8RzmCmzH5rL2c`URFs$F8u zQ<<6;YJwf0BHKk2(>8;eRZyOgP-uqsJF#n&FDQ@tD}$j;2#`U10kt`-|M5^62E+Eq|q`S4(2$*9D&vsNO5v4LbO8XGisY z+^$OTOV$9a3-rSi_94!=pH==q&alS^q)KGp$Hs$-_7=zTI$1VD%g|{hqGX@XZv@=@ z4Wn47M>xkZnqgdH{7)oy#CVh&2bKDJ&`Q79J-Y=;_a?JO27vKZrO zk))X=sFkBG>xdc*yMXrTGRP461~l?g-a^Tl6}(nWy`w7EqwR*3x=V&b&?MNcjYC4g zk8LEG)>P#X4Q#gdvvA3|Y?Ibmk8QMdMy;6bK94Rqh-EHVe2`i4RAl|h83_v|23up^ z-D${77CC5P!-CziA}qslHO0rZaS7;|EX!`E9L#50Qxk6*leDwhfL)L5q8Myw`;EYY z@iNm%6FDKwUWT;~c`R>OD0$j;6~@AJ-qCmBJ|+??q%5gw&6Xgrn&kf|N9l!xJRxe@ ziDOv+YOwMK(lekAM(UApKFG-8jufAFAv0P)`Dfe)^!2_j&fCiJqV`4LGiw_9%5K-~ z1*q7yfZ{wmm;s67`>0B#SSv-jGo1uXk+><|bfGZaTXb3y;{pnK->4VRB|ES!?Fk-c+f_)&zKq=QDtcLMH%V7V2=vLP`O6RFUU-SPp8g@D5Pp1m!3 zYF$nBw#Cy)$Tn@48Ke6LSs$Kh^d5DcjR002C6)kn!NI6min!bsI8@)(V^(1G1%?2y zD&)>iHRBaBGHTr8>oW}q;Mif>orYgTL@l0U*hk($DbY9Qr{TKW!CqahU*K*3e1W5B zW~MwRV~6a?3^^3+4zciE04=09-gjC zFdgUB#yV$D0Wzj`>hOAp3kNg;>G0g0eX!kyBy2Ka8GsbAYQ{>YXwhAe>tFc7nr6yg zBUBDcTCESKYnKbgR?Z_DN1*c2D)ioeE8aNLk5+g@{de)0`#ZY2 z@&1oc`M>SUXSuNzC?Q(H2opxlE6IgfZo%Z*sIE`p?=;gPy5Kdm_>Syv=scuCxZ2SL z9|OjB+;`AyaM1}7gUx&iZRFdJ51MkNZuJVjll*eP6O<7^rYd|L**hJR^qymK$1chFtDN@J&EDv_p)dl`kTdhw2v+MT&bz zE1kXeSTO~)U-`eq^^cPgF)bzn;><2&#CKbi5p8F!y<1%Zqo123a zdxO?DzwWtdJ#NtYu9=0K_9@(;q=*N*Wks^%`ZdJtxDLk&gLr^X8|Ttq@a82p@lABz zE7>E|^G+5HIocD!4)@8?pjQCn+C^L%8bFNVQ=>s0p)xJe!0KCF8i2;~Y0)4$6wt-I z+=V=KGd=~UA60O=1v5n>h(0*)CjFmWxMj{%&>JQ9Xv zMT7K8@sg@J`R4r8H4ShPtHXBI^${iuW8}VMn0mZP>5h!%RsCjYj(?ogQS|nNLB^nA}i|L zFNxn`G3<_HoY?~`x;WUuZOK4zGp{P6e3&DcnR`Z$> zxeP#;wFnU3YtQV*J-n|+>yhg&=A#=0twlEb)Q@c!WddjrvLh(Dv4^H06;-rkX6+M7 zLRyk$X3O{zq94M+MZhC)(?h4qm}Qf6$OdpV_E`M);HrF>)yMafjO+_JjKC)*XMFdQBC-7X7YQ|PiClVl*JBZZIy-;QyI{#r z6y4gT8!Ksu9@(uE$hjn~rL(L1@b_j)l3T5+gp`Jq)P#bvNah0Zl2Ge4SOt31+yUzO|`ogFU*^&yv5lD{9ZsM$-k<95Gz|b!2<) z^TuH@uoQ0(3f=o_czFR|Tp;2t(xn}mHWGdre>h|EZ%8`_r`N5GJfDz{Yo=~_#!j+K)?#Y~!l%p_p+Y978NwBQtb;C6qwe#3!gDu~`Lyr8>7+Ax}L9x7vLs_hkAFTd1s-?ar=yO`=C zP|gNHj||l}O%q`Tu;hUewLW)*8d6-@@#Z(eSb1S-aiU-Sztf8?V#0V4bW3I{uhel0q%3jsL-u$Aq=MXZs@RP zw2s{AalWQQAK2>tLK{_QhSWye&(~j|7hY>DQL!o4M!6;~cG6~{&d(Tra>M52@86#N z=YPL``|{-Vf4@0-`SKDvo}Be^b(s5x(+N?%>49|yB+$cpRTitS3mu9 z>Ah+o^(=wbMvg%M`;dqYdK7LjyxWZGrYa{IoD5Q|*JoDi>NG1m*lvws%^BMLtoj80eS*ukrF@ni=^e#_Y%cI@I)K?}b!<{Io^2)=oK zt@+#VrI>wu17^L3V!%kxw6e7zU{JNCGS`L0%NZ}5Cr1q!vTM5v8z z9?W{2%aU@jJ0!13T@-WjOHB*Z`7UL?%*prv;y?Q9=r3WBe;xhB z*$#0(+TRHLSKuwwjf<$TV8d-(n?XYuQeM7MG-H=caZs71$hQUq=Fb_)T?-wJTO%|LIy&rY%?uV7Qm8*%|ctZqi} zgw1|JR*N>WBD^eF&Z%L=oZND{cE`mVfEYuDbSNZ|5Im~|ckzT-ZAdQf#L;N|M*G~k z3Bc^<#h`-+2;?Ib>~I$XI6_xOOSLnUQ%YBDCPLpjq!7n)efP`;P!yxxY|YNiw0&qj z0X_4@#Ca4A?Mdwn6R9#jF6LxLi_puHw)bJQre1E^q%NeGwzWI#%L`zWjEcI#HCbh5 zF6&53y=|d?`OK3wvV+=Mk@2{gxRC|J-HvAxDG_%hsA+4YYYW& zM$4Y?8vwhS6D#9g`wE9Xx~}15kRq#AwtpPu4*S6eh?<^e;4y6# zv0q3BUC5v*=Y*-|6W~A>^6Wj!YQwhL)8dBBcd-}Wve4rciE7QSP*B_4)>gv%hd1Sh z&7*eY+?%Md4hPT~j=dMzXYaW-`v2fH&15kG6`w+)$htIRcY4AoM@qwUcRwbv2-0uEG%qu6Ji3dK}?p$rU4IHLIDwZF$VWNX2fMB8Ry|gy37AnWGW;|63a%E)Ee)3deu~(o@ru z`x!Ze3EJkwk&k9$Z`aWyOpA<6rb<7w-+QyB*&tNE7fxrue3uELCI}a<9WUxci$ZYN z%c5|0{|UiLqSzF82l9X|a*oH`KGDcZ7IHejsuZL7ODVKbz+$)73;ezbTb;XR@{UlK z(=8|1o?X_{8Dek4gM?;ELi;xyZavciJT!Xbak#yIFTi=jOyJqPqjSe{=$PkBx9Z;f zg4b+_YlYUm?`*~L$;Ih<;n`Fp>OPVO1$tex$L>qB1Hrffs?kz9qi4!*nOIw-;?lNd z3_(@s6)RY_BgO7@dqNL~6?)irNEXBLAaT1fR9#Jgor`EcnLSGoyu%4Y-V6pI>vGJL zzfI8%ak*OPq~tfw-KlN2$b+{&dv6sV9g`EfVmlXy!hpBsoUxtNCW|}Z5`LlK1~?)k zM{GYI#~PBD#Ab3~2v$nnO9`ZJ_@<5R;GA-LfVK}tWuV7|lkE1#(Tf55$!Vb09JPbu zJh6bZX=gRT?!RXzZW^N=>3hTG31gDR5zsJ;#to1#Vq!9Xs-3;LgW8^d9ow4{*W4=Y z0NrnkpNj#xkjDPiGRsdT(-+dfCp+I4e8q>_6=!U@ZqQcwbvX@I+BoX3()`Z_k;;)W z@ouojZD^-$hnHOEf_p6vJ9m52HoOEkJ;0yhH_+p^Dxl6QuYow!Qi&QiU9-AkNwzXI zWdu4HrJT7WfwO_*no^sxLBnaKxbcc~x@tMKhw z7IoYL7tUfVa$)NB-2jdhm=#06*0*CKD3LO)ByjOc&h&}7+V zbkZWLt=8|_GsARtzrFQcNO@CN{@g$wS=@Q#B9o=F-0_{j+vpDa&?Oh(Z4CzvlNLHY zh`93L7P*2qj9EP+xLq0oevm8?)A~ft_8Yr?1+)wSzKK+0p65&eO0Hc}r~+6x5cbY? zydtCY!?mJHaM9r+4h)F`wuacLbFSplJ|13Ykqmx=BU_h`nGcXyRxRqH2;E4rd>^A4 zz`k7gb7~oy=^mZ9F5A~G*^-hmGt_Zo>{bpu5zWdjeb2?E%)8z~GGWxzieWc8tXOA) zjtiEPL;oL5*UN}nqiDUcM|bQv)ny}UOG)2f-LSjeaA26K~YJvcJ1Ht==6)9?fv^sXll5gaC;K|f2Z<78t+{HdEjDrsD`}fWnDH6p-Ijs z6Q-ijbxFuc?z%L)o@jS*4OLSpM01WxuRBZ&Ii>|Exv&cwMO~@Ir^DO1e|}&|pg8d< z9~aE|Ok;wv$|W;S7T$beNVxF@(;5@p-f(g1LLL#5y|T>dJuRz(A$$?}a`-PP7;y=- zgK*$nF1L~7IqGIrz!&k^))Dh|m|Y0-X!6DJ7stg91)J zCp=0CIyVOzg5v1NaK-nbwjd-bKZlF{Y@t*+Dcj-8FSeTPPzLU|6CoUC>)>`SONK?3 z9ev6^A_0K?2JsWb-;FcQ8tKr`XAl>O3;|{0bVSIE(PY2NX7?deCK&AwU(J~$u3417 zm3vlC3A-zZSp-n5#yi;Fh`Cn|iYxjzHCv{yw3e?Bnbpt!x zYJCpoP{@ubCALBlUb%H)Y3U5%gads(Sy2Mf zMRyOtv*>HtyoWUSEMhE;vfiUNtv0MHCLf?p(!LYm*j8-*Sz3ZDtTJdpJgI9TVV@(LOOVYkAuJ(~%jU*p;cP^F2o0Ldcw* zOeS1#Gmq=h*hj~>Semt^Ys};wxpSqFaP}N}O?#=w_8$qZNRT{1bUWoa2vT?J?THz= za>3{x#zXRVDWrOV_KRJnZbbIIuizMX8!NS=V(2(y;T*hlFFrP3@Z~}MXCCCphnBGy zo8P*!I50HhT#C!sZ-IiOf`c(ib`=h>w}|)q`Fg~bug}h9kK(y~W6h<&v-lzJ;iRC` zt>)(2eYl34%H3Ya_M9KQjEI_#S)Ys7DPqp;T|7L=R>a8KxRnkFEhGdKtl+U9vE2P| zB7NLp(MujN`3yk2nuPE{=O(3JUQg&XuIp~DCNA#Z^ltj|`t5E?;jWwMynptFfo=jv z17kQNppx^LxB`9*RXQb$>&Vm$t4edg=gVl(HZZI?!*ixkO&YTf7)4wHv@M&h(MN94*8IXS>3;Bs4) zTwG{lSBNEEDdagRv>aIO>!(`syyK+qzcFLMX&j6hhho!89FUWk>Y-&F4dMB^vLfb% z*k}qVXbT5>zYF)|kudfLxI6ZIJ1{SNQQtg2iKZe4Fu=tngt5A7v8umc2Na@Ly5_hxWXf-?nzQ7xU*(9$pva6B z6;Uj&GZvi#rK8MWLQdMgGpMi*qG!Kzp7vcwqg2I>Pk^g|vBoEa-7+;NmDC!zEXY|z zOM*x3!eVqWm>5Ka8@s1?`z^7xD6=ZBW2UmRKLw&IXqwBnHANw;>UuR}?v(w_yjztdL@g5y8+QXM@PAnG_kTj6T*zDmrDyZfRRA^!*-Y=+-qM&_2$+ zZhssH?dS_mfl<>8z`1~moi<$S4;n?}_}V*qr_Tzi4bQ$VWOj39q}qwHzG~ji9td*s z!xcH@`i3Z`Wvw#T|6&20ibhP@^v8r=h$YQtXzRLIJ9}SA-L$HU>do5sg#U)#X@(RT zTZ-7P*_I20C;B?FUuNI>44lz>m?pen2>gM~G+iVNDT2E_mo>Sg=o18%6kBa|&8rvW zOz2v%rlNCkVylAr&R*Uj2uB2~DJ;K>1t`HkXQ(yn7i6EkH^1K>kp1@)ZT}KxqW4GS zysQeIabryaF=484c;N%R0O=q0Ogj3%J$?HE?C)HXJLrykYt0*`lvE+_w6!5nXOPLV zQnKVNP&l}&yXc+;elZSQhzsEABfH0it`DPm{QyY(BwJ{Y43rXQ>=|zzv|>$ z>(LE#oU_|wozv$7cm+Jx^M&`Nn(RN{kDc#|m%N~=m=D_2YDTr@w4WZlaL@M1AtF|S z%2P1kpd_?BgJOfoMj&a?^wfwtnh7+2D~kCpPphBP0~D#+h3zI1vtet#}pw{B)PwQYWIc2eo3_h|bUqh8)`Oj_<5c zJsN>Lh95$2*~ZX`#YCC0W~hyrMTy-X6Es~fu_GV(?%ny;bz{r^`{>5@`JTEl4B;Aa zeLy{q0q^mx?slXeKj{6-|Gn;?Wwn`Nrl%6!4B}Ns-!(Cs@!NqGKqlb|kSiy@T<^um zfnja-@P8YL*Oe$lKwkBwsvpA>6?g=GobdXO({IrnotTF_Wwy!DGgi$eskO)U;a6AP zQ0_}s&B&{(XwO8Oe`AHXeSM8V-UCevK4FHJ+YZr{Qg9=c-X&l5bJ`p5&Yv#wru8W$ znJfyH`HEy9vVW|Cw$s;4XBI!DBoe$M4QgPT!o3%KSGoc{en2SZg-qX8VZ0 z$)I)*js;jzGwWl!+2`%XH~ka8(@>_FAcB2niIUPRcaELZQ7}>9O|z%ZD8>fuIM(s! zZ?|+dbNi{Qj2yWP%0M_k9Drmgly&lYDK+WS? zGd05DKcRh#R}SF~-?7Q=ckLaUtlBj9F|=6=>F`$Ltj!EdqOkuXs^=?r5wVUxiET^A zg%{BpJ#HLO=>^%}Pk6R3Hg_wc;Ws!5ocy}eG76DV_$@2uLGQ=h=)6XtL7Ls%QI$iV zxQZH%o;sNSyBOyk>Go-?nQE2 zik;7L0@+r?l^6Yr=2GKt?Ahsv3YwQu@QI(8fKPFQL|d#W4h=4Hwv#SOI8)dA;XZTO za3OD+`cw@-@AG-l-L&YQsn3h&q@3$tiXpCNSmn(@`8UgP{&a%Vk1lh0^GE7aHT?6> z+ScFXzNVV@4{0Yhvb~ak$l`h`ff`!}}j9yE2|vvNd7az!#ukLSWE_Mewh^;k3TGbtu~`i54iVQK&T zf^FtMjsl#4NHm~QnaS+>PMyhWXw&Y`DkXaU54vZ zD+S3MrYzV^t+p%47MLJ1Gajxibk}(H?AbGfdH>U&{zRlAl;kYqw#~Gjf@%O)vex579bKwp+ z(bu?Bt7IsK0QsN`d5abSQVfq*50 zN|aEc?yBb*i>;@58F;pbbFP&9Cmu=w^J|G?0LHVY#lzw?*<+Ej`p(N%eREx)L+3s~ zvun`-8XR+N7X+aEZk_SnnitqUgLl96 zyBoG-kl@B}Tcw$)-IhWDx_vLEwQDd^Qgy@fAYVr0(h|S}&__FK3Tn+cbhgqtypl89 zVMzz0(E+kOsfadIIj&?s-*x-)H?-2&6PJrAY)d4xhTC2HHjb%NNApj(f4HNAyCXaA zEnP;dS)1~3;N0Dug|&1ogD#DNr8WJ2a24w@DO&jFd;*MPf$=+b)>e$YoU*%&3EKVe?6Hh3CCSemHLPe_<15CWjPUPWrreiIO+Te8k25iev zSiJA894|N*hi*w>(1cJNrjFZ#`R}$hx~1a3OZk(c?_csL10`mdA6?eF%GR zn6hW)<<&XK6~ARllf$o}uQ)alIoftnFV4DCPd&`&bxhF`VGR|0`w&Z8-40%i;(c^r z9)JXy%UWTMV`#>oNu{iL0?VM9C^qHV0I<7nH-)g%qt6;4C1jj^0B~e4$tbOqyydyK zN!tRPYf@3&!cwJL%Zx)Dra1|bv!Zhl?A)9grb;eY2feVJ87B#?s$#yAtraq7m-V>d zdUo{?*+Z-5$1=^O+LHUSh@$hAgyvvAS|!HX(_9Mhl~JwzTE{R3fVv0oD2wx_JE?b=i1DQoK~YwIa%Yb%bSO=WF8XkxZ^)1&OA`4I5AFw>{T zc8x(jO;dV5Qs%uwOxqJ<6d%_nR(#Mr=O|t;lLb)n@!UjqUi0E$F*5D6oT1zOtR-1p zoFqu-mTr_}T8)C$0|pO%c%Vrxv$|x$G)Jr{3&CL2X#3YV30N%75=dBAF7Jeuz$cgI ziH?WX2yMrK|2U@C*yTB)W9Sv@nycNL(HDImKhNC1RRL%ttUQ^U`tgG4y-) zd2h)>0zbzy@<8NHP3A!ZDQs1822z4EX0tAtMt^yz%(v7u)&hxKefNKn_Nu1FQtWNfMb0sm)~g z6=5Qixn1uyyt~o{%#yT~PFCa!myQleBev^Y;JpuaT~*=xoxR$W8IdTGoXG)!0@s1f zkvnt=c6NmSUXy~C96A)_z^j=~G+7RDpix%U12^cXWTjN|K^WM6*_p}x;s{KLtX7H% zQ_Ne&!~@t8fm9bs5$RPtsYx&sJ;o%hKJlUdr5=RLg5+WCXiVIaTdMTILzxdbzvWu0 zRN_!Ee>+Kic-T{Nbw}wzgoT516+(aZ4$In9wdu3VB{iNQ_`cME5e$+C?pUDD_Y=pd zs4+~57v#SVfBN08!=t|)9{%`j_~(E8?(nA({Ks#P{&w`M|Hto+jt&oh{PxW^*OzDi z;77myDC+VC|MlzPkL>IpYYuXB^tb;=TyV#d;ld218sgT!fbOMvE?pNnpnIKHNbs|9J&kvrpW2KXc*qG0kq!l@m59KE~JSjlRF{ zl8{SAMTkQ~s=LhDfeydLh4cslW7eK4KsduzE-l&Hu$-Tbm>@ ztteip?4wE!A1VhakjGb97zs{2*LH3~3YoQPSvqD2T!u5x)zT8s?3J)I zd!Es8!O&d@r!?^%*eOc-o|kn=YHi;_itdQbOWfgA$6Hu(0S|TDs0l?{SAoV2GzsR; zI**>NOG|3ECTEt*2_$F-n^Y5k!HDYKx03A$UUc~m@V;4V3u@si$36wV@QGLt8?zZw zv>acPwi7ic6u@=#9Os;0D25~BIibFADsUN>oVXWv#Bm0vDrNJ`^|0YhnqYBT9;s+vQq^&Z1>+-Mc?i5pNChz-yvi85P|WTqG!0U+BwEl)&!hpDHLYkC z-Bs8qn%&s(Ao~j5B4)|ikpp6AAG0oGl$j}6PiKH$guluPsu8v-CcSaxOwPHfNj?{} zGQInyd;O3F>>Z_Bz|*+?qLkW#a3^$6M$S( zLkACSKk=c)Rv9MntH_rT`Rdm>ioY|f$s!dLLOF-nEfcwH@~z_%aCO@wi`=EcIpK>! zifOwcUEoc7QE?M02p2iO<#|mD)B$2C@$%{%SH!0?GrVIE(nRg9VcGsY_)?iI*Pt#K zV&q<290>yBmM(X64&6dsnPn%(+--%MY$8=uS4-8Y9E_vQ32?uR3b4K)ux*blFtugE z#Ib=YoW5oN)U`CVS0l=vPqVIXn`3{?%BrAdrwP|Tv;y$0j6us@smO=4u=nut`Dph;3%nFab)Nh;5KeJTxRs2F#HH zB@ZDihEUc6Vx$B%9w~i*w+O=Ca}Av?aEoBisY4O)%CKF7Jw~DDN+n}6)PP9871I1R z+%{hs23oHq^j7km)Ed+$L23bU_~=wPcNoTVQgUtR4I7aws~)535|mtHmELh7vm2I^ zS{Pm=7|vmhK)jaf4B(}8X4SMxv7uMn@mJB#K$L2MZp|JH!rhut^v_i}OysIzlQ_jv z5xu3Dgnzq#z>(1-aseuJF^{I4)o9Ua=@Lu?%b38XhKU9ZW3N~7d{g&m)j}ajHlt$70zxe*X%5Hn+hAVDH!AVlOefY1 zj%-}y5EeOnp0u2#;;){uvi_0$4M+4_r;8eT)gwP< zGpDmzg;P*m5_U-bcYuD3Td9+}d%x}24bEf@zEgzuIrPrdkvoRI<4*VIM;loJ*hH&6 za*5-gyXrP?@mmX8L8RK_+%@PWKxF4SU1%v__k&=5PihjI_x=aRgkX2U$e|irn)*Ci zh-EmFd*v!pSEi#*g*c?3o)!A~yFajkt; z@(S3|+?fw%##KJ7s4{bO4i7r(44`f4IhOs?hi|yZH*{=(v_2msI()MjySVqHJS4UH zW#f0Kb79obaIi~n-3}qI6ifqWdPbY2^^WoNvdhs5u%Q$B{kWM zX`&_c1J#BW1+ z546kVvfl$9R<}9$h+Mf8=Y`3aQMGesC@*v$mg$A{^*t)Xj)n1)!!ga_7{E9l(lyvX z1GP%G+Le&a4>p^5aXumMSSD|o!UKBtzM?{NDPB=t*yHJsX%qbpf-;bKlP5N;xXUZn>|QxHYuQ$*__+d}Nwtb+9#%f4~I zv175mZoR3;&tzHEhP7C+V}E^=h)535=|FQ_QbDI|7#1{aO4g5i>JUBRcO)RqJ+Xr) zcJS%3gLm%qE;0nCiG7G6^mmLnjm)ipYa&Z-4D&To;erncHysc-$HX8~iM37aeO2&` zn^rrke9*^OH#4U0xJL6#5MEZ;upgMw&;eKYSX+393~CPudk>LRT;>zU+~fd=5tj<% z*ts}oN_{_MRq(g0?BLmr~V zVS8MVPV*Gl!mzD9Ms1sOSeCH?1CO{0jFXGgK1{P$#{Oo72O%d5G;h-h_a=M;oI2E6 zgdiZfVe^42+amV7Qvc&V;|6lOOJ!}TdGv@0X_xjSh zmq%(d8@83L0?q$5l7eVe|b#uV#0oBU1Ly z#eUPQs3Qb|kpWqH`|#cVvKhAtW9*^5A)7BCabdTY1;u#&Lk5Z$*U|xnav{m9)^D0@ z3kRGkS-&UVb7E=*hkc92J zZK)hM(^8d^{WooT>^lc>YT-x7cvMVR5-W9962a-XGpZqLdg8K+s#;YNuw1EFx<)-} z*c}joM@2y(qj1yg{S2MQP8RUsF@>Rp1uf+2S4v!+F9ks-LjdE&g&`c(0cM@H5;?4C zY}$FyMs`;Xh*=0%o!Iiuov&In*{xn`txos{WbCo5g*%EKQ+pf4vTyH!$iiaWv2H;l z@QI~?0}Sg|J>N>1nJ}er8^-h1Jb~nr;hw?V1Kg?AWOJ{SDr&F}hLTH$w@n*r7?fuy zHYr-Y*BL2g&L=KI{;HKFGe8772N~CHl9srregyA@l0IyB*$~7ROO6>W=J~HqAY9Gj zH=Q@Q5o!7+u_x?i#V0f#^$6pg#v)CX>qhmV?}35K33IXyJBywO$OE+I57^0n0Q9e88NDGoX*eM;Un2=5%p~_vS{gAlD)lTJNRN&XP*dQy zvGbk1ACZ0b-u!-lK=$8HwEat%iQXTP^D-pTaM9Axn0vtLf-PM(8aVsy>Dw1%Chtft z$sL0XXKS!P?WgvJPm2lw#E{9dQnKWsQqY~fU37LTYSH6>9Tc^&r={uT{^}($R83i| zyT=YB>T=9fT!X~)mfNXGfQr%lttjTZyqA8?F0D^nIb#!AXhsh050CE@H|%Ic-ub7X zOdTwUiHz6Ru?WWvrI|rsSmAWqHb2KN(afuvt*i0^JVevLXi<}mX^|2Tf%4;^|AsCF>^;jI3};o;Q!cix zxT0&h$Ng^FqmMLbUv9Nk}?)8&)iQoBn$&-oSdKd(kj}h-i)J$k@_-&`{8em0It%I8h z1h!*ix&!DK+ZPG~e|$oOTzG>v5JX6D?EEBhs*s{mVgpbr0A&t`8~{uf{x@c+*!OKY z*5Hj}Y3b;*qqZ<<5G?LWzaabj572GoqLo(SaXLmxT}#@~n`|;+nLWhN#K?E+v4%`u zV@%6~GO_6wx@H65axgwDe|3xV2bySmwW4%02LV-!D8(YtT&IR= zX5s_M{e)6$S}RG~^2vP#xm^r!hJ7P8GW@Ia2Z+uut!*EFBtUgQ{KaW)$xLfd7sLx^9uy>70WZqnG+jg#iy`q8&f+XQws z%~+GIaLV<~F1&EBE<)}-v^T;F`gvGzre zn(wIYTEE+Ep39otxfZKQ{<~{ly&z{o*UF8!$~kBa!7X|7pbfBo@j!9;2Rn>y?e|kk z3#h0v;FsLxjR=!^+12_$Z2n4|Pdp+^HxrrbFl3Xu3ra`&v415!b_O}l+3m5;>GJ`+ zf(P5{zAx2e|M`CGd{?~W1yu#MPY9hS!l+hB^3y|=(X)MWC>5+Dqk%igF;U3#y1> zm@W`=K2Far-<`cYxjs96LB4Tw^0t{gBG6r9e!%as4ZCTKlyhEn)#plWdtE=;rOVo=w3O0L<)^Z-q$% zm_8=EHJ_&_L~nc-f8W<$DxwWl22aSrXml_F#q3~o;H{A&R4qDvrdfio^NLRl>E4eK zA#Xh*9`s^cD3=VCkVO$z4s9j6w=6np1#z}|+UTH$mV#U#=XtDmbYH7mu2P^xcDsR=ItCZthWTS7EqDj#g}F)SRfm@fvM z8Y3%2A+f1qQN+|50G5i?%$$FnPT}RGaw#~K;Yq-Asbpxz>(S&8Y(ZhgCA}SI733LPi}j(DFJXbF1EI(qz(Z+jxHv0q?UYR$bDB zC<%rpP;sC{&&z^~8$hjh!p!yeV#I#oudZUW*py1K<%6B9PM96Xj3G*E`Pkn*t4_jF zXzK#exu~Da_9S_Rw=B-N&NSbJEQg6Yf?SaEtCv^jpL!C>eL5$+@XjphY(}e-+RRS5 zhK_4}42q?(Jnl_wjq8koGUHM>2>09VMt%ABlgrq;o7!%o;ThB>?4%6DQ{xKpHa9?5 zH&P2t2CfK2>AJfwGA*l4&$_k%SmL6Hk60pP1K23=WZa6hk?K=OWGjRwS)Y{0> zafoyO3rK8E(7KnVXd(*W6@nc;7lx?`&Da85z<>yL=T^e~Zz9+57Z>ugmx~sEeesu8 zCe&X;?9Cx!hPX#2gd!n#jXN&-ObyFpVGBb*&kwok&unsL=K(^>JJtxE#F$a%i&ZX!Q6Il8RciwQ!`xbqYe#>wu6n zdhF?Nz%X_iWO7r6HC z9stIzU33MXCge{ziGkPG-j1LP^|7^{%Dtb;y(6Z6D))XW_uh&Rc!gZ-(b)vKB6}!pJ6bo6If?T}1icHAdU6zEH=+7}hpw(Bt z<2komp_#gk^)c*}&g3&n|FZCj z+DoU;`(|xD)ne#~w@sy`TGe=I7b0=x#I6C8?Pj7x;f){BHh!w|{fC{nhj-^1 zPGRcdTyK?8&!mxJBM42ahH7!!2r5%@31hu%`U*Dp0Ff4aj$O>CA`dE|6h7Oon{4;g zg(%Y6|Gc{prBnkTc4&~A8SD%6-iP!U zFJ`f;zGcPHr4P{MgHLBbcn+x&lLBgHxqW>Icl&NSSgH&&2W=v9K1-AVDfkT|6a9^n zbu|cW{1wx6VW3cV%-qz?`P0li_HAX_6vQ0vonFxBYC-&RblD zneoUZb&+Yw5kdTde48&+}FKM=u zqMFeGnbMXyvOIn3uud2?wPNr@>ZBidKg-x$W)k$_ECL4?v}6M-(QuVX6EAcC)qEu1+WZO6FQwLrZvB{f=QLM0Fpp$zu^CB+K|o|xjcIV z`FCK0T4Tg8ku-BaMYN~1u{%eEoM~yGzonhaZK5W+&Sr#atQZ-N3z^-d61HR>BLapY zGe&c!u&0z&+N+A?BSKzU?l9pQH4MMYSzcQ+6+kPKCcmCBB2~_;VPGkmwWnw)2LPAC z?W|*N6jgH+t8TZFrnX!=n^7@EO%PT=By_pt@j;)y4AlOC6MW?kaM}=?;i2{qt^*8{ zfadnPOPw|CXt_n=NsWz6TPoiOFVX z?<<9c+C4^EIGc+D_ZXKTpo&)~yJxZ2xXu6q28mg??N53QZ5imv#c3+%?4itVhhaFS zWP$o^dO6q|{|y2S`woZR?xf^~Iqq)lWbmxIANO3EVg-m5%k6L29HzioN4-Yg#4W== zH*DT_h=u*M@5y!VG0`uIJ8OsBz;5_K!*QU1P`r_~%2Dr8lIs{&SOxA3Z+L5aU)A>7 zy5XxEHb2mKUo2;y@d|sqS$Sv8^$lDa{PR66cpeskO69p2kPB(-UuW;Rc8ck#WcorH z_~cRTE)wH0?yd9HamWpadQ&i*;HCW@dQ`G-4!9=gfF_Pxu%S!tmV%2Yof}k0G4!Qq z%d2pEFI8vjx4Iy=81Nb5H_)`WDrm-XlGi{uYAHw!n?@BE-K$+OH3ipaHtTS>;H>{oud zAx&;W_h*wLp+zfH!%JFOaqvG@+XimH8So9t(LE98-zM0dn4Y3B55;`oY*t zbHqNeFh?uwm@eBt61%u|aQ%p^KY_LRXzC`fSwJ4F1)?Eh8c^SmUhm`4#}bRIhTM>< zgjsiQXw^IEA&dkCWU7n@X9^NzENkO|B;Ah?Z?H>Wt;N!;RwL>)GkCe-1*r>1jU(FNPjwE{sb3B6p+%qN=A#Dd?=vB$8u z4Tf~x8Sm>N2{dzeck~!MWMy;;`F6uDkj~3BdF##S^%BetLIW18Zw%nUGt3wNJdTX> z72XBQ_*OTkZI=lI4O#c|<&g(SMPGF`ca)mG_$NJ8eKp^RPhH=np}!5r(QYTHI=%y^ zaDws&9+xU4u=LM!c;i$6WEpg=#u`wuv_!hv*YU+(HDgUmPMGk$AK0V^iqFEgAJd7{y)3_X8jm`vq(Yuh@}v zN2tY)AwDAP;`aN0LI}o>F_Pv7b1G}PEby((I{plR5blx949*#!M1{@4@&^jx^b}T` zjduIu>yyj#-j3ncSQ~T=w?}o(;k_RIyieMpe2!jWUr3OA8{~wXHe_|^Fg@(IO}fvP z7WS&2UDQZYvH|O4iHAJ@w`QW}DyxU0jq7R2+ zw4n)i^fhi}{sL2`s1VX%QhDD@UPw#O1DA{ukQ{rC3PA^+W96eS!X6zwlKPNFS=?~G zxf^v81qEn|=xoMHx`DG}|GctC@zQxn`jpr%FjhefQ>8U31_54ZBjqP#|MvO*qpDJv zcoJ^-;9U0cEG(TG8Fh| z{4x1|Qv*hWV0U#xK0TN76fo-kc?uXk1&lTtFxr^H?$x4B{ z5d^Axj_Bi7K4>MCHx>IXb;iiS!Dw`VnJ^n!tYryiGW?1#k;&Xr;JUYJJmE?ka1S&A zfX(ec$dwRV>p3Fk5CKgO9z))UM^1dTc~iW%D$tnVewBWE-SKA1Sgi5(pX*(U@2KFzdicf(Xaj=zdJfQJpA$7H{V=ep8bO#{raP* z%NzXHuZKUfvwy5P$kEZ?{$sO6_gt8vR6{&&FQ7=TH!Kfs+ot*OrZnvK8qplL^7-KN zbN%?2{G2^Mo5;m_%BI@vTOoLP?+7^#v%%oF8}O-Us#(N?7foH^o;+1deG(N@xLZ%< zQoFnDPvug5N%mAOwL4eWQ@PZ_pQq?o`12I~dMcOtaD?KiTq<>vr*f$$13xJg@l-Cg zETf*vrJl;Ap30>jXSr0rbbnWD)hU`nmqvPV2vk~uI`UL7wZapuZh6K|vP{;(T+16K zHsBUs8Z*ra+bwZvyNNe5!NdERX`OQ>vIocH^Xu>$zO`RO&hq99C&7&+_K2Ji#WG%T z2OLcC^K@8gdof+3+_}B3te6Dh85-!SmJihF>kG?ES0U~4(b@zdc*iv(dM4{4CyM>k z8@cZ7uiG=X!`6M4(0WZrYg%!8(%Hjd)3Wy!S8)5TSSCgO;31Kv1vMrq`kt?mLB^4OO_1Y+TcDd$L1KQQSRzb7+UD?K`GUDN0AS^6muc~b*mNWrK!W{zQ zdnoVI#_)K1-14@s3I01coLn5Pgu`7)j^d~7esZ$BzchfT-xD6|b{|dkyKKnYlCbVy zYB`=8me`2iJ>Bj7^#Aa~y%T$GgjrU(<=*mBCF^RJ zUFBgy?`rnR2d=?zY$2l)3m8quk@t3R(G{clTT#q+Nj5(xdZ0jym`KR5n=yX|Lo;h| zZox5QIcnne@gXF^w_<~%G;)I!p3p)^#uHObZ^fou8?|F{(u6biKz zD88+_r)beoVsyzjL9vT%s5Mi&+ypz{W+jBi%m~GAGv=); zJIgMphi}k>e*Vn0_yQ;lAw4jb*HA%dVI{)c7Z@&{?{RD(Exy4+5;fyh>tSGC5syTg z`U#4t8s~{hXw+>|8?R zaen;n?Bw*#*{IC7tnyCuwcW5CGBljg8^zYx)pKoFiE&0}1AFDo5`Qjha!0Yt8|+W4 zs&>t*7vxOnTDcKdO>E_fFE#X11r7kVcZ0r3@blQ&&)hD*Ap7jS`ThQY?7yFA`W_ znJ}1otG&9=qW?t65~A8lmRx&Xqomo43$_cX#7jEe=^cOxgToit5Pp=>8z_~t{AMQa zhDHu+&4%3Ug3dQ=4wYX!q_mr|};?qg=MjRD zyN9I|+(@N&xru&GRQobn6fEXu(`v-ZG_l&NN9Bx^0g+FFt`ok)ETImVnzQ^|pTm zbyMlK51DBDfGM_{ORn8jTJ2*>sQu(pX?v=O2@&s2rEflnN4=vW!Y4gdM4Fdee6C7j zimMqM8WF$uHrzHn%{rq6JAa$#ZFWz0oyb@CVT?&+nWY9003XmXhGsL@MA?U`qaY~0 z4L6Ypna5;qeI9P(RM&7Q;$0eXTh8FoJ#OH1&I99&c3~+_sbP1tkD=&B@Y@J9rFpKH zjup~QF?81tfVIED!FNK6N=buGs8d-|E_%>paVSq5E0FpTR&p{Kw_o=ZhZ-GD1ps0n?hUmG3 z=8${as>J~Z1lV8!g$A7w1M*rPrX^hDmUc{cs+Qd^KoHXasfHDWV`e#Zc5~TE*p$kCCR!i$Fm8H{lz6?|3t#pN zUA9K?8hyO401mdJKa51RmKkrdn<1$osQHm2=U^1^$zel6pWy8kf$oISP&8&;m47YnRBi2JQIyD?=7j5ZKbd)ZgV6FpK0Sw_snmg-! z7ZFbc>n7%zINGK-K_ek^(@&eT;JRfa_?b(q1tC(&sxGkjHXMbXskJc~jyevNBh8*` zA>HlruD1d9;;|C_^#|W58PEN2$zIlnf=b*JG-9ms*a1@PxRjp#@%O)vR*Se|nUPTF z=N zZ0%hmYVRCJ`(e`erp{qAi1G7aZTQVz1@rUA4rA|!?#pmB%EhL8ekD~(u_vM4OvOFWke98w+QKla} zA9TC00H0z;UjCGkw=>D|jx|m*-IggRJithkW2;hnxQ4*)$jRk-G=RVYeW#Gr5GP- zQ7B_Cvz_g7!Q$+=S)C{Wo}LoyYnQs&!)4#oVYrVODY;Tox!j`mtAfg6_;hBNLPsQ~ z^^c;%o5r15IQ2#nD(1KnBLgM@kin}hV>Y9=T-GXOE+fgl8wgbXxvWF5zXq_ZKxe(Y zzkBh@f*T5a)w%Q$#UXpowOOXB-&&U{GJ2F2{;jU83h;d-_+%G&vOPxE(!afeuQq4r zy9Ng_5*Mt|SjeQYpPjJ-cUiO7{oZd zy8Qahkv+}{5w-Kvl}XiC?S)_L2GMna@I95erLoeIYjj9I{}A!x6BZzDCU!+wd$KxiUBmTjq$5`n7javTvspv# zhRxTKt82f-ec`;4eyr2Ox?~;tKr#C$4#%1VUE^mTTig(vSzO#tq#-Hk`*+OBQL69% z4HqB%jiU1_LzTItikA2P%&@X5=)H|jKKjxhI$rmaV@PI<=8*1jRk3B~z`fJ19&!k# z+ulb@tvGvcn7}q09@ggh-VGP|3-YqoMwagw zmVTVF2^SnnnM!78P7Sq-rb0*q=9;@vU6;|Q<^O@f{nWS5M$i8+dba0Ww|0B~DaU^I z^yucFa-5lB^nQrT+Org~Ghinevh=;PeQ^=^0`KVj|H|=o`$X8g`R$4?UvrHVtcqIE zVre}{OfIH%LDk~7djw7T7mbyc?-AnO6_zw~uX+2N7S)VC$MLcmE2-alSut^PdH(&E zSDlX+1YLL8P5GLA1Py7xPHHc&WUG8BQe0=EL+0`}iE5V(@O=;QE_wA3RCfG(US5nCm z#$+PL&S?NrQa}$+U5`s{v~Q!RSL9;71a<-rsVZOPwKx~#B`sO;k}l^-Yez3!1jhK@2?tOa_0_OaQ66(;QnU|r1JB1NqE20VfD)_t?|lGkyDks z7d+76!O>oXB=)TSLo=b#odr&UUOjDPsrTxI9;ZlxoI#r=Opy+#3oFZSu#~};Tvk= z$p6Q&2A`!>$pFU!X`!p_z>jC1ek`|iOtTv~nY`vDH}_H2MQES(ApBLw`!4EojQwvF zL#iMppcBgx&#Ccl~9nN4}!PU1@1aoJ9C_m^Z7n1m#(Nq|Fuwlz2Ry?+Y_4+JHFRe@@>KOrNz{i=cC}JALU~7=`B~3Jw|HYu+#&r+ zdX(p0>C1>$`tp6RG=JGwvTju;jdHsFxRv)!z=w0zoq&ACKP${6l|~_~yy_D}g)P97 z$Mk>s%~{&wmCt7SPi^I#AaZQPtNwR~G^!+@*n1T>r>BjZ&5F@?W?c1-@V`oaN~MW# z#@XECV0hGeX(1m=r-`l}HK`u+F1;^U+r-E_XEnm9sn~l?%euwcHm#-h6WCl!U90t; zI9+4r$E)A-E`kHNTRsu|3?qxZ^?AL4ISin$_y@4m-nBMZwOo%-JMi3nFLi_uBD`GzG< z+kyrgFX*H89(%7TWH4Jrz9Gwb^2^!V)AQ@IFV0Rcr+Ymo6~L?ye#Mqq;P1^F`vj36 z9ejU$`OEq7yVFC!LXd|7v$hQ+D%WAGD9Ih=mC)E?%1HXe@i!;i9p^^^K2OLQ=6c{h z{%BLsZGT6J3r#3xn%$AKUEy}4V&Be}vZ9hUEaNaZELmVSC+QTu<&_%qqmN(_OOjS? ztNkUf8vuVaw#{-iqDP4}A`)EKW%hSVESba)ZxEffO#6*K^1eROZ&8$7P1P?q%cvwJ z&d|vJ>vkiYs=1QXKVP~|pWKlW@TTT;jg@VU%M^;=`K-Z_)>__xh<>0#3dBogbhMkK zPaQHEZRQ4lQSv581|ZZrv5#$=<&MGR1eWkOBYt(wzILla((zHb=TH=V9DcqF;;1`j z{${QZ^sD}(zZN`Q{Y`ArKzJ(i z9Q-hgoPn-huw|G%2dFdC)W`IWL#)S5hoUu6*N(L1~TMF#2omH~q!NMApBp11?Eb zDw{Z4)^PbviZ8c#=fSRnw~zZSyl2s1=FkUs#WAE7V~^B?m&*55KCjr{w8Tp39ThyN zXC7wDZ-dInC()EmlURuMW6%qeVB(c5Drs`sVP>F-p*|E`K#<2=yN03(dgADHh#Oj9 zDM`uRp#M4e=`X)c4nIFQ`0>@`Z$JO#;HN44$Da>BKm5)9@|VNIgM%Nxe)r||#p%!V z@V6gXmEY>$emnS)oc`SMA%};be-tpuhM=WPPIx)d+vkBiL*#Az9lf-Q$is?RWxBs> zI?zsWmsOzVZRj_s)!-LuUv1W`3f=K|Sd&UA&Y+u>JfHf-W_LKFseR@xSq`zbA=Wm; z+J;!$&cxcT!fD!uKwCemI$+55DQ-A?T!)JBOTl9!TaVgH0rr?@g^aG=!_4)=IAEAavpkdI> zC@4xYqYuHN`k2*$Nk=qL>aGl=AS`Vg^0EzMtR}6&ES^uhQD|Wh1?HN*x>|AG2W2%V zt3g=}%BpW=W#r5sR#WxtLeexN*EA=*lJ6~ujT4Y(YfpC+`mSut)y8skkEyh^o63u% zY>rZX&k#oHrjZgAe5C=GMwnk>FU$MfS@!Y0pS?l{oDq~$Rspf~nY2$X33j|>w)j?4 zlkpOyvH7fRNeK#S?b0?QNOL?V0b6#a{@&fnZ0T4O#fty_ERwiJ=))YQT8lYSMyk>2 zMal1Is`I|y)1N!!L;#tAZfJBzGG64*YSfmp31)jyWtk?~3SGPUn@_IdGcWg8jAUQv zd7+}pGE~6xS61|yr@nu^H@c$b`zs&gM8{+GkIvF|`AP$xfY$;LhPM+ICm$Y@s=K0V z4v{zL(^s!@baL_C`hZjP>FbZ*QDhJu>!0uSWBn!>rfr(&gVWAvL!Rb&C3OYanQjsWaHJb(^9aYYW&nHM0BhYu zv04A=?~`A5qqH8B0Jk!UC_@)KRrc7l@kB9waTl+H!v;B&9Lr?UXzSyaM!j~y)9E88 zzDRQh$^K`Rv3EJgHUI(O%DKRw9OL@W;Fc zmzF?o_xDOsLf3{o7E#J&nl-nF>T69FKV2I;q73 zAa;3Ah3RF0XkO^vpm5nH*2p&Hxo)neQk^^`grsIVzmuEa@(%?`s*=j(31^Z#$UYs- ztLCE{#FuthudA?6O<=ezZwQd5+|%bf$DYkJ@r^5A0Y7VX3XRSd>U`hfj4K zUASm7R&S6H0rwBhF=Z&{tx_I^eLNWS3@}>-F4Y#AN1E8q4d)q3X-N_#O56n)3qO{|WEC`)N#*eGo;hm7M?_pi}nAT_I1Yow4i``19wqo3>;Lrdb+ zz{)@zvN3HR{;nBhF*Emjl@;yJ1@ijI01ws-Vt)`aLbD(-k~f?GFd;E?Q{H> z6_Ye4HugSQ(JQ6?cwe|?Ux5b)q3;-+X=P(i5aaby5(e#S^VYD9paauBSf)M6J{{`> z7Z~s%twde;aaFRz9|Js_G(Ad7UT7I@sbfQe-OVhm-{8%Fb{j*^OU%43Qfo)%1JpP; zO(O)%ajGt#zc%fn`)yMTYXhFxp_Vle8(n;Rb@qS4XJHTarl2TceP*7H=(eshP*)&g z6E8{5?}lyMk!=hRwa)EJHz8;*E9N^{%o`5nE%oe$b^vv~hWGtiG;5AWA#{uIZ0Uy| zBu6FZ&aYJZKU9)KFZt<*=CCQh8Jf{=Vqe|EQA!w>#&ZG-kk8;#-FDG$2j9?gt<>qY zr$VW)dvf8%)+S~phdl(=q!#7zw3wTQhtd(F>i}fwbmY1B%FIqOk7(N`U|%J!35nEwr|#^^Ej4{iNh|sM4lfbT z1b03)dn~+cW7q2A8!i`XLF;xrz3WdN8&cP-^68i;TN^+ELZT>1LQ=w#-8f+$qVuzV zZ+RZuB^Kd4o^z&z!X{4SnF}wtt~B-egD8-R&tk+ln}A5DL_0vq*$jfjV+Wqii0Nnq ztPHkSjfOm8>5i}Dh%ix=X3uCFFm=j_0qpAOes}g3y+Q|SzK5W9W|(H0i657%?@4En z?BhhVd@ZQkP(-VnhprUwDNlLA_hZz!uCp6zPU?ZjT4!YC-Qi_E=HuMLg`q5aMp2XOp^ zy$@0hYcMQP#vx`Y&)22{WNbKT!%XNUmxd#~#oQISBUwZk>KpYvH7~p6@F3mWE2Is# zKB^+>sD{H*c~o-llIt8Pb}y?QwBzp@nS{DFIkNg)A=a?l?^?C83D(|KnG(%+1@*kk z?-~$q6eLM_UThFXaIG;=YLvE+f#x6MmUtOcw1lOW^9DPB{>@WNAbwW0l^G`hnBbmm zzB-^0x}y=i;vfuRqXu4JS1}2|sGwGbu#~bn1SZF*BpHTIsphWVYVUPlAa7`U%xgG? zE*Xl1FgylZ(0_CO?X_PogxS*6zpJnO{-6!3>)Ic(VQ;SsvSAYkydBzM73&Z=*edX0 z{b@l<{K23fj0E1WkM@He#kvxSy04P5x$ylooMnMIo5vhAd#GJs_I2l`Za*ek!{VQD zvOW|SDpNLI-|BXr3w%xX1x}EG)|emWfgSf+H>W&7=PrQ zYkle<-fzZHipgr}{^S4X5xn9C@&Ez3fL`LJFAzK3RIsGwA6A8-9eT%8(r1y`cm9LH z)jQ!#kn#?E&CwW*%=sCO5iil`cs?(Q5cG~rpQEnxAM~akNDWeANhVNUPSXEap$1{IbFT*o`=pTbVNPTqQ9Y9-&E(Fv5bEY+c3nS$DCepgok70AU z{^qI!rB67`^!N3|y|QGi!FXyyU|8tCdR9=~Q@McPL9&Uq=P;$VZPj9wDRf;k@37LH z+d>CHDZpZQh8#?cq^2)NJMtGU?c>q@oBiHdPW4)qyukC8HKuV(wmOb)_%8Up{#?Ut z3-ebbt=)QMnYV2Z-sqLCqXZBmyjK#d;-0N*78=kcgmL2 zmLYcF;HYo1fzf$kz6Dlx8OjM}max!X-iE&vHJm;^T1@)F$q1CUR2TsQ^dq4AjhUF^ zl!UHHz04ZQ^5~eg5L+3w+lXU>ZBzr zt%d}Jcc5Gu(#$42sn8-{1q_G!@%re=lEAWIpltMNiTKQ2w*HCitD9{a!^Y|b)2+6J zeQMVy?c!kFG#a4;{j_}nRT_tzTD{YUqTJL9o<0e$P+)c3IA8-MPkEEgq%|&Cb|$NyxDYMo>0?`mI+wSUvjf1}s9` zX*Lk`K58s|6%vrN&^@Fib%ewe-p}Y<>~*nY7X+tJ9QFSEXM1UIc7Anwd5w z`}X|!8+3JXdV;<T3&%?7ajxU-=85{dU_x-i4*qA}QlzuUk;Z9xjOd1;pM?{qMyc zrpFGHew@Az@T%~df|PeO0egk$;ovWB|c1KF7 zEPOs^^j~f~mjcVw>61`RQ8JwAoYAJ>*;}Hz z0iI1u1&btaGt`NL1yx0gTbhDr44vSdWGA>?sAt1xNu3ZeQJdfEX|lQIO`NDJiCK!v z)SQof;YQnm^|Vvz6>Z-N_!Y5`%7XCa_lh_HmhJV6^%{ zs`ix!F07^2aax0+SU(QeeH5UgAsvq!cXAX#8GH`w85+<$vqmN^<{7n{6y zZV+p!pIsoFrls2~;tY1oOoI#^u)spldHW7-x?D9|0u%}}HwYCTXeq}G9zKR{Eo@S% z1xE*1prRG;JE#Rlh&mbKMFFnTbLsSTq{9R3;$p=Is`Bo*5nl4RhyzKU7%pPd~!36X+qOh zB#)H44Cla{x)C~H9Np1URyadv7l-4zS)Xax39x<5c;VAZhx16H$6mjlXojx%#@QD`~W!))&;>IDHn|H{xB@rk{6lJh^Z6Z%miZaeTG_i+JMcMkzR@G^+q72a;4Rso!DBDW%b#)q}C__AlhB^&U zlvY!=RT_`#(;!XR`X)cAPupwCmSeqNpFX20TNmE8)2GjA%9g{m)2GjC%C`6T{ra>O zoFdGrq>M_6Gl-eHuxsspX^$AaXQ9WfT{;Ryfq+f%+1qOM`Qxjf;pElBH!80}?(wvB zCHIP)UhphM*!5OZr{$hQ0gyVy2dT0xgv7}$I=c{KrHcsFS+g=Fzqnk4I@7v*%zKu)^mBfvEG>tcG9NEZ^Wvb8$gUZ3 zK}^@XPZUm!EZDH6=?(K9Q**{kql*|%HB+=FI@-E3nmtT#gcEfpkSy_RMs2FRHejdz zl~Ko5V=Wn;!^v$qT%GUL&(qa+kn&WQPb2GeHHoN7?fBw)Qn)PXU2A%CEP)a;B_;x> z-sbFLiqJ7ic%E~H$OFy`%_wEpycuy7t<4G3Gg+-lflF7W=qI>aQ}q6B@6DzwN&Rtb z;L>fZLx<_zN~uVclbYGy6olv%%%y2^4eB>#F1DCrQ2O8I4 zNv#IUl%zj&70Sw20?wV$*!F^YSn4zB_?B7=%X*QZ*6toJjRX~<$}Q1xLn0$5k@c7o z-x8FxkEigNd4dH{tnShck@p13s#0PWLvUcsv??UaP)ag-*IKvQM?+%DSe5Eo6X5D{ zUf^m%Wen)r=CM|hU zkaT+3=wM)wL?h#Kj>dK80%36pUK+jaHQ|*Gifgi-ddlPuUhSaJApNC=4pL)V^MYr5 zzSND#l*`aI3ak4U2$0&2@5ZdCTSn$?lQPqIxq6qtxod5e)fJp35o`=K=;b&kvR+ao zNRFALi5LSi+PZnd)Qz`}qhl8iFu3mZNkANpnDCvtfp!%NEg313U`X<+b+Q1Q^nxb0 zI!MsI5m_jM3c;CNoGeIkYhQDdn&Xk-yy`9kVa((rQGWq%try;e^#Z^o&V}ZFv`4r5 zGzn@WzgM&0os^*e*aT-feQVHajp#&pB>K6eEEKjvL}VrQf`dq49>s~&A?j(Z9*yZP zj6K)%5Dr_%QsGTZpH8*elGnAynqy~9?~Dq9Fo^I(o3$;&GSC+Fiy{JbtuHW?Cs||) zhzBaeLUkds;_=iM<0#{7PD(ogvsVxc2Qj!T$YDh4AX!B%BCcGBmMuFPwC10D93a@* zH?_C0-K|;0XY9qSVkH}0{JM>8sx3;bvJ0NJy*?mI@3B_x5@)x%N4cdRlGW6}=x8UdF}cNCY}WiXv}YCgQS=fNpg z5V|yPJbNX4F?|Fyr7plIV7Js4J{wIN3YxDZIj=12)8rZbgl8aLc0DGd{{o%!GB~|9W@Tt-F+rPE|mojOxiQ5Oe{!6 zVCIm90E?p!t-<2FO#-~&C9n(XQ6gVujb*hACd1p$&2umlG zXxR^7J%rRKPSUa2+A?-3ci%TP_optxNeq{-b@kOIw$02uvDHSwkCEglHXVYr@;5GG z${BGWS$&Lnm0Foz>iCrQ1lw+may3j%x;CC|rxe!=w=qW>-mw%#I+T-|OkwjRw-rij zi*S!+vQXkd&E=|5F@`lqA0TSg6`G=BZ>~KIZz7b9brpwpiRhg1lGJm8*M?|UmqNKm z&!UU{^74I7$I9_+Irz6GTngK$hHnC~pTlp~Vp|uq;>gh<0V{l!@P}lQuLCv=Z!B)0-2#VjR|0(S8q}$RKUZO!cimMVeqJN zQgWr18&aUPLirAet8C)}HUSEqo6OW-N>}4xU$M6B+K&JY4oZRuOL$dcQ^imTvNGw3 zD;I|Bh<*{XyEZ7d@q2g$_=Za*MK&AH^~@TL3t8nkEHW%-yvz+fCY;HVsFzBlm+)B8 zrS5nJ7W3j&PC?AtoRpbuYJx z@hy(D6q(q3^`x<2M}I`zWwB{`hHE9`O@2eG35SFw4+R(Yj(9lYKLV1yv6x1K1HQv> z4hnd)GKcfqI>^SEUBrEjAegp?kOpvln7~9)T$Eh$glFx)6d$a#hsnFwYT7V(Xw4hAmY*zHJ5}$lFBPA+nqU<7<233D-=OS#kGqTibAF`$qbJC)C#&yEU zCO`K!wc0+r}lcs-sc6@$ZzlAl~^`D0E zH0YnpFHR<(ee%htpm41KxWB)jQp_;ml67iR?Vr2-6BzGs8vLI1s!wbO$!0*{P0$0? zBlnxqYVmQhk0$7=>+6f7k5N&ob9Kx3eMZtbfu6UTT|{^NsVga=VUPd*Aa1O}aSeUW>ykI)4DKyI#ha!X|Q zxqtTWpMKhXR$_mBR@dKL#m*=61bqvxR4pZp6aR?m{P+PwqDmGBi=biiWy13Uvn9l| z^5rC{gyi|eP9sEW1RFCbpa()<+JTu?2{ne!1F1Hl5OtXG?fKO&-yHwf={I3Q^f=3m zN#lCL7)=gDV0B-*iqU^oM%GPrFN}mUq0HluwX`mC6Y}Qb`{#umC$= z|D2k^E`k-S>mNjCI-tZEX_z`xxNf{Qv>a#x#vjWdfNwuX6HX&%Uc~@sjvCu534&5H zZ5jI*-JtOtqId;mK2<*a3h>9csHXU=iP8-k)JOC-fVwqGcNH_ULiZmuoaVq?!H+(Q z`89H2m9UA9LFejA2VX^na$ey5ukM!VQV7;OoR?`IW`s8AZ z>f-F;Dfbp#*@*k-`s89XMx*cEs{aA}+ttbS#VG9Bcodb_Cl?#ny%LvmB15$=X3KA9 zAzzq89+CQ+f$!CA%g;?a&(bqtiK_z9F-;4FfDWH}89n_Se)rs{))Y2&vSxdFtp@(= z(@#J7bgDa$IfI#jGylug_b1RlBWy^kDm@D829!4A{FbDsDs(VLw-<+Xh_GJuBCYm} z)>iw}pUR5O;GhX%7Kz@pef9W#A8Jifbby(GFvum!ad8+O5mFO2art!;Q-`AY$2n)l z{Bj*u!d@n)(qO*?k%;`W!kJAV_;2`fDjJ*z%H|Vnj*H1HS+)#k1-#9~X|qm=jT{$kvKrM*M#bWs%S(dO<*_Y* z-(;fWsWH9o9Xj*DmI%)Yldf$S&dlYFuI01lxw+{n6`DC21~cPB1e?#Gb=&fYaXEqi z3SdKW0Dk4j0h5H5KOX<6lTaoyA+aR0D!U?bUqE*cU{0&OiGcJ3v{gk{m)`?dhGxmo z<4`G-gcq(hwx~*F!|LAHq^yZNLSEL3vjgEe&oWY)J#;;2PTh_vL2G}z%Cw7Ux=N^d zg>9tJC3{6_!8}rTQ8Xv0QD%ip;-X0;MI+eN5maA=mnGophSx_A$$4RtnVGo0FjWF(Qi zY$rl+YU^|^f-`Hu#%G+oy5x@*U2<(*f;`gsC8ZAFc$;*Q!@LC*q3P8Fn@dwR>bhfO z5a{D3=ZA;o<2r_lSzs}`5*lDM0|k{v#(3q@mZi}cd-oq0G6 zg9LqH65qXz*e?yOuS}6ZG=m^QP|l8L$}p50Ev2Y^@Dsq$oL!8x0}gbdQ}mtChd0Mm zcR)9DL)c8N?WXBgU^P<5lxD_0&Jse|S*v@frraLn*6cF+2O*GNIaw!A3lVX?9(_&? z`UpT-`IWX{*u|ZQaO6i~PEPw^Ok)M?*BdXr@;ZA#KKDsaS0fGvgOH>-;g!6C;@LnT zK$now>c}hfF~a<-TcNWHtv&4e2uYLMB|KyrIPkSA-LOHS|9pl1?cdPf|MAz){{7Xf z17(T7Mk!t%DxGDlT6^fxKmOrK&CsFW`fLVD6TW`+S2N-#Xu+#e1cp{(Bhaxi=t!@= z^%smO_tr9Nv}#!xe-^LThtnu2VR_r?%Fn{f)&Q@?+ z4PqVbqT=?wF&0#rr#Dqi-|1>0B}elLmzYUHkU{g}bfI6-);xw1#WxCiRtiEiV+oYT zP~F`M?t6F34!ShI})D1po+9N&n@85GNdG|70sef07Z7B+qlwbw zI)3d~jVG8ktT&G(CxnAv*WBswK$CjCSC?nxo;GqRdnHj!fP3Ovk$P>Xlt}R)-2sIt z+!r6Gjo6A?SufL~ompi%LxcsJl8d(Y%}X@gEDenb1Xg5OC0;{UFB+mdceairHA5%* z+dARVXxn9*C^Q-vgtWAXLi&Y<-gKVH}~G zie|dB$(=6Ub;Ubi4yFUlznb|npdp45#l-c^1&QV@ifD58w|)ix2KleyP!mu=4b=@G z3?JvJZd(UVXI=%1WzMO}Qd!wh-EnAwC+~aNwr41INg8CrnqJwqO!3RO8|5w}B4~1@ z4g$_B{gf$9=b8$~GQ2c;sDyI7^ywO#D@WOU;{MLM#}Jt6U&DnoUWLx1n`piIjtl5t zO_+qR}{+qP}nw$J;0|K1Th;_Ryv=VnDk*2=8Bs>odHfnHXV?{U$Xos6Gh;@BZM zL~&I!l(W1vpkxYY&w}d**wTKZVg<7lS^? z!T98dRy#w_(mTU0)jRwtmj}U%nw>*xx2|72?a&GBV#sjl-r+M|TrDfhK%77Do_gi= zvL+1xif$#bo0Tsx(mH%!Fpu)Z(n<2JmQfi$=Ep2tmM>^A*4+mb3!)8Ej_AQt#`bY3 zPY$i>KSMJLUzpw(s1FdniU0Vau}X;rcj}@Y;&ak{o>chxg~Irq=9+b6Qq0EkpNQ;t ztSr2{e!uqw0GyAb&vh^!w6{Kl==`vnVo%;8Z;wmjbwiLWX|^%}%u0v?2Gl)SRkX{)j~~0nKCW(97!MsoGX3=xXD@K<3t}xX ztS4wNG8_BVESR(J_2+)2{8e+0UG>nS$X+$hI2GCMePz5w&w&J`)6*EIuUxfAOri=Y zj(oKz`0MZybh8wb0q5O<{>CK>J;a?T&0_V0a4eIB+Nmrk{}U~4Y*P+66m1nw)4$sO z+G!t?1X`<`77pG6)E1PEQ;OjnaK#Vp_l2F`0fY$ScLVG}Q%C!7?}rCJJ7#`ckI(9f zFVfKi=D3en-O3llHOLdP$=>pHg9{#C?9Eck9a=By%EK2da;ibL+4aH{C`z0iy?3vt zy(;S11X}qk_!qNuGETBjKd-kBkMS!7AYV3}Om0+hTpr#K>`b+XLUh(EUKb5~hVsZS zw(+m;GvB<2pGsm6RDOZFHaJOo$TZDv+E3<9U$M#a0J|y3d!ty>Np$)QeT;5%K~vj{ zmte&|@gOJphZf*IR;>p}lHS>n?#QI^&P_N(2x%=x+edVknE!MD*2Z;YPd0k<_5(b|N@qb8OZxUY4LkH>OEeg2)Mx9T?8Vcj`i?6O?eApx$JGvjSD+DQ$k zso`;^oTESIgXg+Jo><$~HDDcXnG8SunW2xObf!7btqLm3>?s}haM+Y*FN_R(mvkR8 zj+`n@|I4)0H1OCggC8GCXcpBIyGnyFbbYy(ou$CBEVG{^Yl_KINSKqshY^!5T$+g- zAp={63}!2Km%wEI=^~cDt=v}WpV4^t=+WHX3FJ?uJ%qudQ&u9qqX&isT+cU+lnCBu zDfr$DB){CG-`Cpr0w9ZDcIV@5FK3C`egEkMpS;OB`}^}`V5VyZo}I>Gph9d}=V)1v zbzAA8XT??Sg5M5PquCD+QRV|^Tu-w{w#5@IXVErMAwcY>hKz6KLA)H|PwfOfR5q#f(?W!Z2GzA4+PO=z_FGyi#S2>pIm^J#Ma!VM&AtN8Ixv|^-7@x>qt(YF z3{HoTzaFotPr`}r=I_9$N=aE((A)@ZJ@$5?^$rYO?z|ULDlW(=&e>iczl1T~RoNqn zitXMP9m7xAqaTx2xov!LQ=O^SLlUEc9Z1+SKJ5mAsBHu3RwbY8OXby6P!K%(QOnmw z1qJ(Odr=HAJM!$NnCI`&;Pj6cGK2}ED}tfPo{)jLQw8h0#G@WgQX^4xdL6Ww3#r|Z zc4Ms14L3O^q1$eOY}3 zd>bzuJmmP%BcApGnDwAMLBu3^h_>1l-i|6`4BEt$1;u$jkSz(^r79LyqeI(Xa8ge# zKx7)ogOOtwFUmJDc^Z#Sa?ZUj<3`~@HK0*fWAl`qabrapk&!R!m1(a555xjrMWPCF zO68&iFDR?1qA^J(UOWUdrerNc-)e{4`AHnKE?QhB7^#Rv6h>)Sr{&eN)z)G+#1zKV z;=zqBqNd93%d~B7tF5kwzxxY&Rf4v_lEg3j$-SW;r$pnR*-udTV7FT?qCM1~MkG6b z?#|)tWMH@o6Nzhz&vcu2lEb{Z>ZkPxKgHdH)Pa)TK0K#k+(=zlb0;+fb-l-028M`_ zK;^MUt+2Gm-Sji)gwym4`&OU4H(E%_{5K0*Br{S%s&PVMR_X*}hFr;q4^3sf+se#w z5x!NlgN?d8PczzH%dnT4Px+AsV%9RwF15^H^Yp>L)Rx|d!5kflVV+(zp3dDfU4%?} zNnK<0kjjOow}>USLtt{`eS&9$ciNn*>CY#Ip`D;Qh}@}i8N?^-_^}V#t7o~g z;A5M7tkd!4^w|(`Pn;Vs7A#XY!azmanZ;o;{Iy z?)#KomVziSMPCuuj|Q4|3zNB$Nky+TRX2N+v@DbGU_=v1CfJ|V3@e01Sp7S@(I{-* zf{Gp3FQBLd+IX7OjJ?uM)p_R-3sWh7yS;sjTeeFUB1<+fUhe>`P;mFv^zKH@aDA)q?m^UAOvo z(4rcti1D_F<=JKL3c{tO61uCBuDcx**(R;ubL8y2XTrb2!oKx1Ft2$^>=N+^Z|DNRd_Hzq#`sg6rc?Svatu zzY27;5Yrsx!cYaCETX;Kjw?4{(XhB`-G{pDcQTWPs1QGrkjzkBc(k`uy_=We131iMuF?N5B-0nt!M(8{sxATOBo!743_M z=W?=^Z@%!6=B!u;{W&UQCj+L@p9j?usy*iW;pJ5JORbzQR+mMV00K7|2}x~QY8+h| zULy1$fT|_g_(OmXbUE!DKjgV9VY!SaDLPpvM^?VkAQk!ZHap?)miJ`fA_;g+PE$)4 zj<#&bZw`MJ>6kRJu15~4tP@O|>s2;eu|?%4SNQ{>KHP*X^DDd&(+9PbjpOX4 zdhwISO;^^#x2bsnxcnTL#x5c@Vzl(=Yj$_|0MjD{uL|P~@z#TC=4goO@_|jGpgCF% z%P4r$Vl7m9ZW*W$;L!2XD6RU(u=tX>*lW+xrx{ue*SB}#DgRvp7f+JOa=NER?&Z65 z*0uY_g+wkg^s882P2OtXlE}cnvV(-Cdw7>HD8F`PXv~3U38hDuo?f|Pvx{wMox|Rv zqUShM&;8`^OBI&ywB!akQ*SR&eJlXIW4X&h-Ef`t5u=HSOdO4}|oExb6ez<4k)x?M9zC9Z@7irU5;gp^W!{tG(EwIog%1Oz;D&g5GVSLVMT zJ*7KHRM?Yrb=;~B=GULi@{L_X?cADOxr{qLHVWaa0d^C5Ky}mjeZOZ>g#xJ=T0#DA z!O!_m?tzxemCEwx+*|y#MJ~Rxnhj|v$_>EVp~2KrC4K+TuxCe%91E+Kth{cI=WpWV z_GK#PGL^8dbrkvs^iNeErRQenWuqG#yOt+P>;8!W+oA?75mp%Q;95XEt4NVLrNa>x{gsV}&X_^NJ; zt?EV>_*z^qHhSHb19LExQoqV`obBiiGvJD3ruw*RK}hyX2Rdkks`3Pore|m>+(d|^ zJdAN3y?yvt__^i|R&knG1*2uy8Lv~#&w~P|u zrL`9B`%GZ?8c@;|pNh(J72F|GQjfwn<{nVA_pFA{LbAY7T2Qe*&-jjRCW693Q3bx{ zyd~MXd*;u%{{kX))|>uR1ULOEq}76o?? ztkBID8+aMVg#UAGu1w%-ZZoJ$bc4H3IpWE6n)917HEbuoKIU(mX|~adC}E$F)xCSq zn{_c|h_`DD*Boclw8e{)<4XNe7ATD4qU+*A?;3X z92Fb7nTUlMYvq0%VlT5@3Trvl4_ButG~x$xxIoyZah`{m*wL~rgTF=h0P?dF+yOIU zfZN2={`ymj-PL25FG|)_;w!60L~0Chm(}F3XQ@39%)ezighIQ<8pHl2E=So0caBXs zK|psJ$lw07SwJ~I)8SMY{GfaQjMkMz9P^|_)c}E1CEAtqJ&Ba3<*2q@+uGVQXglEu zEQIj~egVj8NQB7GCg|Q*R6SR(Z^QT$sN4P3if6Hxwn^^k_LuQ*MYP=XYW1z)mnzfL z>)iIW<`#tyt{l(5>4l+m!`!0wz68bbj?MH>)>WI02w{*x?YQNAB3y4}u@M$>rLhoU zY7C|YBOPpQhA4sx)DFT6NdivhFP7}ubZT@g64S$LVL5{iWUuZ|Z_uXAWZ4p12wjXg z`9ick1oaae$|oEqLm*!148*74M6f#o`PGy{(`o2)qRas%s>m!O37v?a?T|*s?1Y~x zmuXZQ*|WK_TvjNi$)dc_%p-INYkd280sE~*&%CAR`<{5o9S=aPlx^eq;rrEvs1tz{$};hD4G_o zb55=-!h=?tMyegVU?czu$YCG=5z%2LC z4uC2hz@o>sdH~fZ&PB#i2`81cj3EE`^WNi1e0vNz@($PWM%dMKYCclBk;uq~9;}7! zK)lyNi18h?Q~CCy)hip6(4~BIalIqs^4*y_TXcMQvrK?8U9p(cU_65HNY&m{s;1ziD7j#I2h$_( zfc5qpv9YXWrJ{R?;E;it<|r$Dvh+Q5G(hF!Km@vy$HfktUQ|xd^Oar*{E~l~$rr!I zj(hu*u6tn6FWW{r<8hIZ>^^^of8G4pN7hKq(mnJaW1g9f32^8z;}x2xISw;RjD`)) zfkEddJX2o9uP@W)RY8b6d^9i;eMuIEig6NJOEm60H@1bnm2`tTi*W;1_N<_1FfAlL z1}^(UXa*FPOqjxMmlt&G)TKjC=MNlQB+o0_RaaS(Tmi^&lF1YZ{1pXzI4wu|&HK^X zLbt*9NGDHmb(_C!JzW*Xbpz+zy5ka-%i}5ko!RP(&3{Ty*CTcfdaoZH*lB}5Zu@RTuUQM zvCWJ0dZiHD^63@3g$a^zK}s*NIEoIYHYwr1uUUtDvc6LDi`?gk_H_yiR>Q~lwo0+K zO^0qH7vwvko(88EA>A0NxUmqnXd3@jHRw{1c`8EEi_-#_wNShYQm|46C&~TA6ePM4 ze1-~e9Yt84dEu)HzRuW>i1gBMbq<lmm*!nVq&6zB^L$0lexyH`Ano;-qr;a!@% zhx9<_?m0=)l-~ASu^Gos7y@Cf)Vjn zW^}zgl3na)KPn0-eoO@#oTB#FQBdk>7u3Oh^*d@LSYK!0ZL4B8^s|{VmEMI*X9f)j z@)(rXf`nalm0-=8)A?3aD=zs#$Z}<`EaRQAy^JIu`PV`s_z97Uea60a+AHo67t0K$ zzonZlSKYO&*az&>O2AvB6PLHeM(T+U{*!(+v)L7kc+#{$6=(iATaoUl{0~66h=P9gOG9|co6^1 zHRV18^NNgDfuHm^yf#m%=i0__PUr)-pE>Nj6qxqS`MB+Duu4EVi0K(-eN&#F7dkpCYJ8_-{Zqza#1%MeTk`UzbtRs*?x(H|obJh4@o91D3 zz}Br(Jh2;*PKU~fXW34PXXO+ma&2ZMa)FTmf8XYu|L_0kQ?bIilde^8A-Ko>LM(Hb zK`issQPvRsSFg`wxgcyG-Ki~-Z2@knZhzOOXu!44sNgxAH`)IC1a)8Z7oGrr2ZTT_)9|* z9%8PVUMQ-j9C&&)g9;tvAn#|(;~=3bB0^@?;vX%Ni8!Ua{qR=y}F{< z0@7&DVzOXRBfE`@!RYGs_B`ZIB7kW2A^Jqh&N{KE2sU_{)h+ zVx>;BJSMM4y3mXD(aqz!8um*^^BWL!*%|-?7N3B}kZ(F+ztsQvoz3nXt=S=b>1>;g z0^&cd%)Fk7_Hd?0w=>*~dSbYvP}}vt^ zGne($Uin~R;-CzcZxQQm*8|cQ_)o$~r{R4B0G>}cBAM^oaokd9(&Zs6 zhud@F5LTa5j=j08)}@Eo#^B;{%M$c-5Epc^Bm}oDl#awPv2KeZ({Q!6QsFt^A!eW1 z*v_aZNlAoO*Hrs6yeji#{$J#i>`^1qicQUnJ=vJBe|kGua_O7VBmhlK zbQzP9Rn`*nN-pMhoF~X!Mu<;}#M41sb}VU+QUS~+N@{bsl5b3vLc@@m=p3t!Xf?+uMKWnaevU`#} zj~ETEzGFVQ&2ZlLL`Ev|)vwnT9IF84}3x2V}p z7957KXh_ZwmumP#PmiDP_dWF8yxcu_Bo_o4kYijD%Qli~{nyQ;s#Oz*lBjNru!CE` zXXLJ5)G;t%95nZjhuQ02Gyqd&F2YiM-jV+Qy!;$rd|LSFk zhV9mwkPzG}CUgaqqs2B-S@e>4ZYXT3|7uPpV?Gf_zQ8TF7~n^gb_kfcD8_p#85=0F z6WH~yMNRMQ?OWA%k~Fj$TRN=~78n!cFg6B@aZw%Bl%Sh|a7!rnb9bo(O;w9iHD!?KPG1U9lNuP?i)e5QB8qd|Flw@Y zvh7pigd&ImNOeX>Kj)bVts{ks;Ox`OVh)g`-npDzKdzd-jRf@5KdkA1hBYPSP8#)7 z1zm@VtI1eHR8k_R0mTs*6+I>)W&V8ERMxnt3$v{Ib=RuMY#Yb@KOd3cQh@Z~VU6F% zrD!lbJxg~zdAKJyR7_D*YI`HOW}M~{MP#_tT-{r`tRNPE<5=G!4^i{uEKEB>oWd;} z{b9QT=2(mmO0KE5loGGTAZGKM$0txk6}2-7lA=;w3t*-v{42 zJ$zp`Kbt>qe}0%52OOu>61AnyDBU*aX5Ns51{GyajpduXoU zF}ITn#_UOW=S`1*r$pL@4EjhGf$>D;<(xFsHSM(X{CNvJC|G4nEH3tL1%5&X42m0_yj{3}EEj)bDL#Z?CT}RDov2_U5{t@q)Zb@#ecJCblBr>~K z2gKhB8UV-K4^TDnh$4(-JY)>v8IBuS4d)q7Mw@g&2311Z3i^&4Ttyn7@#J#2UCyaN}4(g2)zLWJ4h_{)QcU1Wg!hwVqDP~UReHbq1n7->1~ko(EQ%4 zIfiLPjKds@E^2Spc=^5mBEygH%CUEnv>P1C62KfsM%H`-sbqESvP(Iil3&YatWeNA z%LlnKaK^tWia$Aj#&Fkz6WD=SNp(rv1o+}n{9Q#p+$6ls@4R9~uMc73fMg)k(Y^Pc zkQj8gtF9nliA7&2fqa?Y-hlD4{qnTgcwBXz()u9aZHm#=WJkF2+13c{)uv7P019<^ zDC2r#^?7Fzl{9_KE12gtwH-l{g-&!9E5NZZK}#(pfIY_S zXB%FU3i4oJfB-f6UqN@emx0Nnmd=$J4U^T5Kw?cz<+gBa0_5BQ1r=QmZRyZKoFRWT zaz%Z5KT-PvxiQzt#h=MhoC!r)kkiz?daQ`lEql`)TBleFYjn3w$QYDRh*XU^Mp?ce zI%!TTU^{{6KzaaSO39hDPQ`LBVwB+0E2%O7T31EGwU0T2rp2XjdY9n0YDyjm1U$F= z4pXgN%zsoTjGX1JB{;>*8l33poulY4J$&IBd@1soA0a%?BuMUX413Wsc-0^W@MWwX zyr`NnajtwTzQGEpbnv|=@~1V$%t$oI)|SCm96&^ASq)m;riPRx614i|!W@)Cq=BP7g|Drog9xQ@oHLnUioW={Hlz7 zmRv|u%g`)30n)%iObVcyh2KgQHa$j@n8;xss!mzs-KH?Lws>K)J@PW{emm{Uy^2hU;e3^SLwy_Ad0n%6 z5J;Li-Y-A`*t*|!!%PssAkKNODV-u0eNZ7i-v`j+U_lmX|EyfqC<>xZV;Tj3!zi5J zZSdT)cUW{ur7WO7&!s1tk$6eDA#;gNwDSYM3cd!Kf*!l;!I|@iz7}s`+f$KP=<7)* z{rGXI5gI^aWF_C~4PAf3BJ5*8#~6p(Y+!uVoW~k#V1m2U{%m|>Af@Bvd!1@lrdUN( zbC!#I{%V7!@hIXoUo9spfKFaRE@a+MUUY6%AHHRK=PyA}$(WZVeb()>m`lJlFuB~0 zF8~K{Pfi1Hhu04E3J-g)MkmSX7cuK0J6GUcdCm_Fs7>xkmjcNa;P!a zo9H42ksn2+zDbWBfur9S1>gVCmard=ZW_;(<+fWM!T{po>PXA~IZpPx!}d<3#ocHj zxU21n&*+yJ({5tbL&~D6Q441a;BMwPxBuPM_E;}Uo*c&`4)ZnYjM z&`PK=0abG{gY#O*OXo?~6MeF0$5{y3DCu=W{~lPiMU!b5moI=r^Euwr0ffj0kRk^JnK|_fGby~4%|SrQ0FuA}N9G?8^u8GoN#?TQUb zV-HyvSe-0s8e{-mMm3{f*Gh7H@6Q@HE;vTHgv~}yMtZb;{6HRS7x--5^pdxG2}E?) z{o4XGN`q^HiuG7^qgH67I5qFM_sLz8ZrusX=0s;?cloS0-q0}#Ma@=zqTy!u>}BiT`_xj-Qc?^|h2w@+SdZD|GnOAO~m|gBq1TT$>T<11k6GZYW(k z^A3VbbcH99N@Eq4mRJY}7^0ZUSsMpcM>WAgt$saWh=m%tSu-}D++8SuT6DfPlPD3UsQC!Uo ziw#?F82D6Lb;FgN*UXRe!Qg9*`>hBT0ckQCSi@_P5^?n2;;C76Ns-0RdM*ow0*6xAtGeH(&yAFl(U} z->mZlASe7kalL*K<3IB&wt^r~)kgR56x26f>yLl=KkdXK|ue z=0PqKq>mZmVapc~4_;jq;p(?ETWo6YxF#$$jxMsn$k>n5dvU=|!c7T_oaRrVETpqd zI14h_boyA@yWFHoBFO+@Cq}wl{H{;qbJOCpp)!FQVf-^uUA{MWJ1wMC4-IGKXgyus zEcbGx2K6b4HQX8fKefK4OqwlaQK@O9!scY%1xOfX05I1sqy~Miw zb3%5&F3yRTkTg!kuIZdm8c&%i|L|zv-h$5hnjXHA?g$(ErruRtG}28d)#?aU=K*)L zNG0>qT<&7zb4=mKsaYZ>#F-Q7(4Y8X2m-f7kfmd6Z>`=KTk%yNH?_T&kv+K-!!Y$C zz|v7UXLLKMnr5QS!iSf!)|a=6O7dXAVOn|imrIzjV}PN<_2LG`ca8hevBV&i*BFnh zpEl>O=K0V~1c*T{xY`<$QkyVgoIA#m7eNx)O%pn;{=r^i_Owyu33fL2 z)j#yBER-u@LTev+_+M23Y{$$%d5<5Xv=Z6y*bCf4QM2@DvNPNFVgBgdY*G} z^@MnEAo*)Vz)nqvcHGP zY=jwohvS`^daKhMdhkj7L5CmWapj-~fWZc7cNT`51Z(T4t7vJ`{q#f4Ezz+$VaB;m zmD6aQw^{@i(|uBC(~n{yU>tJdr>kB;qmr^ei)t_yKSpz2Th5Q)qXz|tPTL1&%gnZE z;+aqbIcVtY&ZhmvvKgKT+BTMM>`ix+bf))qmTs8jA@eq<4qNolw@Ee5n%X<6`v>Gf zA(1~U#T1~Sdiq95Z8lahKTYqgp6TPdj99R?N@tT;V*3TVV&EvKB+Tk24~{v&{E}}t zQVr9{hyK13k+3tTQqpC+Q>qA@qjk;%X`qCbeWRA3P9sSOunL@8TKG7f$u z8Yq4rvtJrgwk;_L8AS~5BJ#Vy5jwq7lvHv2X3by{d_f%~$~J7!<#$|iI>>({>0CmA z)_lHBAqp`2>ZzbJj4&N0@ayWHe7k-)6bjK#?(U>8F1pF(5XMKsXzFgNHRFE^PDyY7u(6z5H1?Ph9x-;Q5<+Cf6c>3G{8*#02M>Qo z>hsSpgmULtv&H7%Xnl;e{`3=~ES*&t3=~WtuccrtXTlCVxf8#U)8Fsho&tWM?!#t# z!p@*-ZsAh2t#M}Pxa`-Eq?${Ki(Jw%w&p6LJ_p=wTDK!Jf|)ENhLh$ui)9sK3yR~wdDW4tXe!nl2*w-GOt)4-lgI0iJd-C#d`8Sn#I5Mg6o)+(mJ>9 z4UNG#h80RB6m5slGltE0l`^AgUA=8>3@D*+{*4*Zw!SaVhLxtQVx1y?$Q@SEc1rL8 z$BU@uR$7O-56K0*^$j5?et3xw~R*LH=GuFS4wEPGdV@E z)qO_xhU-lvPJqq8GtAWjv^0!dIx1+M2zjg-K@tWOshXM*L6SR(5F?_L^{A!@;0^t~ zF+tMlhCeP8Db`rBzk=aHT?!x)B&{Ya1I8eP!vE&@E984nKnjJ!aRb&GJVv4Q`33dG zj3@>64I6~)gGIh9g8ARf?&$-CBvwQzz^MGkCm>atdkpXiTu}V~z6LBaCHp^_{tEkb zxLE&d)DWh7LVyCWCBQtuBms&$_iey70ow(9J=^U(pC&Q^>Yd*4Ki9E>NH)6gUDb4o z;9s%A;5_nG{ko+Lk@ZGi75F`mDa73|oh%o1-8ecjPwp$r(=cw#jFSF?gsfU7%=p)^ms(l#)U$|E8(Ho>l0TZVPEZA{ zvx%qR6~8dbb@cm`Fgf~mh%+^H_~;$z7sA&B%J-7z0e@k}P-$V8PH9#APS$N_DTzfX ze%Hu)eF>4;qHPN*{hqbh$*>9UIOBj5lS2h(S>$bOvqEU9aoVv~3%9(!O72IQ;D&p9jt!w*fRBM=NwJPI{NSUpQgb@5mP~8AgN67U>YDj8$U4EEAqN zq|oBn-<&SII#2K(x{?5&VoI(B7N9H>X%}L!c(xwf7?V=O*dQZ5OUM3gt7hQ-1d3f^ zGcY8wi6Sm_be=9Hvx>V}K})AL?2_)a-|wk=<9L!Mm*Wb0L68Vm%~%TQv% z_o@$lZh>CeRAo#aldScKy-0W>A|~c#R{CW|YPJ9WRBIbw`YDU64d1XitX!6WN5^pZ z1twtuO$MbzJ@d#_OxgB(Lm0&3=+)Y6lB6;LOuAEh!4`W#*}l{D->e2#FFJEfTxgDL z6(dC;cUe-BO10BncJC7J7=e4r8&aG3cfGRD644ppsh`RHm_j~eyf1F>?nS7+&hFm+rQa|GKTVv2uHdou}6 zh@&@8{R_=FILZ)~!hFJn8KHZF_cKQ|$kxZgHG6TV6x+k;h-w%c*AGi&>$>rxnc^_F zr!%$@%sg5j{8J5t;k9ZWN%$Qk;ZZjEm zkKKLPIO6`Qm6856{0NHc#o<@_b`6+_pHcM98UwF6j`UnPNI`>!&V_0+@9+0ggO6AE z6-Fv@Aujjm(lz35RBiIa;;4L6Rz(ja0w>vJh$@C>9EzTm&#dFhXUkVr2ljr%8x%ey z0N!t*h9{%*23D(Z9%|U!SZXd1a7qOOIXj)=e`9eyIDGd0e<+&TSj<%%*TV5ymIS%y zc?_y?G0?at7YRtHGa@1wBz##Hs}%FG=avyncXJWKWX-$R`Kdj^n*~YUV50*y-Ssqv z(}WN1H?ysb7VcWuWaF+C1^5vmIAUWW*OL5iSyQ4uO!fGU>2w@^Mg$Hj(wU%oi6qHt zYuf13K!I-@We6V-qJVW%hP=F>@kk2$vY6mtSj%k30T0twpav6Oe6Gm;7RGNF;+LM% zIq(b6VlOBFQ_%KKtKOdN&m!tRH z#FC%hm*eO2)|v;$d8Bl{kKl~AtTwz#Rej(unYJ_`Dj+B%_3@j)KbjL3E@Be;bx?E> z2TUhNqGM((#2eiX)B{?LcXe+knz|QMi%(JcnduZjrzy<0-X#GZzBFM Te$)Y~H!|_Kl3_S!6EfiJV3? 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 @!Kc+HtlNTij??( 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®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