diff --git a/apis/visibility/openapi/zz_generated.openapi.go b/apis/visibility/openapi/zz_generated.openapi.go index c0599621e5..943faad307 100644 --- a/apis/visibility/openapi/zz_generated.openapi.go +++ b/apis/visibility/openapi/zz_generated.openapi.go @@ -88,6 +88,13 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "sigs.k8s.io/kueue/apis/visibility/v1alpha1.PendingWorkload": schema_kueue_apis_visibility_v1alpha1_PendingWorkload(ref), "sigs.k8s.io/kueue/apis/visibility/v1alpha1.PendingWorkloadOptions": schema_kueue_apis_visibility_v1alpha1_PendingWorkloadOptions(ref), "sigs.k8s.io/kueue/apis/visibility/v1alpha1.PendingWorkloadsSummary": schema_kueue_apis_visibility_v1alpha1_PendingWorkloadsSummary(ref), + "sigs.k8s.io/kueue/apis/visibility/v1beta1.ClusterQueue": schema_kueue_apis_visibility_v1beta1_ClusterQueue(ref), + "sigs.k8s.io/kueue/apis/visibility/v1beta1.ClusterQueueList": schema_kueue_apis_visibility_v1beta1_ClusterQueueList(ref), + "sigs.k8s.io/kueue/apis/visibility/v1beta1.LocalQueue": schema_kueue_apis_visibility_v1beta1_LocalQueue(ref), + "sigs.k8s.io/kueue/apis/visibility/v1beta1.LocalQueueList": schema_kueue_apis_visibility_v1beta1_LocalQueueList(ref), + "sigs.k8s.io/kueue/apis/visibility/v1beta1.PendingWorkload": schema_kueue_apis_visibility_v1beta1_PendingWorkload(ref), + "sigs.k8s.io/kueue/apis/visibility/v1beta1.PendingWorkloadOptions": schema_kueue_apis_visibility_v1beta1_PendingWorkloadOptions(ref), + "sigs.k8s.io/kueue/apis/visibility/v1beta1.PendingWorkloadsSummary": schema_kueue_apis_visibility_v1beta1_PendingWorkloadsSummary(ref), } } @@ -3003,3 +3010,327 @@ func schema_kueue_apis_visibility_v1alpha1_PendingWorkloadsSummary(ref common.Re "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta", "sigs.k8s.io/kueue/apis/visibility/v1alpha1.PendingWorkload"}, } } + +func schema_kueue_apis_visibility_v1beta1_ClusterQueue(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "pendingWorkloadsSummary": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("sigs.k8s.io/kueue/apis/visibility/v1beta1.PendingWorkloadsSummary"), + }, + }, + }, + Required: []string{"pendingWorkloadsSummary"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta", "sigs.k8s.io/kueue/apis/visibility/v1beta1.PendingWorkloadsSummary"}, + } +} + +func schema_kueue_apis_visibility_v1beta1_ClusterQueueList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("sigs.k8s.io/kueue/apis/visibility/v1beta1.ClusterQueue"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta", "sigs.k8s.io/kueue/apis/visibility/v1beta1.ClusterQueue"}, + } +} + +func schema_kueue_apis_visibility_v1beta1_LocalQueue(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "pendingWorkloadsSummary": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("sigs.k8s.io/kueue/apis/visibility/v1beta1.PendingWorkloadsSummary"), + }, + }, + }, + Required: []string{"pendingWorkloadsSummary"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta", "sigs.k8s.io/kueue/apis/visibility/v1beta1.PendingWorkloadsSummary"}, + } +} + +func schema_kueue_apis_visibility_v1beta1_LocalQueueList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("sigs.k8s.io/kueue/apis/visibility/v1beta1.LocalQueue"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta", "sigs.k8s.io/kueue/apis/visibility/v1beta1.LocalQueue"}, + } +} + +func schema_kueue_apis_visibility_v1beta1_PendingWorkload(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PendingWorkload is a user-facing representation of a pending workload that summarizes the relevant information for position in the cluster queue.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "priority": { + SchemaProps: spec.SchemaProps{ + Description: "Priority indicates the workload's priority", + Default: 0, + Type: []string{"integer"}, + Format: "int32", + }, + }, + "localQueueName": { + SchemaProps: spec.SchemaProps{ + Description: "LocalQueueName indicates the name of the LocalQueue the workload is submitted to", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "positionInClusterQueue": { + SchemaProps: spec.SchemaProps{ + Description: "PositionInClusterQueue indicates the workload's position in the ClusterQueue, starting from 0", + Default: 0, + Type: []string{"integer"}, + Format: "int32", + }, + }, + "positionInLocalQueue": { + SchemaProps: spec.SchemaProps{ + Description: "PositionInLocalQueue indicates the workload's position in the LocalQueue, starting from 0", + Default: 0, + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + Required: []string{"priority", "localQueueName", "positionInClusterQueue", "positionInLocalQueue"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_kueue_apis_visibility_v1beta1_PendingWorkloadOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PendingWorkloadOptions are query params used in the visibility queries", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "offset": { + SchemaProps: spec.SchemaProps{ + Description: "Offset indicates position of the first pending workload that should be fetched, starting from 0. 0 by default", + Default: 0, + Type: []string{"integer"}, + Format: "int64", + }, + }, + "limit": { + SchemaProps: spec.SchemaProps{ + Description: "Limit indicates max number of pending workloads that should be fetched. 1000 by default", + Type: []string{"integer"}, + Format: "int64", + }, + }, + }, + Required: []string{"offset"}, + }, + }, + } +} + +func schema_kueue_apis_visibility_v1beta1_PendingWorkloadsSummary(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PendingWorkloadsSummary contains a list of pending workloads in the context of the query (within LocalQueue or ClusterQueue).", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("sigs.k8s.io/kueue/apis/visibility/v1beta1.PendingWorkload"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta", "sigs.k8s.io/kueue/apis/visibility/v1beta1.PendingWorkload"}, + } +} diff --git a/apis/visibility/v1beta1/conversion_test.go b/apis/visibility/v1beta1/conversion_test.go new file mode 100644 index 0000000000..a9fec3d340 --- /dev/null +++ b/apis/visibility/v1beta1/conversion_test.go @@ -0,0 +1,93 @@ +/* +Copyright 2023 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 v1beta1 + +import ( + "net/url" + "testing" + + "github.com/google/go-cmp/cmp" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/diff" +) + +func TestPendingWorkloadsOptions(t *testing.T) { + scheme := runtime.NewScheme() + err := AddToScheme(scheme) + if err != nil { + t.Fatal(err) + } + codec := runtime.NewParameterCodec(scheme) + + cases := map[string]struct { + inputQueryParams url.Values + wantQueryParams url.Values + wantPendingWorkloadOptions PendingWorkloadOptions + }{ + "correct parameters": { + inputQueryParams: url.Values{ + "limit": {"1"}, + "offset": {"2"}, + }, + wantQueryParams: url.Values{ + "limit": {"1"}, + "offset": {"2"}, + }, + wantPendingWorkloadOptions: PendingWorkloadOptions{ + Limit: 1, + Offset: 2, + }, + }, + "default values": { + inputQueryParams: url.Values{ + "limit": {"0"}, + "offset": {"0"}, + }, + wantQueryParams: url.Values{ + "limit": {"1000"}, + "offset": {"0"}, + }, + wantPendingWorkloadOptions: PendingWorkloadOptions{ + Limit: 1000, + Offset: 0, + }, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + // versioned -> query params + actualParameters, err := codec.EncodeParameters(&tc.wantPendingWorkloadOptions, SchemeGroupVersion) + if err != nil { + t.Fatal(err) + } + if d := cmp.Diff(actualParameters, tc.wantQueryParams); d != "" { + t.Fatalf("Unexpected serialization:\n%s", diff.ObjectGoPrintSideBySide(tc.wantQueryParams, actualParameters)) + } + + // query params -> versioned + convertedPendingWorkloadOptions := PendingWorkloadOptions{} + err = codec.DecodeParameters(tc.inputQueryParams, SchemeGroupVersion, &convertedPendingWorkloadOptions) + if err != nil { + t.Fatal(err) + } + if d := cmp.Diff(convertedPendingWorkloadOptions, tc.wantPendingWorkloadOptions); d != "" { + t.Fatalf("Unexpected deserialization:\n%s", diff.ObjectGoPrintSideBySide(tc.wantPendingWorkloadOptions, convertedPendingWorkloadOptions)) + } + }) + } +} diff --git a/apis/visibility/v1beta1/defaults.go b/apis/visibility/v1beta1/defaults.go new file mode 100644 index 0000000000..2dfe0b9555 --- /dev/null +++ b/apis/visibility/v1beta1/defaults.go @@ -0,0 +1,37 @@ +/* +Copyright 2023 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 v1beta1 + +import ( + "k8s.io/apimachinery/pkg/runtime" +) + +func init() { + localSchemeBuilder.Register(addDefaultingFuncs) +} + +func addDefaultingFuncs(scheme *runtime.Scheme) error { + return RegisterDefaults(scheme) +} + +//nolint:revive // format required by generated code for defaulting +func SetDefaults_PendingWorkloadOptions(obj *PendingWorkloadOptions) { + defaultPendingWorkloadsLimit := int64(1000) + if obj.Limit == 0 { + obj.Limit = defaultPendingWorkloadsLimit + } +} diff --git a/apis/visibility/v1beta1/doc.go b/apis/visibility/v1beta1/doc.go new file mode 100644 index 0000000000..587f160223 --- /dev/null +++ b/apis/visibility/v1beta1/doc.go @@ -0,0 +1,23 @@ +/* +Copyright 2023 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. +*/ + +// +kubebuilder:object:generate=true +// +kubebuilder:skip +// +groupName=visibility.kueue.x-k8s.io +// +k8s:openapi-gen=true +// +k8s:conversion-gen=false + +package v1beta1 diff --git a/apis/visibility/v1beta1/groupversion_info.go b/apis/visibility/v1beta1/groupversion_info.go new file mode 100644 index 0000000000..1ca97c4c09 --- /dev/null +++ b/apis/visibility/v1beta1/groupversion_info.go @@ -0,0 +1,53 @@ +/* +Copyright 2023 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 v1beta1 contains API Schema definitions for the pending workloads kueue v1beta1 API group +// +kubebuilder:object:generate=true +// +kubebuilder:skip +// +groupName=visibility.kueue.x-k8s.io +// +k8s:openapi-gen=true +// +k8s:conversion-gen=false + +package v1beta1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects. + GroupVersion = schema.GroupVersion{Group: "visibility.kueue.x-k8s.io", Version: "v1beta1"} + + // SchemeGroupVersion is alias to GroupVersion for client-go libraries. + // It is required by pkg/client/informers/externalversions/... + SchemeGroupVersion = GroupVersion + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // localSchemeBuilder is used to register autogenerated conversion and defaults functions + // It is required by ./zz_generated.conversion.go and ./zz_generated.defaults.go + localSchemeBuilder = &SchemeBuilder.SchemeBuilder + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) + +// Resource is required by pkg/client/listers/... +func Resource(resource string) schema.GroupResource { + return GroupVersion.WithResource(resource).GroupResource() +} diff --git a/apis/visibility/v1beta1/types.go b/apis/visibility/v1beta1/types.go new file mode 100644 index 0000000000..7e6c7e5927 --- /dev/null +++ b/apis/visibility/v1beta1/types.go @@ -0,0 +1,113 @@ +/* +Copyright 2023 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 v1beta1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +genclient +// +kubebuilder:object:root=true +// +k8s:openapi-gen=true +// +genclient:nonNamespaced +// +genclient:method=GetPendingWorkloadsSummary,verb=get,subresource=pendingworkloads,result=sigs.k8s.io/kueue/apis/visibility/v1beta1.PendingWorkloadsSummary +type ClusterQueue struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Summary PendingWorkloadsSummary `json:"pendingWorkloadsSummary"` +} + +// +kubebuilder:object:root=true +type ClusterQueueList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + + Items []ClusterQueue `json:"items"` +} + +// +genclient +// +kubebuilder:object:root=true +// +k8s:openapi-gen=true +// +genclient:method=GetPendingWorkloadsSummary,verb=get,subresource=pendingworkloads,result=sigs.k8s.io/kueue/apis/visibility/v1beta1.PendingWorkloadsSummary +type LocalQueue struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Summary PendingWorkloadsSummary `json:"pendingWorkloadsSummary"` +} + +// +kubebuilder:object:root=true +type LocalQueueList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + + Items []LocalQueue `json:"items"` +} + +// PendingWorkload is a user-facing representation of a pending workload that summarizes the relevant information for +// position in the cluster queue. +type PendingWorkload struct { + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Priority indicates the workload's priority + Priority int32 `json:"priority"` + + // LocalQueueName indicates the name of the LocalQueue the workload is submitted to + LocalQueueName string `json:"localQueueName"` + + // PositionInClusterQueue indicates the workload's position in the ClusterQueue, starting from 0 + PositionInClusterQueue int32 `json:"positionInClusterQueue"` + + // PositionInLocalQueue indicates the workload's position in the LocalQueue, starting from 0 + PositionInLocalQueue int32 `json:"positionInLocalQueue"` +} + +// +k8s:openapi-gen=true +// +kubebuilder:object:root=true + +// PendingWorkloadsSummary contains a list of pending workloads in the context +// of the query (within LocalQueue or ClusterQueue). +type PendingWorkloadsSummary struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Items []PendingWorkload `json:"items"` +} + +// +kubebuilder:object:root=true +// +k8s:openapi-gen=true +// +k8s:conversion-gen:explicit-from=net/url.Values +// +k8s:defaulter-gen=true + +// PendingWorkloadOptions are query params used in the visibility queries +type PendingWorkloadOptions struct { + metav1.TypeMeta `json:",inline"` + + // Offset indicates position of the first pending workload that should be fetched, starting from 0. 0 by default + Offset int64 `json:"offset"` + + // Limit indicates max number of pending workloads that should be fetched. 1000 by default + Limit int64 `json:"limit,omitempty"` +} + +func init() { + SchemeBuilder.Register( + &PendingWorkloadsSummary{}, + &PendingWorkloadOptions{}, + ) +} diff --git a/apis/visibility/v1beta1/zz_generated.conversion.go b/apis/visibility/v1beta1/zz_generated.conversion.go new file mode 100644 index 0000000000..396ba67ec1 --- /dev/null +++ b/apis/visibility/v1beta1/zz_generated.conversion.go @@ -0,0 +1,68 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by conversion-gen. DO NOT EDIT. + +package v1beta1 + +import ( + url "net/url" + + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*url.Values)(nil), (*PendingWorkloadOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_url_Values_To_v1beta1_PendingWorkloadOptions(a.(*url.Values), b.(*PendingWorkloadOptions), scope) + }); err != nil { + return err + } + return nil +} + +func autoConvert_url_Values_To_v1beta1_PendingWorkloadOptions(in *url.Values, out *PendingWorkloadOptions, s conversion.Scope) error { + // WARNING: Field TypeMeta does not have json tag, skipping. + + if values, ok := map[string][]string(*in)["offset"]; ok && len(values) > 0 { + if err := runtime.Convert_Slice_string_To_int64(&values, &out.Offset, s); err != nil { + return err + } + } else { + out.Offset = 0 + } + if values, ok := map[string][]string(*in)["limit"]; ok && len(values) > 0 { + if err := runtime.Convert_Slice_string_To_int64(&values, &out.Limit, s); err != nil { + return err + } + } else { + out.Limit = 0 + } + return nil +} + +// Convert_url_Values_To_v1beta1_PendingWorkloadOptions is an autogenerated conversion function. +func Convert_url_Values_To_v1beta1_PendingWorkloadOptions(in *url.Values, out *PendingWorkloadOptions, s conversion.Scope) error { + return autoConvert_url_Values_To_v1beta1_PendingWorkloadOptions(in, out, s) +} diff --git a/apis/visibility/v1beta1/zz_generated.deepcopy.go b/apis/visibility/v1beta1/zz_generated.deepcopy.go new file mode 100644 index 0000000000..ae6d235718 --- /dev/null +++ b/apis/visibility/v1beta1/zz_generated.deepcopy.go @@ -0,0 +1,213 @@ +//go:build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1beta1 + +import ( + "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterQueue) DeepCopyInto(out *ClusterQueue) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Summary.DeepCopyInto(&out.Summary) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterQueue. +func (in *ClusterQueue) DeepCopy() *ClusterQueue { + if in == nil { + return nil + } + out := new(ClusterQueue) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterQueue) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterQueueList) DeepCopyInto(out *ClusterQueueList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ClusterQueue, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterQueueList. +func (in *ClusterQueueList) DeepCopy() *ClusterQueueList { + if in == nil { + return nil + } + out := new(ClusterQueueList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterQueueList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LocalQueue) DeepCopyInto(out *LocalQueue) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Summary.DeepCopyInto(&out.Summary) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LocalQueue. +func (in *LocalQueue) DeepCopy() *LocalQueue { + if in == nil { + return nil + } + out := new(LocalQueue) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *LocalQueue) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LocalQueueList) DeepCopyInto(out *LocalQueueList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]LocalQueue, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LocalQueueList. +func (in *LocalQueueList) DeepCopy() *LocalQueueList { + if in == nil { + return nil + } + out := new(LocalQueueList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *LocalQueueList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PendingWorkload) DeepCopyInto(out *PendingWorkload) { + *out = *in + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PendingWorkload. +func (in *PendingWorkload) DeepCopy() *PendingWorkload { + if in == nil { + return nil + } + out := new(PendingWorkload) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PendingWorkloadOptions) DeepCopyInto(out *PendingWorkloadOptions) { + *out = *in + out.TypeMeta = in.TypeMeta +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PendingWorkloadOptions. +func (in *PendingWorkloadOptions) DeepCopy() *PendingWorkloadOptions { + if in == nil { + return nil + } + out := new(PendingWorkloadOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PendingWorkloadOptions) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PendingWorkloadsSummary) DeepCopyInto(out *PendingWorkloadsSummary) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]PendingWorkload, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PendingWorkloadsSummary. +func (in *PendingWorkloadsSummary) DeepCopy() *PendingWorkloadsSummary { + if in == nil { + return nil + } + out := new(PendingWorkloadsSummary) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PendingWorkloadsSummary) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} diff --git a/apis/visibility/v1beta1/zz_generated.defaults.go b/apis/visibility/v1beta1/zz_generated.defaults.go new file mode 100644 index 0000000000..4c02fbaaff --- /dev/null +++ b/apis/visibility/v1beta1/zz_generated.defaults.go @@ -0,0 +1,37 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1beta1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + scheme.AddTypeDefaultingFunc(&PendingWorkloadOptions{}, func(obj interface{}) { SetObjectDefaults_PendingWorkloadOptions(obj.(*PendingWorkloadOptions)) }) + return nil +} + +func SetObjectDefaults_PendingWorkloadOptions(in *PendingWorkloadOptions) { + SetDefaults_PendingWorkloadOptions(in) +} diff --git a/charts/kueue/templates/visibility/apiservice_v1beta1.yaml b/charts/kueue/templates/visibility/apiservice_v1beta1.yaml new file mode 100644 index 0000000000..38ed65d332 --- /dev/null +++ b/charts/kueue/templates/visibility/apiservice_v1beta1.yaml @@ -0,0 +1,15 @@ +apiVersion: apiregistration.k8s.io/v1 +kind: APIService +metadata: + labels: + {{- include "kueue.labels" . | nindent 4 }} + name: v1beta1.visibility.kueue.x-k8s.io +spec: + group: visibility.kueue.x-k8s.io + groupPriorityMinimum: 100 + insecureSkipTLSVerify: true + service: + name: '{{ include "kueue.fullname" . }}-visibility-server' + namespace: '{{ .Release.Namespace }}' + version: v1beta1 + versionPriority: 100 diff --git a/client-go/applyconfiguration/utils.go b/client-go/applyconfiguration/utils.go index f7457c4086..89e2bd5ca5 100644 --- a/client-go/applyconfiguration/utils.go +++ b/client-go/applyconfiguration/utils.go @@ -24,10 +24,12 @@ import ( v1alpha1 "sigs.k8s.io/kueue/apis/kueue/v1alpha1" v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" visibilityv1alpha1 "sigs.k8s.io/kueue/apis/visibility/v1alpha1" + visibilityv1beta1 "sigs.k8s.io/kueue/apis/visibility/v1beta1" 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" + applyconfigurationvisibilityv1beta1 "sigs.k8s.io/kueue/client-go/applyconfiguration/visibility/v1beta1" ) // ForKind returns an apply configuration type for the given GroupVersionKind, or nil if no @@ -142,6 +144,16 @@ func ForKind(kind schema.GroupVersionKind) interface{} { case visibilityv1alpha1.SchemeGroupVersion.WithKind("PendingWorkloadsSummary"): return &applyconfigurationvisibilityv1alpha1.PendingWorkloadsSummaryApplyConfiguration{} + // Group=visibility.kueue.x-k8s.io, Version=v1beta1 + case visibilityv1beta1.SchemeGroupVersion.WithKind("ClusterQueue"): + return &applyconfigurationvisibilityv1beta1.ClusterQueueApplyConfiguration{} + case visibilityv1beta1.SchemeGroupVersion.WithKind("LocalQueue"): + return &applyconfigurationvisibilityv1beta1.LocalQueueApplyConfiguration{} + case visibilityv1beta1.SchemeGroupVersion.WithKind("PendingWorkload"): + return &applyconfigurationvisibilityv1beta1.PendingWorkloadApplyConfiguration{} + case visibilityv1beta1.SchemeGroupVersion.WithKind("PendingWorkloadsSummary"): + return &applyconfigurationvisibilityv1beta1.PendingWorkloadsSummaryApplyConfiguration{} + } return nil } diff --git a/client-go/applyconfiguration/visibility/v1beta1/clusterqueue.go b/client-go/applyconfiguration/visibility/v1beta1/clusterqueue.go new file mode 100644 index 0000000000..087a3eed14 --- /dev/null +++ b/client-go/applyconfiguration/visibility/v1beta1/clusterqueue.go @@ -0,0 +1,214 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1beta1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// ClusterQueueApplyConfiguration represents a declarative configuration of the ClusterQueue type for use +// with apply. +type ClusterQueueApplyConfiguration struct { + v1.TypeMetaApplyConfiguration `json:",inline"` + *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Summary *PendingWorkloadsSummaryApplyConfiguration `json:"pendingWorkloadsSummary,omitempty"` +} + +// ClusterQueue constructs a declarative configuration of the ClusterQueue type for use with +// apply. +func ClusterQueue(name string) *ClusterQueueApplyConfiguration { + b := &ClusterQueueApplyConfiguration{} + b.WithName(name) + b.WithKind("ClusterQueue") + b.WithAPIVersion("visibility.kueue.x-k8s.io/v1beta1") + return b +} + +// WithKind sets the Kind 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 Kind field is set to the value of the last call. +func (b *ClusterQueueApplyConfiguration) WithKind(value string) *ClusterQueueApplyConfiguration { + b.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion 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 APIVersion field is set to the value of the last call. +func (b *ClusterQueueApplyConfiguration) WithAPIVersion(value string) *ClusterQueueApplyConfiguration { + b.APIVersion = &value + return b +} + +// WithName sets the Name 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 Name field is set to the value of the last call. +func (b *ClusterQueueApplyConfiguration) WithName(value string) *ClusterQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.Name = &value + return b +} + +// WithGenerateName sets the GenerateName 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 GenerateName field is set to the value of the last call. +func (b *ClusterQueueApplyConfiguration) WithGenerateName(value string) *ClusterQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace 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 Namespace field is set to the value of the last call. +func (b *ClusterQueueApplyConfiguration) WithNamespace(value string) *ClusterQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.Namespace = &value + return b +} + +// WithUID sets the UID 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 UID field is set to the value of the last call. +func (b *ClusterQueueApplyConfiguration) WithUID(value types.UID) *ClusterQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion 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 ResourceVersion field is set to the value of the last call. +func (b *ClusterQueueApplyConfiguration) WithResourceVersion(value string) *ClusterQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation 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 Generation field is set to the value of the last call. +func (b *ClusterQueueApplyConfiguration) WithGeneration(value int64) *ClusterQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp 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 CreationTimestamp field is set to the value of the last call. +func (b *ClusterQueueApplyConfiguration) WithCreationTimestamp(value metav1.Time) *ClusterQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp 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 DeletionTimestamp field is set to the value of the last call. +func (b *ClusterQueueApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *ClusterQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds 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 DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *ClusterQueueApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *ClusterQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *ClusterQueueApplyConfiguration) WithLabels(entries map[string]string) *ClusterQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.Labels == nil && len(entries) > 0 { + b.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *ClusterQueueApplyConfiguration) WithAnnotations(entries map[string]string) *ClusterQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.Annotations == nil && len(entries) > 0 { + b.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences 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 OwnerReferences field. +func (b *ClusterQueueApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *ClusterQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.OwnerReferences = append(b.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers 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 Finalizers field. +func (b *ClusterQueueApplyConfiguration) WithFinalizers(values ...string) *ClusterQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.Finalizers = append(b.Finalizers, values[i]) + } + return b +} + +func (b *ClusterQueueApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{} + } +} + +// WithSummary sets the Summary 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 Summary field is set to the value of the last call. +func (b *ClusterQueueApplyConfiguration) WithSummary(value *PendingWorkloadsSummaryApplyConfiguration) *ClusterQueueApplyConfiguration { + 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/v1beta1/localqueue.go b/client-go/applyconfiguration/visibility/v1beta1/localqueue.go new file mode 100644 index 0000000000..9d7cb18735 --- /dev/null +++ b/client-go/applyconfiguration/visibility/v1beta1/localqueue.go @@ -0,0 +1,215 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1beta1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// LocalQueueApplyConfiguration represents a declarative configuration of the LocalQueue type for use +// with apply. +type LocalQueueApplyConfiguration struct { + v1.TypeMetaApplyConfiguration `json:",inline"` + *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Summary *PendingWorkloadsSummaryApplyConfiguration `json:"pendingWorkloadsSummary,omitempty"` +} + +// LocalQueue constructs a declarative configuration of the LocalQueue type for use with +// apply. +func LocalQueue(name, namespace string) *LocalQueueApplyConfiguration { + b := &LocalQueueApplyConfiguration{} + b.WithName(name) + b.WithNamespace(namespace) + b.WithKind("LocalQueue") + b.WithAPIVersion("visibility.kueue.x-k8s.io/v1beta1") + return b +} + +// WithKind sets the Kind 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 Kind field is set to the value of the last call. +func (b *LocalQueueApplyConfiguration) WithKind(value string) *LocalQueueApplyConfiguration { + b.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion 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 APIVersion field is set to the value of the last call. +func (b *LocalQueueApplyConfiguration) WithAPIVersion(value string) *LocalQueueApplyConfiguration { + b.APIVersion = &value + return b +} + +// WithName sets the Name 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 Name field is set to the value of the last call. +func (b *LocalQueueApplyConfiguration) WithName(value string) *LocalQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.Name = &value + return b +} + +// WithGenerateName sets the GenerateName 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 GenerateName field is set to the value of the last call. +func (b *LocalQueueApplyConfiguration) WithGenerateName(value string) *LocalQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace 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 Namespace field is set to the value of the last call. +func (b *LocalQueueApplyConfiguration) WithNamespace(value string) *LocalQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.Namespace = &value + return b +} + +// WithUID sets the UID 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 UID field is set to the value of the last call. +func (b *LocalQueueApplyConfiguration) WithUID(value types.UID) *LocalQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion 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 ResourceVersion field is set to the value of the last call. +func (b *LocalQueueApplyConfiguration) WithResourceVersion(value string) *LocalQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation 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 Generation field is set to the value of the last call. +func (b *LocalQueueApplyConfiguration) WithGeneration(value int64) *LocalQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp 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 CreationTimestamp field is set to the value of the last call. +func (b *LocalQueueApplyConfiguration) WithCreationTimestamp(value metav1.Time) *LocalQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp 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 DeletionTimestamp field is set to the value of the last call. +func (b *LocalQueueApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *LocalQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds 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 DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *LocalQueueApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *LocalQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *LocalQueueApplyConfiguration) WithLabels(entries map[string]string) *LocalQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.Labels == nil && len(entries) > 0 { + b.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *LocalQueueApplyConfiguration) WithAnnotations(entries map[string]string) *LocalQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.Annotations == nil && len(entries) > 0 { + b.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences 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 OwnerReferences field. +func (b *LocalQueueApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *LocalQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.OwnerReferences = append(b.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers 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 Finalizers field. +func (b *LocalQueueApplyConfiguration) WithFinalizers(values ...string) *LocalQueueApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.Finalizers = append(b.Finalizers, values[i]) + } + return b +} + +func (b *LocalQueueApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{} + } +} + +// WithSummary sets the Summary 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 Summary field is set to the value of the last call. +func (b *LocalQueueApplyConfiguration) WithSummary(value *PendingWorkloadsSummaryApplyConfiguration) *LocalQueueApplyConfiguration { + 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/v1beta1/pendingworkload.go b/client-go/applyconfiguration/visibility/v1beta1/pendingworkload.go new file mode 100644 index 0000000000..0ae8299c99 --- /dev/null +++ b/client-go/applyconfiguration/visibility/v1beta1/pendingworkload.go @@ -0,0 +1,220 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1beta1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// PendingWorkloadApplyConfiguration represents a declarative configuration of the PendingWorkload type for use +// with apply. +type PendingWorkloadApplyConfiguration struct { + *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Priority *int32 `json:"priority,omitempty"` + LocalQueueName *string `json:"localQueueName,omitempty"` + PositionInClusterQueue *int32 `json:"positionInClusterQueue,omitempty"` + PositionInLocalQueue *int32 `json:"positionInLocalQueue,omitempty"` +} + +// PendingWorkloadApplyConfiguration constructs a declarative configuration of the PendingWorkload type for use with +// apply. +func PendingWorkload() *PendingWorkloadApplyConfiguration { + return &PendingWorkloadApplyConfiguration{} +} + +// WithName sets the Name 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 Name field is set to the value of the last call. +func (b *PendingWorkloadApplyConfiguration) WithName(value string) *PendingWorkloadApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.Name = &value + return b +} + +// WithGenerateName sets the GenerateName 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 GenerateName field is set to the value of the last call. +func (b *PendingWorkloadApplyConfiguration) WithGenerateName(value string) *PendingWorkloadApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace 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 Namespace field is set to the value of the last call. +func (b *PendingWorkloadApplyConfiguration) WithNamespace(value string) *PendingWorkloadApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.Namespace = &value + return b +} + +// WithUID sets the UID 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 UID field is set to the value of the last call. +func (b *PendingWorkloadApplyConfiguration) WithUID(value types.UID) *PendingWorkloadApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion 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 ResourceVersion field is set to the value of the last call. +func (b *PendingWorkloadApplyConfiguration) WithResourceVersion(value string) *PendingWorkloadApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation 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 Generation field is set to the value of the last call. +func (b *PendingWorkloadApplyConfiguration) WithGeneration(value int64) *PendingWorkloadApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp 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 CreationTimestamp field is set to the value of the last call. +func (b *PendingWorkloadApplyConfiguration) WithCreationTimestamp(value metav1.Time) *PendingWorkloadApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp 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 DeletionTimestamp field is set to the value of the last call. +func (b *PendingWorkloadApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *PendingWorkloadApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds 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 DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *PendingWorkloadApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *PendingWorkloadApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *PendingWorkloadApplyConfiguration) WithLabels(entries map[string]string) *PendingWorkloadApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.Labels == nil && len(entries) > 0 { + b.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *PendingWorkloadApplyConfiguration) WithAnnotations(entries map[string]string) *PendingWorkloadApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.Annotations == nil && len(entries) > 0 { + b.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences 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 OwnerReferences field. +func (b *PendingWorkloadApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *PendingWorkloadApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.OwnerReferences = append(b.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers 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 Finalizers field. +func (b *PendingWorkloadApplyConfiguration) WithFinalizers(values ...string) *PendingWorkloadApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.Finalizers = append(b.Finalizers, values[i]) + } + return b +} + +func (b *PendingWorkloadApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{} + } +} + +// WithPriority sets the Priority 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 Priority field is set to the value of the last call. +func (b *PendingWorkloadApplyConfiguration) WithPriority(value int32) *PendingWorkloadApplyConfiguration { + b.Priority = &value + return b +} + +// WithLocalQueueName sets the LocalQueueName 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 LocalQueueName field is set to the value of the last call. +func (b *PendingWorkloadApplyConfiguration) WithLocalQueueName(value string) *PendingWorkloadApplyConfiguration { + b.LocalQueueName = &value + return b +} + +// WithPositionInClusterQueue sets the PositionInClusterQueue 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 PositionInClusterQueue field is set to the value of the last call. +func (b *PendingWorkloadApplyConfiguration) WithPositionInClusterQueue(value int32) *PendingWorkloadApplyConfiguration { + b.PositionInClusterQueue = &value + return b +} + +// WithPositionInLocalQueue sets the PositionInLocalQueue 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 PositionInLocalQueue field is set to the value of the last call. +func (b *PendingWorkloadApplyConfiguration) WithPositionInLocalQueue(value int32) *PendingWorkloadApplyConfiguration { + 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/v1beta1/pendingworkloadssummary.go b/client-go/applyconfiguration/visibility/v1beta1/pendingworkloadssummary.go new file mode 100644 index 0000000000..c1554dde29 --- /dev/null +++ b/client-go/applyconfiguration/visibility/v1beta1/pendingworkloadssummary.go @@ -0,0 +1,218 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1beta1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// PendingWorkloadsSummaryApplyConfiguration represents a declarative configuration of the PendingWorkloadsSummary type for use +// with apply. +type PendingWorkloadsSummaryApplyConfiguration struct { + v1.TypeMetaApplyConfiguration `json:",inline"` + *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Items []PendingWorkloadApplyConfiguration `json:"items,omitempty"` +} + +// PendingWorkloadsSummaryApplyConfiguration constructs a declarative configuration of the PendingWorkloadsSummary type for use with +// apply. +func PendingWorkloadsSummary() *PendingWorkloadsSummaryApplyConfiguration { + b := &PendingWorkloadsSummaryApplyConfiguration{} + b.WithKind("PendingWorkloadsSummary") + b.WithAPIVersion("visibility.kueue.x-k8s.io/v1beta1") + return b +} + +// WithKind sets the Kind 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 Kind field is set to the value of the last call. +func (b *PendingWorkloadsSummaryApplyConfiguration) WithKind(value string) *PendingWorkloadsSummaryApplyConfiguration { + b.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion 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 APIVersion field is set to the value of the last call. +func (b *PendingWorkloadsSummaryApplyConfiguration) WithAPIVersion(value string) *PendingWorkloadsSummaryApplyConfiguration { + b.APIVersion = &value + return b +} + +// WithName sets the Name 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 Name field is set to the value of the last call. +func (b *PendingWorkloadsSummaryApplyConfiguration) WithName(value string) *PendingWorkloadsSummaryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.Name = &value + return b +} + +// WithGenerateName sets the GenerateName 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 GenerateName field is set to the value of the last call. +func (b *PendingWorkloadsSummaryApplyConfiguration) WithGenerateName(value string) *PendingWorkloadsSummaryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace 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 Namespace field is set to the value of the last call. +func (b *PendingWorkloadsSummaryApplyConfiguration) WithNamespace(value string) *PendingWorkloadsSummaryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.Namespace = &value + return b +} + +// WithUID sets the UID 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 UID field is set to the value of the last call. +func (b *PendingWorkloadsSummaryApplyConfiguration) WithUID(value types.UID) *PendingWorkloadsSummaryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion 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 ResourceVersion field is set to the value of the last call. +func (b *PendingWorkloadsSummaryApplyConfiguration) WithResourceVersion(value string) *PendingWorkloadsSummaryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation 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 Generation field is set to the value of the last call. +func (b *PendingWorkloadsSummaryApplyConfiguration) WithGeneration(value int64) *PendingWorkloadsSummaryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp 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 CreationTimestamp field is set to the value of the last call. +func (b *PendingWorkloadsSummaryApplyConfiguration) WithCreationTimestamp(value metav1.Time) *PendingWorkloadsSummaryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp 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 DeletionTimestamp field is set to the value of the last call. +func (b *PendingWorkloadsSummaryApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *PendingWorkloadsSummaryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds 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 DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *PendingWorkloadsSummaryApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *PendingWorkloadsSummaryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *PendingWorkloadsSummaryApplyConfiguration) WithLabels(entries map[string]string) *PendingWorkloadsSummaryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.Labels == nil && len(entries) > 0 { + b.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *PendingWorkloadsSummaryApplyConfiguration) WithAnnotations(entries map[string]string) *PendingWorkloadsSummaryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.Annotations == nil && len(entries) > 0 { + b.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences 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 OwnerReferences field. +func (b *PendingWorkloadsSummaryApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *PendingWorkloadsSummaryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.OwnerReferences = append(b.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers 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 Finalizers field. +func (b *PendingWorkloadsSummaryApplyConfiguration) WithFinalizers(values ...string) *PendingWorkloadsSummaryApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.Finalizers = append(b.Finalizers, values[i]) + } + return b +} + +func (b *PendingWorkloadsSummaryApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{} + } +} + +// WithItems adds the given value to the Items 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 Items field. +func (b *PendingWorkloadsSummaryApplyConfiguration) WithItems(values ...*PendingWorkloadApplyConfiguration) *PendingWorkloadsSummaryApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithItems") + } + b.Items = append(b.Items, *values[i]) + } + 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/clientset.go b/client-go/clientset/versioned/clientset.go index 1511da7838..2f01cb1402 100644 --- a/client-go/clientset/versioned/clientset.go +++ b/client-go/clientset/versioned/clientset.go @@ -27,6 +27,7 @@ import ( kueuev1alpha1 "sigs.k8s.io/kueue/client-go/clientset/versioned/typed/kueue/v1alpha1" kueuev1beta1 "sigs.k8s.io/kueue/client-go/clientset/versioned/typed/kueue/v1beta1" visibilityv1alpha1 "sigs.k8s.io/kueue/client-go/clientset/versioned/typed/visibility/v1alpha1" + visibilityv1beta1 "sigs.k8s.io/kueue/client-go/clientset/versioned/typed/visibility/v1beta1" ) type Interface interface { @@ -34,6 +35,7 @@ type Interface interface { KueueV1alpha1() kueuev1alpha1.KueueV1alpha1Interface KueueV1beta1() kueuev1beta1.KueueV1beta1Interface VisibilityV1alpha1() visibilityv1alpha1.VisibilityV1alpha1Interface + VisibilityV1beta1() visibilityv1beta1.VisibilityV1beta1Interface } // Clientset contains the clients for groups. @@ -42,6 +44,7 @@ type Clientset struct { kueueV1alpha1 *kueuev1alpha1.KueueV1alpha1Client kueueV1beta1 *kueuev1beta1.KueueV1beta1Client visibilityV1alpha1 *visibilityv1alpha1.VisibilityV1alpha1Client + visibilityV1beta1 *visibilityv1beta1.VisibilityV1beta1Client } // KueueV1alpha1 retrieves the KueueV1alpha1Client @@ -59,6 +62,11 @@ func (c *Clientset) VisibilityV1alpha1() visibilityv1alpha1.VisibilityV1alpha1In return c.visibilityV1alpha1 } +// VisibilityV1beta1 retrieves the VisibilityV1beta1Client +func (c *Clientset) VisibilityV1beta1() visibilityv1beta1.VisibilityV1beta1Interface { + return c.visibilityV1beta1 +} + // Discovery retrieves the DiscoveryClient func (c *Clientset) Discovery() discovery.DiscoveryInterface { if c == nil { @@ -115,6 +123,10 @@ func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, if err != nil { return nil, err } + cs.visibilityV1beta1, err = visibilityv1beta1.NewForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient) if err != nil { @@ -139,6 +151,7 @@ func New(c rest.Interface) *Clientset { cs.kueueV1alpha1 = kueuev1alpha1.New(c) cs.kueueV1beta1 = kueuev1beta1.New(c) cs.visibilityV1alpha1 = visibilityv1alpha1.New(c) + cs.visibilityV1beta1 = visibilityv1beta1.New(c) cs.DiscoveryClient = discovery.NewDiscoveryClient(c) return &cs diff --git a/client-go/clientset/versioned/fake/clientset_generated.go b/client-go/clientset/versioned/fake/clientset_generated.go index 7a94d3d3ee..1e31ae2d6b 100644 --- a/client-go/clientset/versioned/fake/clientset_generated.go +++ b/client-go/clientset/versioned/fake/clientset_generated.go @@ -31,6 +31,8 @@ import ( fakekueuev1beta1 "sigs.k8s.io/kueue/client-go/clientset/versioned/typed/kueue/v1beta1/fake" visibilityv1alpha1 "sigs.k8s.io/kueue/client-go/clientset/versioned/typed/visibility/v1alpha1" fakevisibilityv1alpha1 "sigs.k8s.io/kueue/client-go/clientset/versioned/typed/visibility/v1alpha1/fake" + visibilityv1beta1 "sigs.k8s.io/kueue/client-go/clientset/versioned/typed/visibility/v1beta1" + fakevisibilityv1beta1 "sigs.k8s.io/kueue/client-go/clientset/versioned/typed/visibility/v1beta1/fake" ) // NewSimpleClientset returns a clientset that will respond with the provided objects. @@ -133,3 +135,8 @@ func (c *Clientset) KueueV1beta1() kueuev1beta1.KueueV1beta1Interface { func (c *Clientset) VisibilityV1alpha1() visibilityv1alpha1.VisibilityV1alpha1Interface { return &fakevisibilityv1alpha1.FakeVisibilityV1alpha1{Fake: &c.Fake} } + +// VisibilityV1beta1 retrieves the VisibilityV1beta1Client +func (c *Clientset) VisibilityV1beta1() visibilityv1beta1.VisibilityV1beta1Interface { + return &fakevisibilityv1beta1.FakeVisibilityV1beta1{Fake: &c.Fake} +} diff --git a/client-go/clientset/versioned/fake/register.go b/client-go/clientset/versioned/fake/register.go index 6df4d26714..3f13d30978 100644 --- a/client-go/clientset/versioned/fake/register.go +++ b/client-go/clientset/versioned/fake/register.go @@ -26,6 +26,7 @@ import ( kueuev1alpha1 "sigs.k8s.io/kueue/apis/kueue/v1alpha1" kueuev1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" visibilityv1alpha1 "sigs.k8s.io/kueue/apis/visibility/v1alpha1" + visibilityv1beta1 "sigs.k8s.io/kueue/apis/visibility/v1beta1" ) var scheme = runtime.NewScheme() @@ -35,6 +36,7 @@ var localSchemeBuilder = runtime.SchemeBuilder{ kueuev1alpha1.AddToScheme, kueuev1beta1.AddToScheme, visibilityv1alpha1.AddToScheme, + visibilityv1beta1.AddToScheme, } // AddToScheme adds all types of this clientset into the given scheme. This allows composition diff --git a/client-go/clientset/versioned/scheme/register.go b/client-go/clientset/versioned/scheme/register.go index c72c4376e1..d8b1d5036f 100644 --- a/client-go/clientset/versioned/scheme/register.go +++ b/client-go/clientset/versioned/scheme/register.go @@ -26,6 +26,7 @@ import ( kueuev1alpha1 "sigs.k8s.io/kueue/apis/kueue/v1alpha1" kueuev1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" visibilityv1alpha1 "sigs.k8s.io/kueue/apis/visibility/v1alpha1" + visibilityv1beta1 "sigs.k8s.io/kueue/apis/visibility/v1beta1" ) var Scheme = runtime.NewScheme() @@ -35,6 +36,7 @@ var localSchemeBuilder = runtime.SchemeBuilder{ kueuev1alpha1.AddToScheme, kueuev1beta1.AddToScheme, visibilityv1alpha1.AddToScheme, + visibilityv1beta1.AddToScheme, } // AddToScheme adds all types of this clientset into the given scheme. This allows composition diff --git a/client-go/clientset/versioned/typed/visibility/v1beta1/clusterqueue.go b/client-go/clientset/versioned/typed/visibility/v1beta1/clusterqueue.go new file mode 100644 index 0000000000..b39cec618c --- /dev/null +++ b/client-go/clientset/versioned/typed/visibility/v1beta1/clusterqueue.go @@ -0,0 +1,83 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by client-gen. DO NOT EDIT. + +package v1beta1 + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" + v1beta1 "sigs.k8s.io/kueue/apis/visibility/v1beta1" + visibilityv1beta1 "sigs.k8s.io/kueue/client-go/applyconfiguration/visibility/v1beta1" + scheme "sigs.k8s.io/kueue/client-go/clientset/versioned/scheme" +) + +// ClusterQueuesGetter has a method to return a ClusterQueueInterface. +// A group's client should implement this interface. +type ClusterQueuesGetter interface { + ClusterQueues() ClusterQueueInterface +} + +// ClusterQueueInterface has methods to work with ClusterQueue resources. +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) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1beta1.ClusterQueue, error) + List(ctx context.Context, opts v1.ListOptions) (*v1beta1.ClusterQueueList, error) + 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 *visibilityv1beta1.ClusterQueueApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.ClusterQueue, err error) + GetPendingWorkloadsSummary(ctx context.Context, clusterQueueName string, options v1.GetOptions) (*v1beta1.PendingWorkloadsSummary, error) + + ClusterQueueExpansion +} + +// clusterQueues implements ClusterQueueInterface +type clusterQueues struct { + *gentype.ClientWithListAndApply[*v1beta1.ClusterQueue, *v1beta1.ClusterQueueList, *visibilityv1beta1.ClusterQueueApplyConfiguration] +} + +// newClusterQueues returns a ClusterQueues +func newClusterQueues(c *VisibilityV1beta1Client) *clusterQueues { + return &clusterQueues{ + gentype.NewClientWithListAndApply[*v1beta1.ClusterQueue, *v1beta1.ClusterQueueList, *visibilityv1beta1.ClusterQueueApplyConfiguration]( + "clusterqueues", + c.RESTClient(), + scheme.ParameterCodec, + "", + func() *v1beta1.ClusterQueue { return &v1beta1.ClusterQueue{} }, + func() *v1beta1.ClusterQueueList { return &v1beta1.ClusterQueueList{} }), + } +} + +// GetPendingWorkloadsSummary takes name of the clusterQueue, and returns the corresponding v1beta1.PendingWorkloadsSummary object, and an error if there is any. +func (c *clusterQueues) GetPendingWorkloadsSummary(ctx context.Context, clusterQueueName string, options v1.GetOptions) (result *v1beta1.PendingWorkloadsSummary, err error) { + result = &v1beta1.PendingWorkloadsSummary{} + err = c.GetClient().Get(). + Resource("clusterqueues"). + Name(clusterQueueName). + SubResource("pendingworkloads"). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} diff --git a/client-go/clientset/versioned/typed/visibility/v1beta1/doc.go b/client-go/clientset/versioned/typed/visibility/v1beta1/doc.go new file mode 100644 index 0000000000..87e8d205a1 --- /dev/null +++ b/client-go/clientset/versioned/typed/visibility/v1beta1/doc.go @@ -0,0 +1,19 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1beta1 diff --git a/client-go/clientset/versioned/typed/visibility/v1beta1/fake/doc.go b/client-go/clientset/versioned/typed/visibility/v1beta1/fake/doc.go new file mode 100644 index 0000000000..3b00159259 --- /dev/null +++ b/client-go/clientset/versioned/typed/visibility/v1beta1/fake/doc.go @@ -0,0 +1,19 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/client-go/clientset/versioned/typed/visibility/v1beta1/fake/fake_clusterqueue.go b/client-go/clientset/versioned/typed/visibility/v1beta1/fake/fake_clusterqueue.go new file mode 100644 index 0000000000..2f9aefdc26 --- /dev/null +++ b/client-go/clientset/versioned/typed/visibility/v1beta1/fake/fake_clusterqueue.go @@ -0,0 +1,161 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1beta1 "sigs.k8s.io/kueue/apis/visibility/v1beta1" + visibilityv1beta1 "sigs.k8s.io/kueue/client-go/applyconfiguration/visibility/v1beta1" +) + +// FakeClusterQueues implements ClusterQueueInterface +type FakeClusterQueues struct { + Fake *FakeVisibilityV1beta1 +} + +var clusterqueuesResource = v1beta1.SchemeGroupVersion.WithResource("clusterqueues") + +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.NewRootGetActionWithOptions(clusterqueuesResource, name, options), emptyResult) + if obj == nil { + 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.NewRootListActionWithOptions(clusterqueuesResource, clusterqueuesKind, opts), emptyResult) + if obj == nil { + return emptyResult, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.ClusterQueueList{ListMeta: obj.(*v1beta1.ClusterQueueList).ListMeta} + for _, item := range obj.(*v1beta1.ClusterQueueList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// 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.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.NewRootCreateActionWithOptions(clusterqueuesResource, clusterQueue, opts), emptyResult) + if obj == nil { + 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.NewRootUpdateActionWithOptions(clusterqueuesResource, clusterQueue, opts), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1beta1.ClusterQueue), err +} + +// Delete takes name of the clusterQueue and deletes it. Returns an error if one occurs. +func (c *FakeClusterQueues) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(clusterqueuesResource, name, opts), &v1beta1.ClusterQueue{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeClusterQueues) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionActionWithOptions(clusterqueuesResource, opts, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.ClusterQueueList{}) + return err +} + +// 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.NewRootPatchSubresourceActionWithOptions(clusterqueuesResource, name, pt, data, opts, subresources...), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1beta1.ClusterQueue), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied clusterQueue. +func (c *FakeClusterQueues) Apply(ctx context.Context, clusterQueue *visibilityv1beta1.ClusterQueueApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.ClusterQueue, err error) { + if clusterQueue == nil { + return nil, fmt.Errorf("clusterQueue provided to Apply must not be nil") + } + 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") + } + emptyResult := &v1beta1.ClusterQueue{} + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceActionWithOptions(clusterqueuesResource, *name, types.ApplyPatchType, data, opts.ToPatchOptions()), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1beta1.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 *v1beta1.PendingWorkloadsSummary, err error) { + emptyResult := &v1beta1.PendingWorkloadsSummary{} + obj, err := c.Fake. + Invokes(testing.NewRootGetSubresourceActionWithOptions(clusterqueuesResource, "pendingworkloads", clusterQueueName, options), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1beta1.PendingWorkloadsSummary), err +} diff --git a/client-go/clientset/versioned/typed/visibility/v1beta1/fake/fake_localqueue.go b/client-go/clientset/versioned/typed/visibility/v1beta1/fake/fake_localqueue.go new file mode 100644 index 0000000000..e8e64cbbd3 --- /dev/null +++ b/client-go/clientset/versioned/typed/visibility/v1beta1/fake/fake_localqueue.go @@ -0,0 +1,171 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1beta1 "sigs.k8s.io/kueue/apis/visibility/v1beta1" + visibilityv1beta1 "sigs.k8s.io/kueue/client-go/applyconfiguration/visibility/v1beta1" +) + +// FakeLocalQueues implements LocalQueueInterface +type FakeLocalQueues struct { + Fake *FakeVisibilityV1beta1 + ns string +} + +var localqueuesResource = v1beta1.SchemeGroupVersion.WithResource("localqueues") + +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.NewGetActionWithOptions(localqueuesResource, c.ns, name, options), emptyResult) + + if obj == nil { + 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.NewListActionWithOptions(localqueuesResource, localqueuesKind, c.ns, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.LocalQueueList{ListMeta: obj.(*v1beta1.LocalQueueList).ListMeta} + for _, item := range obj.(*v1beta1.LocalQueueList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// 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.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.NewCreateActionWithOptions(localqueuesResource, c.ns, localQueue, opts), emptyResult) + + if obj == nil { + 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.NewUpdateActionWithOptions(localqueuesResource, c.ns, localQueue, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1beta1.LocalQueue), err +} + +// Delete takes name of the localQueue and deletes it. Returns an error if one occurs. +func (c *FakeLocalQueues) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(localqueuesResource, c.ns, name, opts), &v1beta1.LocalQueue{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeLocalQueues) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionActionWithOptions(localqueuesResource, c.ns, opts, listOpts) + + _, err := c.Fake.Invokes(action, &v1beta1.LocalQueueList{}) + return err +} + +// 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.NewPatchSubresourceActionWithOptions(localqueuesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1beta1.LocalQueue), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied localQueue. +func (c *FakeLocalQueues) Apply(ctx context.Context, localQueue *visibilityv1beta1.LocalQueueApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.LocalQueue, err error) { + if localQueue == nil { + return nil, fmt.Errorf("localQueue provided to Apply must not be nil") + } + 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") + } + emptyResult := &v1beta1.LocalQueue{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(localqueuesResource, c.ns, *name, types.ApplyPatchType, data, opts.ToPatchOptions()), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1beta1.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 *v1beta1.PendingWorkloadsSummary, err error) { + emptyResult := &v1beta1.PendingWorkloadsSummary{} + obj, err := c.Fake. + Invokes(testing.NewGetSubresourceActionWithOptions(localqueuesResource, c.ns, "pendingworkloads", localQueueName, options), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1beta1.PendingWorkloadsSummary), err +} diff --git a/client-go/clientset/versioned/typed/visibility/v1beta1/fake/fake_visibility_client.go b/client-go/clientset/versioned/typed/visibility/v1beta1/fake/fake_visibility_client.go new file mode 100644 index 0000000000..c0c020ad3c --- /dev/null +++ b/client-go/clientset/versioned/typed/visibility/v1beta1/fake/fake_visibility_client.go @@ -0,0 +1,43 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1beta1 "sigs.k8s.io/kueue/client-go/clientset/versioned/typed/visibility/v1beta1" +) + +type FakeVisibilityV1beta1 struct { + *testing.Fake +} + +func (c *FakeVisibilityV1beta1) ClusterQueues() v1beta1.ClusterQueueInterface { + return &FakeClusterQueues{c} +} + +func (c *FakeVisibilityV1beta1) LocalQueues(namespace string) v1beta1.LocalQueueInterface { + return &FakeLocalQueues{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeVisibilityV1beta1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/client-go/clientset/versioned/typed/visibility/v1beta1/generated_expansion.go b/client-go/clientset/versioned/typed/visibility/v1beta1/generated_expansion.go new file mode 100644 index 0000000000..26e84b21ec --- /dev/null +++ b/client-go/clientset/versioned/typed/visibility/v1beta1/generated_expansion.go @@ -0,0 +1,22 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by client-gen. DO NOT EDIT. + +package v1beta1 + +type ClusterQueueExpansion interface{} + +type LocalQueueExpansion interface{} diff --git a/client-go/clientset/versioned/typed/visibility/v1beta1/localqueue.go b/client-go/clientset/versioned/typed/visibility/v1beta1/localqueue.go new file mode 100644 index 0000000000..02ccffc9f9 --- /dev/null +++ b/client-go/clientset/versioned/typed/visibility/v1beta1/localqueue.go @@ -0,0 +1,84 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by client-gen. DO NOT EDIT. + +package v1beta1 + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" + v1beta1 "sigs.k8s.io/kueue/apis/visibility/v1beta1" + visibilityv1beta1 "sigs.k8s.io/kueue/client-go/applyconfiguration/visibility/v1beta1" + scheme "sigs.k8s.io/kueue/client-go/clientset/versioned/scheme" +) + +// LocalQueuesGetter has a method to return a LocalQueueInterface. +// A group's client should implement this interface. +type LocalQueuesGetter interface { + LocalQueues(namespace string) LocalQueueInterface +} + +// LocalQueueInterface has methods to work with LocalQueue resources. +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) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1beta1.LocalQueue, error) + List(ctx context.Context, opts v1.ListOptions) (*v1beta1.LocalQueueList, error) + 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 *visibilityv1beta1.LocalQueueApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.LocalQueue, err error) + GetPendingWorkloadsSummary(ctx context.Context, localQueueName string, options v1.GetOptions) (*v1beta1.PendingWorkloadsSummary, error) + + LocalQueueExpansion +} + +// localQueues implements LocalQueueInterface +type localQueues struct { + *gentype.ClientWithListAndApply[*v1beta1.LocalQueue, *v1beta1.LocalQueueList, *visibilityv1beta1.LocalQueueApplyConfiguration] +} + +// newLocalQueues returns a LocalQueues +func newLocalQueues(c *VisibilityV1beta1Client, namespace string) *localQueues { + return &localQueues{ + gentype.NewClientWithListAndApply[*v1beta1.LocalQueue, *v1beta1.LocalQueueList, *visibilityv1beta1.LocalQueueApplyConfiguration]( + "localqueues", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *v1beta1.LocalQueue { return &v1beta1.LocalQueue{} }, + func() *v1beta1.LocalQueueList { return &v1beta1.LocalQueueList{} }), + } +} + +// GetPendingWorkloadsSummary takes name of the localQueue, and returns the corresponding v1beta1.PendingWorkloadsSummary object, and an error if there is any. +func (c *localQueues) GetPendingWorkloadsSummary(ctx context.Context, localQueueName string, options v1.GetOptions) (result *v1beta1.PendingWorkloadsSummary, err error) { + result = &v1beta1.PendingWorkloadsSummary{} + err = c.GetClient().Get(). + Namespace(c.GetNamespace()). + Resource("localqueues"). + Name(localQueueName). + SubResource("pendingworkloads"). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} diff --git a/client-go/clientset/versioned/typed/visibility/v1beta1/visibility_client.go b/client-go/clientset/versioned/typed/visibility/v1beta1/visibility_client.go new file mode 100644 index 0000000000..d606438e9a --- /dev/null +++ b/client-go/clientset/versioned/typed/visibility/v1beta1/visibility_client.go @@ -0,0 +1,111 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by client-gen. DO NOT EDIT. + +package v1beta1 + +import ( + "net/http" + + rest "k8s.io/client-go/rest" + v1beta1 "sigs.k8s.io/kueue/apis/visibility/v1beta1" + "sigs.k8s.io/kueue/client-go/clientset/versioned/scheme" +) + +type VisibilityV1beta1Interface interface { + RESTClient() rest.Interface + ClusterQueuesGetter + LocalQueuesGetter +} + +// VisibilityV1beta1Client is used to interact with features provided by the visibility.kueue.x-k8s.io group. +type VisibilityV1beta1Client struct { + restClient rest.Interface +} + +func (c *VisibilityV1beta1Client) ClusterQueues() ClusterQueueInterface { + return newClusterQueues(c) +} + +func (c *VisibilityV1beta1Client) LocalQueues(namespace string) LocalQueueInterface { + return newLocalQueues(c, namespace) +} + +// NewForConfig creates a new VisibilityV1beta1Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*VisibilityV1beta1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new VisibilityV1beta1Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*VisibilityV1beta1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) + if err != nil { + return nil, err + } + return &VisibilityV1beta1Client{client}, nil +} + +// NewForConfigOrDie creates a new VisibilityV1beta1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *VisibilityV1beta1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new VisibilityV1beta1Client for the given RESTClient. +func New(c rest.Interface) *VisibilityV1beta1Client { + return &VisibilityV1beta1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1beta1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *VisibilityV1beta1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/client-go/informers/externalversions/generic.go b/client-go/informers/externalversions/generic.go index 20debdeb89..c12c4c4879 100644 --- a/client-go/informers/externalversions/generic.go +++ b/client-go/informers/externalversions/generic.go @@ -25,6 +25,7 @@ import ( v1alpha1 "sigs.k8s.io/kueue/apis/kueue/v1alpha1" v1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1" visibilityv1alpha1 "sigs.k8s.io/kueue/apis/visibility/v1alpha1" + visibilityv1beta1 "sigs.k8s.io/kueue/apis/visibility/v1beta1" ) // GenericInformer is type of SharedIndexInformer which will locate and delegate to other @@ -81,6 +82,12 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource case visibilityv1alpha1.SchemeGroupVersion.WithResource("localqueues"): return &genericInformer{resource: resource.GroupResource(), informer: f.Visibility().V1alpha1().LocalQueues().Informer()}, nil + // Group=visibility.kueue.x-k8s.io, Version=v1beta1 + case visibilityv1beta1.SchemeGroupVersion.WithResource("clusterqueues"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Visibility().V1beta1().ClusterQueues().Informer()}, nil + case visibilityv1beta1.SchemeGroupVersion.WithResource("localqueues"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Visibility().V1beta1().LocalQueues().Informer()}, nil + } return nil, fmt.Errorf("no informer found for %v", resource) diff --git a/client-go/informers/externalversions/visibility/interface.go b/client-go/informers/externalversions/visibility/interface.go index a7179d892b..7b8442f891 100644 --- a/client-go/informers/externalversions/visibility/interface.go +++ b/client-go/informers/externalversions/visibility/interface.go @@ -20,12 +20,15 @@ package visibility import ( internalinterfaces "sigs.k8s.io/kueue/client-go/informers/externalversions/internalinterfaces" v1alpha1 "sigs.k8s.io/kueue/client-go/informers/externalversions/visibility/v1alpha1" + v1beta1 "sigs.k8s.io/kueue/client-go/informers/externalversions/visibility/v1beta1" ) // Interface provides access to each of this group's versions. type Interface interface { // V1alpha1 provides access to shared informers for resources in V1alpha1. V1alpha1() v1alpha1.Interface + // V1beta1 provides access to shared informers for resources in V1beta1. + V1beta1() v1beta1.Interface } type group struct { @@ -43,3 +46,8 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList func (g *group) V1alpha1() v1alpha1.Interface { return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions) } + +// V1beta1 returns a new v1beta1.Interface. +func (g *group) V1beta1() v1beta1.Interface { + return v1beta1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/client-go/informers/externalversions/visibility/v1beta1/clusterqueue.go b/client-go/informers/externalversions/visibility/v1beta1/clusterqueue.go new file mode 100644 index 0000000000..e0d445d35f --- /dev/null +++ b/client-go/informers/externalversions/visibility/v1beta1/clusterqueue.go @@ -0,0 +1,88 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by informer-gen. DO NOT EDIT. + +package v1beta1 + +import ( + "context" + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + visibilityv1beta1 "sigs.k8s.io/kueue/apis/visibility/v1beta1" + versioned "sigs.k8s.io/kueue/client-go/clientset/versioned" + internalinterfaces "sigs.k8s.io/kueue/client-go/informers/externalversions/internalinterfaces" + v1beta1 "sigs.k8s.io/kueue/client-go/listers/visibility/v1beta1" +) + +// ClusterQueueInformer provides access to a shared informer and lister for +// ClusterQueues. +type ClusterQueueInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1beta1.ClusterQueueLister +} + +type clusterQueueInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewClusterQueueInformer constructs a new informer for ClusterQueue type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewClusterQueueInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredClusterQueueInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredClusterQueueInformer constructs a new informer for ClusterQueue type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredClusterQueueInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.VisibilityV1beta1().ClusterQueues().List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.VisibilityV1beta1().ClusterQueues().Watch(context.TODO(), options) + }, + }, + &visibilityv1beta1.ClusterQueue{}, + resyncPeriod, + indexers, + ) +} + +func (f *clusterQueueInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredClusterQueueInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *clusterQueueInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&visibilityv1beta1.ClusterQueue{}, f.defaultInformer) +} + +func (f *clusterQueueInformer) Lister() v1beta1.ClusterQueueLister { + return v1beta1.NewClusterQueueLister(f.Informer().GetIndexer()) +} diff --git a/client-go/informers/externalversions/visibility/v1beta1/interface.go b/client-go/informers/externalversions/visibility/v1beta1/interface.go new file mode 100644 index 0000000000..7be28f5dd5 --- /dev/null +++ b/client-go/informers/externalversions/visibility/v1beta1/interface.go @@ -0,0 +1,51 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by informer-gen. DO NOT EDIT. + +package v1beta1 + +import ( + internalinterfaces "sigs.k8s.io/kueue/client-go/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // ClusterQueues returns a ClusterQueueInformer. + ClusterQueues() ClusterQueueInformer + // LocalQueues returns a LocalQueueInformer. + LocalQueues() LocalQueueInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// ClusterQueues returns a ClusterQueueInformer. +func (v *version) ClusterQueues() ClusterQueueInformer { + return &clusterQueueInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + +// LocalQueues returns a LocalQueueInformer. +func (v *version) LocalQueues() LocalQueueInformer { + return &localQueueInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/client-go/informers/externalversions/visibility/v1beta1/localqueue.go b/client-go/informers/externalversions/visibility/v1beta1/localqueue.go new file mode 100644 index 0000000000..c991a90802 --- /dev/null +++ b/client-go/informers/externalversions/visibility/v1beta1/localqueue.go @@ -0,0 +1,89 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by informer-gen. DO NOT EDIT. + +package v1beta1 + +import ( + "context" + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + visibilityv1beta1 "sigs.k8s.io/kueue/apis/visibility/v1beta1" + versioned "sigs.k8s.io/kueue/client-go/clientset/versioned" + internalinterfaces "sigs.k8s.io/kueue/client-go/informers/externalversions/internalinterfaces" + v1beta1 "sigs.k8s.io/kueue/client-go/listers/visibility/v1beta1" +) + +// LocalQueueInformer provides access to a shared informer and lister for +// LocalQueues. +type LocalQueueInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1beta1.LocalQueueLister +} + +type localQueueInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewLocalQueueInformer constructs a new informer for LocalQueue type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewLocalQueueInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredLocalQueueInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredLocalQueueInformer constructs a new informer for LocalQueue type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredLocalQueueInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.VisibilityV1beta1().LocalQueues(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.VisibilityV1beta1().LocalQueues(namespace).Watch(context.TODO(), options) + }, + }, + &visibilityv1beta1.LocalQueue{}, + resyncPeriod, + indexers, + ) +} + +func (f *localQueueInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredLocalQueueInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *localQueueInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&visibilityv1beta1.LocalQueue{}, f.defaultInformer) +} + +func (f *localQueueInformer) Lister() v1beta1.LocalQueueLister { + return v1beta1.NewLocalQueueLister(f.Informer().GetIndexer()) +} diff --git a/client-go/listers/visibility/v1beta1/clusterqueue.go b/client-go/listers/visibility/v1beta1/clusterqueue.go new file mode 100644 index 0000000000..de16fa1c25 --- /dev/null +++ b/client-go/listers/visibility/v1beta1/clusterqueue.go @@ -0,0 +1,47 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by lister-gen. DO NOT EDIT. + +package v1beta1 + +import ( + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/listers" + "k8s.io/client-go/tools/cache" + v1beta1 "sigs.k8s.io/kueue/apis/visibility/v1beta1" +) + +// ClusterQueueLister helps list ClusterQueues. +// All objects returned here must be treated as read-only. +type ClusterQueueLister interface { + // List lists all ClusterQueues in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1beta1.ClusterQueue, err error) + // Get retrieves the ClusterQueue from the index for a given name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1beta1.ClusterQueue, error) + ClusterQueueListerExpansion +} + +// clusterQueueLister implements the ClusterQueueLister interface. +type clusterQueueLister struct { + listers.ResourceIndexer[*v1beta1.ClusterQueue] +} + +// NewClusterQueueLister returns a new ClusterQueueLister. +func NewClusterQueueLister(indexer cache.Indexer) ClusterQueueLister { + return &clusterQueueLister{listers.New[*v1beta1.ClusterQueue](indexer, v1beta1.Resource("clusterqueue"))} +} diff --git a/client-go/listers/visibility/v1beta1/expansion_generated.go b/client-go/listers/visibility/v1beta1/expansion_generated.go new file mode 100644 index 0000000000..c53049a1cf --- /dev/null +++ b/client-go/listers/visibility/v1beta1/expansion_generated.go @@ -0,0 +1,30 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by lister-gen. DO NOT EDIT. + +package v1beta1 + +// ClusterQueueListerExpansion allows custom methods to be added to +// ClusterQueueLister. +type ClusterQueueListerExpansion interface{} + +// LocalQueueListerExpansion allows custom methods to be added to +// LocalQueueLister. +type LocalQueueListerExpansion interface{} + +// LocalQueueNamespaceListerExpansion allows custom methods to be added to +// LocalQueueNamespaceLister. +type LocalQueueNamespaceListerExpansion interface{} diff --git a/client-go/listers/visibility/v1beta1/localqueue.go b/client-go/listers/visibility/v1beta1/localqueue.go new file mode 100644 index 0000000000..01319fb93a --- /dev/null +++ b/client-go/listers/visibility/v1beta1/localqueue.go @@ -0,0 +1,69 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by lister-gen. DO NOT EDIT. + +package v1beta1 + +import ( + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/listers" + "k8s.io/client-go/tools/cache" + v1beta1 "sigs.k8s.io/kueue/apis/visibility/v1beta1" +) + +// LocalQueueLister helps list LocalQueues. +// All objects returned here must be treated as read-only. +type LocalQueueLister interface { + // List lists all LocalQueues in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1beta1.LocalQueue, err error) + // LocalQueues returns an object that can list and get LocalQueues. + LocalQueues(namespace string) LocalQueueNamespaceLister + LocalQueueListerExpansion +} + +// localQueueLister implements the LocalQueueLister interface. +type localQueueLister struct { + listers.ResourceIndexer[*v1beta1.LocalQueue] +} + +// NewLocalQueueLister returns a new LocalQueueLister. +func NewLocalQueueLister(indexer cache.Indexer) LocalQueueLister { + 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{listers.NewNamespaced[*v1beta1.LocalQueue](s.ResourceIndexer, namespace)} +} + +// LocalQueueNamespaceLister helps list and get LocalQueues. +// All objects returned here must be treated as read-only. +type LocalQueueNamespaceLister interface { + // List lists all LocalQueues in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1beta1.LocalQueue, err error) + // Get retrieves the LocalQueue from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1beta1.LocalQueue, error) + LocalQueueNamespaceListerExpansion +} + +// localQueueNamespaceLister implements the LocalQueueNamespaceLister +// interface. +type localQueueNamespaceLister struct { + listers.ResourceIndexer[*v1beta1.LocalQueue] +} diff --git a/cmd/kueuectl/app/list/list_workload.go b/cmd/kueuectl/app/list/list_workload.go index 489c6c68a8..5088e186e8 100644 --- a/cmd/kueuectl/app/list/list_workload.go +++ b/cmd/kueuectl/app/list/list_workload.go @@ -35,7 +35,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/kueue/apis/kueue/v1beta1" - "sigs.k8s.io/kueue/apis/visibility/v1alpha1" + visibility "sigs.k8s.io/kueue/apis/visibility/v1beta1" clientset "sigs.k8s.io/kueue/client-go/clientset/versioned" "sigs.k8s.io/kueue/client-go/clientset/versioned/scheme" "sigs.k8s.io/kueue/cmd/kueuectl/app/completion" @@ -427,11 +427,11 @@ func (o *WorkloadOptions) localQueues(ctx context.Context, list *v1beta1.Workloa return localQueues, nil } -func (o *WorkloadOptions) pendingWorkloads(ctx context.Context, list *v1beta1.WorkloadList, localQueues map[string]*v1beta1.LocalQueue) (map[string]*v1alpha1.PendingWorkload, error) { +func (o *WorkloadOptions) pendingWorkloads(ctx context.Context, list *v1beta1.WorkloadList, localQueues map[string]*v1beta1.LocalQueue) (map[string]*visibility.PendingWorkload, error) { var err error - pendingWorkloads := make(map[string]*v1alpha1.PendingWorkload) - pendingWorkloadsSummaries := make(map[string]*v1alpha1.PendingWorkloadsSummary) + pendingWorkloads := make(map[string]*visibility.PendingWorkload) + pendingWorkloadsSummaries := make(map[string]*visibility.PendingWorkloadsSummary) for _, wl := range list.Items { if !workloadPending(&wl) { @@ -448,7 +448,7 @@ func (o *WorkloadOptions) pendingWorkloads(ctx context.Context, list *v1beta1.Wo } pendingWorkloadsSummary, ok := pendingWorkloadsSummaries[clusterQueueName] if !ok { - pendingWorkloadsSummary, err = o.ClientSet.VisibilityV1alpha1().ClusterQueues(). + pendingWorkloadsSummary, err = o.ClientSet.VisibilityV1beta1().ClusterQueues(). GetPendingWorkloadsSummary(ctx, clusterQueueName, metav1.GetOptions{}) if client.IgnoreNotFound(err) != nil { return nil, err diff --git a/cmd/kueuectl/app/list/list_workload_printer.go b/cmd/kueuectl/app/list/list_workload_printer.go index f550b82f31..c7e0b4c6ee 100644 --- a/cmd/kueuectl/app/list/list_workload_printer.go +++ b/cmd/kueuectl/app/list/list_workload_printer.go @@ -31,7 +31,7 @@ import ( "k8s.io/utils/clock" "sigs.k8s.io/kueue/apis/kueue/v1beta1" - "sigs.k8s.io/kueue/apis/visibility/v1alpha1" + visibility "sigs.k8s.io/kueue/apis/visibility/v1beta1" "sigs.k8s.io/kueue/pkg/workload" ) @@ -39,14 +39,14 @@ const crdTypeMaxLength = 20 type listWorkloadResources struct { localQueues map[string]*v1beta1.LocalQueue - pendingWorkloads map[string]*v1alpha1.PendingWorkload + pendingWorkloads map[string]*visibility.PendingWorkload apiResourceLists map[string]*metav1.APIResourceList } func newListWorkloadResources() *listWorkloadResources { return &listWorkloadResources{ localQueues: make(map[string]*v1beta1.LocalQueue), - pendingWorkloads: make(map[string]*v1alpha1.PendingWorkload), + pendingWorkloads: make(map[string]*visibility.PendingWorkload), apiResourceLists: make(map[string]*metav1.APIResourceList), } } diff --git a/cmd/kueuectl/app/list/list_workload_test.go b/cmd/kueuectl/app/list/list_workload_test.go index 3436e7dd3c..b437656afe 100644 --- a/cmd/kueuectl/app/list/list_workload_test.go +++ b/cmd/kueuectl/app/list/list_workload_test.go @@ -44,7 +44,7 @@ import ( testingclock "k8s.io/utils/clock/testing" kueue "sigs.k8s.io/kueue/apis/kueue/v1beta1" - "sigs.k8s.io/kueue/apis/visibility/v1alpha1" + visibility "sigs.k8s.io/kueue/apis/visibility/v1beta1" "sigs.k8s.io/kueue/client-go/clientset/versioned/fake" cmdtesting "sigs.k8s.io/kueue/cmd/kueuectl/app/testing" "sigs.k8s.io/kueue/pkg/controller/constants" @@ -57,7 +57,7 @@ func TestWorkloadCmd(t *testing.T) { testCases := map[string]struct { ns string apiResourceLists []*metav1.APIResourceList - pendingWorkloads []v1alpha1.PendingWorkload + pendingWorkloads []visibility.PendingWorkload objs []runtime.Object args []string mapperKinds []schema.GroupVersionKind @@ -823,7 +823,7 @@ wl1 rayjob.ray.io job-test lq1 cq1 PENDING `, }, "should print workload list with position in queue": { - pendingWorkloads: []v1alpha1.PendingWorkload{ + pendingWorkloads: []visibility.PendingWorkload{ { ObjectMeta: metav1.ObjectMeta{ Name: "wl1", @@ -921,7 +921,7 @@ wl2 j2 lq2 cq2 PENDING 22 // Default `Reaction` handle all verbs and resources, so need to add on // head of chain. clientset.PrependReactor("get", "clusterqueues", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { - obj := &v1alpha1.PendingWorkloadsSummary{Items: tc.pendingWorkloads} + obj := &visibility.PendingWorkloadsSummary{Items: tc.pendingWorkloads} return true, obj, err }) clientset.Discovery().(*fakediscovery.FakeDiscovery).Resources = tc.apiResourceLists diff --git a/config/components/visibility/apiservice_v1alpha1.yaml b/config/components/visibility/apiservice_v1alpha1.yaml index 9b2060c1f6..054ea07d62 100644 --- a/config/components/visibility/apiservice_v1alpha1.yaml +++ b/config/components/visibility/apiservice_v1alpha1.yaml @@ -10,4 +10,4 @@ spec: name: visibility-server namespace: kueue-system version: v1alpha1 - versionPriority: 100 + versionPriority: 100 \ No newline at end of file diff --git a/config/components/visibility/apiservice_v1beta1.yaml b/config/components/visibility/apiservice_v1beta1.yaml new file mode 100644 index 0000000000..1dc275ab47 --- /dev/null +++ b/config/components/visibility/apiservice_v1beta1.yaml @@ -0,0 +1,13 @@ +apiVersion: apiregistration.k8s.io/v1 +kind: APIService +metadata: + name: v1beta1.visibility.kueue.x-k8s.io +spec: + group: visibility.kueue.x-k8s.io + groupPriorityMinimum: 100 + insecureSkipTLSVerify: true + service: + name: visibility-server + namespace: kueue-system + version: v1beta1 + versionPriority: 100 \ No newline at end of file diff --git a/config/components/visibility/kustomization.yaml b/config/components/visibility/kustomization.yaml index 0e7d2cec7d..9b130042ed 100644 --- a/config/components/visibility/kustomization.yaml +++ b/config/components/visibility/kustomization.yaml @@ -1,4 +1,5 @@ resources: - apiservice_v1alpha1.yaml +- apiservice_v1beta1.yaml - role_binding.yaml - service.yaml diff --git a/hack/update-helm.sh b/hack/update-helm.sh index 6b066dc2fc..7a40339990 100755 --- a/hack/update-helm.sh +++ b/hack/update-helm.sh @@ -274,9 +274,9 @@ rm ${DEST_WEBHOOK_DIR}/MutatingWebhookConfiguration.yml ${DEST_WEBHOOK_DIR}/Vali # Add visibility files, replace names, namespaces in helm format for output_file in "${DEST_VISIBILITY_DIR}"/*.yaml; do - # The name of the v1alpha1.visibility.kueue.x-k8s.io APIService needs to remain unchanged. + # The name of the v1alpha1.visibility.kueue.x-k8s.io and v1beta1.visibility.kueue.x-k8s.io APIService needs to remain unchanged. if [ "$(< "$output_file" $YQ '.metadata | has("name")')" = "true" ] && - [ "$(< "$output_file" $YQ '.metadata.name | (. == "v1alpha1*")')" = "false" ]; then + [ "$(< "$output_file" $YQ '.metadata.name | (. == "v1alpha1*" or . == "v1beta1*")')" = "false" ]; then $YQ -N -i '.metadata.name |= "{{ include \"kueue.fullname\" . }}-" + .' "$output_file" fi # The namespace of the visibility-server-auth-reader rolebinding needs to remain unchanged. diff --git a/pkg/features/kube_features.go b/pkg/features/kube_features.go index d74970db27..5d16d6df77 100644 --- a/pkg/features/kube_features.go +++ b/pkg/features/kube_features.go @@ -60,6 +60,7 @@ const ( // owner: @pbundyra // kep: https://github.com/kubernetes-sigs/kueue/pull/1300 // alpha: v0.6 + // beta: v0.9 // // Enables Kueue visibility on demand VisibilityOnDemand featuregate.Feature = "VisibilityOnDemand" @@ -116,7 +117,7 @@ var defaultFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{ QueueVisibility: {Default: false, PreRelease: featuregate.Alpha}, FlavorFungibility: {Default: true, PreRelease: featuregate.Beta}, ProvisioningACC: {Default: true, PreRelease: featuregate.Beta}, - VisibilityOnDemand: {Default: false, PreRelease: featuregate.Alpha}, + VisibilityOnDemand: {Default: true, PreRelease: featuregate.Beta}, PrioritySortingWithinCohort: {Default: true, PreRelease: featuregate.Beta}, MultiKueue: {Default: false, PreRelease: featuregate.Alpha}, LendingLimit: {Default: true, PreRelease: featuregate.Beta}, diff --git a/pkg/visibility/api/install.go b/pkg/visibility/api/install.go index 6a415a2abe..134ad6a7fd 100644 --- a/pkg/visibility/api/install.go +++ b/pkg/visibility/api/install.go @@ -1,16 +1,18 @@ -// Copyright 2023 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. +/* +Copyright 2023 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 api @@ -20,42 +22,32 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apiserver/pkg/registry/rest" genericapiserver "k8s.io/apiserver/pkg/server" - "sigs.k8s.io/kueue/apis/visibility/v1alpha1" + visibilityv1alpha1 "sigs.k8s.io/kueue/apis/visibility/v1alpha1" + visibilityv1beta1 "sigs.k8s.io/kueue/apis/visibility/v1beta1" "sigs.k8s.io/kueue/pkg/queue" apiv1alpha1 "sigs.k8s.io/kueue/pkg/visibility/api/v1alpha1" + apiv1beta1 "sigs.k8s.io/kueue/pkg/visibility/api/v1beta1" ) var ( - Scheme = runtime.NewScheme() - - Codecs = serializer.NewCodecFactory(Scheme) - + Scheme = runtime.NewScheme() + Codecs = serializer.NewCodecFactory(Scheme) ParameterCodec = runtime.NewParameterCodec(Scheme) ) func init() { - utilruntime.Must(v1alpha1.AddToScheme(Scheme)) - utilruntime.Must(Scheme.SetVersionPriority(v1alpha1.GroupVersion)) + utilruntime.Must(visibilityv1alpha1.AddToScheme(Scheme)) + utilruntime.Must(visibilityv1beta1.AddToScheme(Scheme)) + utilruntime.Must(Scheme.SetVersionPriority(visibilityv1alpha1.GroupVersion, visibilityv1beta1.GroupVersion)) metav1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) } -// Install installs API scheme defined in apis/v1alpha1 and registers storage +// Install installs API scheme and registers storages func Install(server *genericapiserver.GenericAPIServer, kueueMgr *queue.Manager) error { - apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(v1alpha1.GroupVersion.Group, Scheme, ParameterCodec, Codecs) - pendingWorkloadsInCqREST := apiv1alpha1.NewPendingWorkloadsInCqREST(kueueMgr) - cqREST := apiv1alpha1.NewCqREST() - pendingWorkloadsInLqREST := apiv1alpha1.NewPendingWorkloadsInLqREST(kueueMgr) - lqREST := apiv1alpha1.NewLqREST() - - visibilityServerResources := map[string]rest.Storage{ - "clusterqueues": cqREST, - "clusterqueues/pendingworkloads": pendingWorkloadsInCqREST, - "localqueues": lqREST, - "localqueues/pendingworkloads": pendingWorkloadsInLqREST, - } - apiGroupInfo.VersionedResourcesStorageMap[v1alpha1.GroupVersion.Version] = visibilityServerResources + apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(visibilityv1beta1.GroupVersion.Group, Scheme, ParameterCodec, Codecs) + apiGroupInfo.VersionedResourcesStorageMap[visibilityv1alpha1.GroupVersion.Version] = apiv1alpha1.NewStorage(kueueMgr) + apiGroupInfo.VersionedResourcesStorageMap[visibilityv1beta1.GroupVersion.Version] = apiv1beta1.NewStorage(kueueMgr) return server.InstallAPIGroups(&apiGroupInfo) } diff --git a/pkg/visibility/api/v1alpha1/storage.go b/pkg/visibility/api/v1alpha1/storage.go new file mode 100644 index 0000000000..a509125e94 --- /dev/null +++ b/pkg/visibility/api/v1alpha1/storage.go @@ -0,0 +1,32 @@ +/* +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 v1alpha1 + +import ( + "k8s.io/apiserver/pkg/registry/rest" + + "sigs.k8s.io/kueue/pkg/queue" +) + +func NewStorage(mgr *queue.Manager) map[string]rest.Storage { + return map[string]rest.Storage{ + "clusterqueues": NewCqREST(), + "clusterqueues/pendingworkloads": NewPendingWorkloadsInCqREST(mgr), + "localqueues": NewLqREST(), + "localqueues/pendingworkloads": NewPendingWorkloadsInLqREST(mgr), + } +} diff --git a/pkg/visibility/api/v1beta1/cluster_queue.go b/pkg/visibility/api/v1beta1/cluster_queue.go new file mode 100644 index 0000000000..e269da377c --- /dev/null +++ b/pkg/visibility/api/v1beta1/cluster_queue.go @@ -0,0 +1,55 @@ +/* +Copyright 2023 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 v1beta1 + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/registry/rest" + + visibility "sigs.k8s.io/kueue/apis/visibility/v1beta1" +) + +// CqREST type is used only to install clusterqueues/ resource, so we can install clusterqueues/pending_workloads subresource. +// It implements the necessary interfaces for genericapiserver but does not provide any actual functionalities. +type CqREST struct{} + +// Those interfaces are necessary for genericapiserver to work properly +var _ rest.Storage = &CqREST{} +var _ rest.Scoper = &CqREST{} +var _ rest.SingularNameProvider = &CqREST{} + +func NewCqREST() *CqREST { + return &CqREST{} +} + +// New implements rest.Storage interface +func (m *CqREST) New() runtime.Object { + return &visibility.PendingWorkloadsSummary{} +} + +// Destroy implements rest.Storage interface +func (m *CqREST) Destroy() {} + +// NamespaceScoped implements rest.Scoper interface +func (m *CqREST) NamespaceScoped() bool { + return false +} + +// GetSingularName implements rest.SingularNameProvider interface +func (m *CqREST) GetSingularName() string { + return "clusterqueue" +} diff --git a/pkg/visibility/api/v1beta1/local_queue.go b/pkg/visibility/api/v1beta1/local_queue.go new file mode 100644 index 0000000000..4437278ea8 --- /dev/null +++ b/pkg/visibility/api/v1beta1/local_queue.go @@ -0,0 +1,55 @@ +/* +Copyright 2023 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 v1beta1 + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/registry/rest" + + visibility "sigs.k8s.io/kueue/apis/visibility/v1beta1" +) + +// LqREST type is used only to install localqueues/ resource, so we can install localqueues/pending_workloads subresource. +// It implements the necessary interfaces for genericapiserver but does not provide any actual functionalities. +type LqREST struct{} + +// Those interfaces are necessary for genericapiserver to work properly +var _ rest.Storage = &LqREST{} +var _ rest.Scoper = &LqREST{} +var _ rest.SingularNameProvider = &LqREST{} + +func NewLqREST() *LqREST { + return &LqREST{} +} + +// New implements rest.Storage interface +func (m *LqREST) New() runtime.Object { + return &visibility.PendingWorkloadsSummary{} +} + +// Destroy implements rest.Storage interface +func (m *LqREST) Destroy() {} + +// NamespaceScoped implements rest.Scoper interface +func (m *LqREST) NamespaceScoped() bool { + return true +} + +// GetSingularName implements rest.SingularNameProvider interface +func (m *LqREST) GetSingularName() string { + return "localqueue" +} diff --git a/pkg/visibility/api/v1beta1/pending_workloads_cq.go b/pkg/visibility/api/v1beta1/pending_workloads_cq.go new file mode 100644 index 0000000000..7672819e95 --- /dev/null +++ b/pkg/visibility/api/v1beta1/pending_workloads_cq.go @@ -0,0 +1,104 @@ +/* +Copyright 2023 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 v1beta1 + +import ( + "context" + "fmt" + + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/registry/rest" + ctrl "sigs.k8s.io/controller-runtime" + + visibility "sigs.k8s.io/kueue/apis/visibility/v1beta1" + "sigs.k8s.io/kueue/pkg/constants" + "sigs.k8s.io/kueue/pkg/queue" + + _ "k8s.io/metrics/pkg/apis/metrics/install" +) + +type pendingWorkloadsInCqREST struct { + queueMgr *queue.Manager + log logr.Logger +} + +var _ rest.Storage = &pendingWorkloadsInCqREST{} +var _ rest.GetterWithOptions = &pendingWorkloadsInCqREST{} +var _ rest.Scoper = &pendingWorkloadsInCqREST{} + +func NewPendingWorkloadsInCqREST(kueueMgr *queue.Manager) *pendingWorkloadsInCqREST { + return &pendingWorkloadsInCqREST{ + queueMgr: kueueMgr, + log: ctrl.Log.WithName("pending-workload-in-cq"), + } +} + +// New implements rest.Storage interface +func (m *pendingWorkloadsInCqREST) New() runtime.Object { + return &visibility.PendingWorkloadsSummary{} +} + +// Destroy implements rest.Storage interface +func (m *pendingWorkloadsInCqREST) Destroy() {} + +// Get implements rest.GetterWithOptions interface +// It fetches information about pending workloads and returns according to query params +func (m *pendingWorkloadsInCqREST) Get(_ context.Context, name string, opts runtime.Object) (runtime.Object, error) { + pendingWorkloadOpts, ok := opts.(*visibility.PendingWorkloadOptions) + if !ok { + return nil, fmt.Errorf("invalid options object: %#v", opts) + } + limit := pendingWorkloadOpts.Limit + offset := pendingWorkloadOpts.Offset + + wls := make([]visibility.PendingWorkload, 0, limit) + pendingWorkloadsInfo := m.queueMgr.PendingWorkloadsInfo(name) + if pendingWorkloadsInfo == nil { + return nil, errors.NewNotFound(visibility.Resource("clusterqueue"), name) + } + + localQueuePositions := make(map[string]int32, 0) + + for index := 0; index < int(offset+limit) && index < len(pendingWorkloadsInfo); index++ { + // Update positions in LocalQueue + wlInfo := pendingWorkloadsInfo[index] + queueName := wlInfo.Obj.Spec.QueueName + positionInLocalQueue := localQueuePositions[queueName] + localQueuePositions[queueName]++ + + if index >= int(offset) { + // Add a workload to results + wls = append(wls, *newPendingWorkload(wlInfo, positionInLocalQueue, index)) + } + } + return &visibility.PendingWorkloadsSummary{Items: wls}, nil +} + +// NewGetOptions creates a new options object +func (m *pendingWorkloadsInCqREST) NewGetOptions() (runtime.Object, bool, string) { + // If no query parameters were passed the generated defaults function are not executed so it's necessary to set default values here as well + return &visibility.PendingWorkloadOptions{ + Limit: constants.DefaultPendingWorkloadsLimit, + }, false, "" +} + +// NamespaceScoped implements rest.Scoper interface +func (m *pendingWorkloadsInCqREST) NamespaceScoped() bool { + return false +} diff --git a/pkg/visibility/api/v1beta1/pending_workloads_cq_test.go b/pkg/visibility/api/v1beta1/pending_workloads_cq_test.go new file mode 100644 index 0000000000..6128f65fc5 --- /dev/null +++ b/pkg/visibility/api/v1beta1/pending_workloads_cq_test.go @@ -0,0 +1,360 @@ +/* +Copyright 2023 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 v1beta1 + +import ( + "context" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + + kueue "sigs.k8s.io/kueue/apis/kueue/v1beta1" + visibility "sigs.k8s.io/kueue/apis/visibility/v1beta1" + "sigs.k8s.io/kueue/pkg/constants" + "sigs.k8s.io/kueue/pkg/queue" + utiltesting "sigs.k8s.io/kueue/pkg/util/testing" +) + +func TestPendingWorkloadsInCQ(t *testing.T) { + const ( + nsName = "foo" + cqNameA = "cqA" + cqNameB = "cqB" + lqNameA = "lqA" + lqNameB = "lqB" + lowPrio = 50 + highPrio = 100 + ) + + var ( + defaultQueryParams = &visibility.PendingWorkloadOptions{ + Offset: 0, + Limit: constants.DefaultPendingWorkloadsLimit, + } + ) + + scheme := runtime.NewScheme() + if err := kueue.AddToScheme(scheme); err != nil { + t.Fatalf("Failed adding kueue scheme: %s", err) + } + if err := visibility.AddToScheme(scheme); err != nil { + t.Fatalf("Failed adding kueue scheme: %s", err) + } + + now := time.Now() + cases := map[string]struct { + clusterQueues []*kueue.ClusterQueue + queues []*kueue.LocalQueue + workloads []*kueue.Workload + req *req + wantResp *resp + wantErrMatch func(error) bool + }{ + "single ClusterQueue and single LocalQueue setup with two workloads and default query parameters": { + clusterQueues: []*kueue.ClusterQueue{ + utiltesting.MakeClusterQueue(cqNameA).Obj(), + }, + queues: []*kueue.LocalQueue{ + utiltesting.MakeLocalQueue(lqNameA, nsName).ClusterQueue(cqNameA).Obj(), + }, + workloads: []*kueue.Workload{ + utiltesting.MakeWorkload("a", nsName).Queue(lqNameA).Priority(highPrio).Creation(now).Obj(), + utiltesting.MakeWorkload("b", nsName).Queue(lqNameA).Priority(lowPrio).Creation(now).Obj(), + }, + req: &req{ + queueName: cqNameA, + queryParams: defaultQueryParams, + }, + wantResp: &resp{ + wantPendingWorkloads: []visibility.PendingWorkload{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "a", + Namespace: nsName, + CreationTimestamp: metav1.NewTime(now), + }, + LocalQueueName: lqNameA, + Priority: highPrio, + PositionInClusterQueue: 0, + PositionInLocalQueue: 0, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "b", + Namespace: nsName, + CreationTimestamp: metav1.NewTime(now), + }, + LocalQueueName: lqNameA, + Priority: lowPrio, + PositionInClusterQueue: 1, + PositionInLocalQueue: 1, + }}, + }, + }, + "single ClusterQueue and two LocalQueue setup with four workloads and default query parameters": { + clusterQueues: []*kueue.ClusterQueue{ + utiltesting.MakeClusterQueue(cqNameA).Obj(), + }, + queues: []*kueue.LocalQueue{ + utiltesting.MakeLocalQueue(lqNameA, nsName).ClusterQueue(cqNameA).Obj(), + utiltesting.MakeLocalQueue(lqNameB, nsName).ClusterQueue(cqNameA).Obj(), + }, + workloads: []*kueue.Workload{ + utiltesting.MakeWorkload("lqA-high-prio", nsName).Queue(lqNameA).Priority(highPrio).Creation(now).Obj(), + utiltesting.MakeWorkload("lqA-low-prio", nsName).Queue(lqNameA).Priority(lowPrio).Creation(now).Obj(), + utiltesting.MakeWorkload("lqB-high-prio", nsName).Queue(lqNameB).Priority(highPrio).Creation(now.Add(time.Second)).Obj(), + utiltesting.MakeWorkload("lqB-low-prio", nsName).Queue(lqNameB).Priority(lowPrio).Creation(now.Add(time.Second)).Obj(), + }, + req: &req{ + queueName: cqNameA, + queryParams: defaultQueryParams, + }, + wantResp: &resp{ + wantPendingWorkloads: []visibility.PendingWorkload{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "lqA-high-prio", + Namespace: nsName, + CreationTimestamp: metav1.NewTime(now), + }, + LocalQueueName: lqNameA, + Priority: highPrio, + PositionInClusterQueue: 0, + PositionInLocalQueue: 0, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "lqB-high-prio", + Namespace: nsName, + CreationTimestamp: metav1.NewTime(now.Add(time.Second)), + }, + LocalQueueName: lqNameB, + Priority: highPrio, + PositionInClusterQueue: 1, + PositionInLocalQueue: 0, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "lqA-low-prio", + Namespace: nsName, + CreationTimestamp: metav1.NewTime(now), + }, + LocalQueueName: lqNameA, + Priority: lowPrio, + PositionInClusterQueue: 2, + PositionInLocalQueue: 1, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "lqB-low-prio", + Namespace: nsName, + CreationTimestamp: metav1.NewTime(now.Add(time.Second)), + }, + LocalQueueName: lqNameB, + Priority: lowPrio, + PositionInClusterQueue: 3, + PositionInLocalQueue: 1, + }}, + }, + }, + "limit query parameter set": { + clusterQueues: []*kueue.ClusterQueue{ + utiltesting.MakeClusterQueue(cqNameA).Obj(), + }, + queues: []*kueue.LocalQueue{ + utiltesting.MakeLocalQueue(lqNameA, nsName).ClusterQueue(cqNameA).Obj(), + }, + workloads: []*kueue.Workload{ + utiltesting.MakeWorkload("a", nsName).Queue(lqNameA).Priority(highPrio).Creation(now).Obj(), + utiltesting.MakeWorkload("b", nsName).Queue(lqNameA).Priority(highPrio).Creation(now.Add(time.Second)).Obj(), + utiltesting.MakeWorkload("c", nsName).Queue(lqNameA).Priority(highPrio).Creation(now.Add(time.Second * 2)).Obj(), + }, + req: &req{ + queueName: cqNameA, + queryParams: &visibility.PendingWorkloadOptions{ + Limit: 2, + }, + }, + wantResp: &resp{ + wantPendingWorkloads: []visibility.PendingWorkload{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "a", + Namespace: nsName, + CreationTimestamp: metav1.NewTime(now), + }, + LocalQueueName: lqNameA, + Priority: highPrio, + PositionInClusterQueue: 0, + PositionInLocalQueue: 0, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "b", + Namespace: nsName, + CreationTimestamp: metav1.NewTime(now.Add(time.Second)), + }, + LocalQueueName: lqNameA, + Priority: highPrio, + PositionInClusterQueue: 1, + PositionInLocalQueue: 1, + }}, + }, + }, + "offset query parameter set": { + clusterQueues: []*kueue.ClusterQueue{ + utiltesting.MakeClusterQueue(cqNameA).Obj(), + }, + queues: []*kueue.LocalQueue{ + utiltesting.MakeLocalQueue(lqNameA, nsName).ClusterQueue(cqNameA).Obj(), + }, + workloads: []*kueue.Workload{ + utiltesting.MakeWorkload("a", nsName).Queue(lqNameA).Priority(highPrio).Creation(now).Obj(), + utiltesting.MakeWorkload("b", nsName).Queue(lqNameA).Priority(highPrio).Creation(now.Add(time.Second)).Obj(), + utiltesting.MakeWorkload("c", nsName).Queue(lqNameA).Priority(highPrio).Creation(now.Add(time.Second * 2)).Obj(), + }, + req: &req{ + queueName: cqNameA, + queryParams: &visibility.PendingWorkloadOptions{ + Offset: 1, + Limit: constants.DefaultPendingWorkloadsLimit, + }, + }, + wantResp: &resp{ + wantPendingWorkloads: []visibility.PendingWorkload{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "b", + Namespace: nsName, + CreationTimestamp: metav1.NewTime(now.Add(time.Second)), + }, + LocalQueueName: lqNameA, + Priority: highPrio, + PositionInClusterQueue: 1, + PositionInLocalQueue: 1, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "c", + Namespace: nsName, + CreationTimestamp: metav1.NewTime(now.Add(time.Second * 2)), + }, + LocalQueueName: lqNameA, + Priority: highPrio, + PositionInClusterQueue: 2, + PositionInLocalQueue: 2, + }}, + }, + }, + "limit offset query parameters set": { + clusterQueues: []*kueue.ClusterQueue{ + utiltesting.MakeClusterQueue(cqNameA).Obj(), + }, + queues: []*kueue.LocalQueue{ + utiltesting.MakeLocalQueue(lqNameA, nsName).ClusterQueue(cqNameA).Obj(), + }, + workloads: []*kueue.Workload{ + utiltesting.MakeWorkload("a", nsName).Queue(lqNameA).Priority(highPrio).Creation(now).Obj(), + utiltesting.MakeWorkload("b", nsName).Queue(lqNameA).Priority(highPrio).Creation(now.Add(time.Second)).Obj(), + utiltesting.MakeWorkload("c", nsName).Queue(lqNameA).Priority(highPrio).Creation(now.Add(time.Second * 2)).Obj(), + }, + req: &req{ + queueName: cqNameA, + queryParams: &visibility.PendingWorkloadOptions{ + Offset: 1, + Limit: 1, + }, + }, + wantResp: &resp{ + wantPendingWorkloads: []visibility.PendingWorkload{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "b", + Namespace: nsName, + CreationTimestamp: metav1.NewTime(now.Add(time.Second)), + }, + LocalQueueName: lqNameA, + Priority: highPrio, + PositionInClusterQueue: 1, + PositionInLocalQueue: 1, + }}, + }, + }, + "empty cluster queue": { + clusterQueues: []*kueue.ClusterQueue{ + utiltesting.MakeClusterQueue(cqNameA).Obj(), + }, + req: &req{ + queueName: cqNameA, + queryParams: defaultQueryParams, + }, + wantResp: &resp{}, + }, + "nonexistent queue name": { + req: &req{ + queueName: "nonexistent-queue", + queryParams: defaultQueryParams, + }, + wantResp: &resp{ + wantErr: errors.NewNotFound(visibility.Resource("clusterqueue"), "nonexistent-queue"), + }, + wantErrMatch: errors.IsNotFound, + }, + } + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + manager := queue.NewManager(utiltesting.NewFakeClient(), nil) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + go manager.CleanUpOnContext(ctx) + pendingWorkloadsInCqRest := NewPendingWorkloadsInCqREST(manager) + for _, cq := range tc.clusterQueues { + if err := manager.AddClusterQueue(ctx, cq); err != nil { + t.Fatalf("Adding cluster queue %s: %v", cq.Name, err) + } + } + for _, q := range tc.queues { + if err := manager.AddLocalQueue(ctx, q); err != nil { + t.Fatalf("Adding queue %q: %v", q.Name, err) + } + } + for _, w := range tc.workloads { + manager.AddOrUpdateWorkload(w) + } + + info, err := pendingWorkloadsInCqRest.Get(ctx, tc.req.queueName, tc.req.queryParams) + switch { + case tc.wantErrMatch != nil: + if !tc.wantErrMatch(err) { + t.Errorf("Error differs: (-want,+got):\n%s", cmp.Diff(tc.wantResp.wantErr.Error(), err.Error())) + } + case err != nil: + t.Error(err) + default: + pendingWorkloadsInfo := info.(*visibility.PendingWorkloadsSummary) + if diff := cmp.Diff(tc.wantResp.wantPendingWorkloads, pendingWorkloadsInfo.Items, cmpopts.EquateEmpty()); diff != "" { + t.Errorf("Pending workloads differ: (-want,+got):\n%s", diff) + } + } + }) + } +} diff --git a/pkg/visibility/api/v1beta1/pending_workloads_lq.go b/pkg/visibility/api/v1beta1/pending_workloads_lq.go new file mode 100644 index 0000000000..bd3018eb70 --- /dev/null +++ b/pkg/visibility/api/v1beta1/pending_workloads_lq.go @@ -0,0 +1,107 @@ +/* +Copyright 2023 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 v1beta1 + +import ( + "context" + "fmt" + + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + genericapirequest "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/apiserver/pkg/registry/rest" + ctrl "sigs.k8s.io/controller-runtime" + + visibility "sigs.k8s.io/kueue/apis/visibility/v1beta1" + "sigs.k8s.io/kueue/pkg/constants" + "sigs.k8s.io/kueue/pkg/queue" + + _ "k8s.io/metrics/pkg/apis/metrics/install" +) + +type pendingWorkloadsInLqREST struct { + queueMgr *queue.Manager + log logr.Logger +} + +var _ rest.Storage = &pendingWorkloadsInLqREST{} +var _ rest.GetterWithOptions = &pendingWorkloadsInLqREST{} +var _ rest.Scoper = &pendingWorkloadsInLqREST{} + +func NewPendingWorkloadsInLqREST(kueueMgr *queue.Manager) *pendingWorkloadsInLqREST { + return &pendingWorkloadsInLqREST{ + queueMgr: kueueMgr, + log: ctrl.Log.WithName("pending-workload-in-lq"), + } +} + +// New implements rest.Storage interface +func (m *pendingWorkloadsInLqREST) New() runtime.Object { + return &visibility.PendingWorkloadsSummary{} +} + +// Destroy implements rest.Storage interface +func (m *pendingWorkloadsInLqREST) Destroy() {} + +// Get implements rest.GetterWithOptions interface +// It fetches information about pending workloads and returns according to query params +func (m *pendingWorkloadsInLqREST) Get(ctx context.Context, name string, opts runtime.Object) (runtime.Object, error) { + pendingWorkloadOpts, ok := opts.(*visibility.PendingWorkloadOptions) + if !ok { + return nil, fmt.Errorf("invalid options object: %#v", opts) + } + limit := pendingWorkloadOpts.Limit + offset := pendingWorkloadOpts.Offset + + namespace := genericapirequest.NamespaceValue(ctx) + cqName, ok := m.queueMgr.ClusterQueueFromLocalQueue(queue.QueueKey(namespace, name)) + if !ok { + return nil, errors.NewNotFound(visibility.Resource("localqueue"), name) + } + + wls := make([]visibility.PendingWorkload, 0, limit) + skippedWls := 0 + for index, wlInfo := range m.queueMgr.PendingWorkloadsInfo(cqName) { + if len(wls) >= int(limit) { + break + } + if wlInfo.Obj.Spec.QueueName == name { + if skippedWls < int(offset) { + skippedWls++ + } else { + // Add a workload to results + wls = append(wls, *newPendingWorkload(wlInfo, int32(len(wls)+int(offset)), index)) + } + } + } + + return &visibility.PendingWorkloadsSummary{Items: wls}, nil +} + +// NewGetOptions creates a new options object +func (m *pendingWorkloadsInLqREST) NewGetOptions() (runtime.Object, bool, string) { + // If no query parameters were passed the generated defaults function are not executed so it's necessary to set default values here as well + return &visibility.PendingWorkloadOptions{ + Limit: constants.DefaultPendingWorkloadsLimit, + }, false, "" +} + +// NamespaceScoped implements rest.Scoper interface +func (m *pendingWorkloadsInLqREST) NamespaceScoped() bool { + return true +} diff --git a/pkg/visibility/api/v1beta1/pending_workloads_lq_test.go b/pkg/visibility/api/v1beta1/pending_workloads_lq_test.go new file mode 100644 index 0000000000..54c2bdadb0 --- /dev/null +++ b/pkg/visibility/api/v1beta1/pending_workloads_lq_test.go @@ -0,0 +1,477 @@ +/* +Copyright 2023 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 v1beta1 + +import ( + "context" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/endpoints/request" + + kueue "sigs.k8s.io/kueue/apis/kueue/v1beta1" + visibility "sigs.k8s.io/kueue/apis/visibility/v1beta1" + "sigs.k8s.io/kueue/pkg/constants" + "sigs.k8s.io/kueue/pkg/queue" + utiltesting "sigs.k8s.io/kueue/pkg/util/testing" +) + +func TestPendingWorkloadsInLQ(t *testing.T) { + const ( + nsNameA = "nsA" + nsNameB = "nsB" + cqNameA = "cqA" + cqNameB = "cqB" + lqNameA = "lqA" + lqNameB = "lqB" + lowPrio = 50 + highPrio = 100 + ) + + defaultQueryParams := &visibility.PendingWorkloadOptions{ + Offset: 0, + Limit: constants.DefaultPendingWorkloadsLimit, + } + + scheme := runtime.NewScheme() + if err := kueue.AddToScheme(scheme); err != nil { + t.Fatalf("Failed adding kueue scheme: %s", err) + } + if err := visibility.AddToScheme(scheme); err != nil { + t.Fatalf("Failed adding kueue scheme: %s", err) + } + + now := time.Now() + cases := map[string]struct { + clusterQueues []*kueue.ClusterQueue + queues []*kueue.LocalQueue + workloads []*kueue.Workload + req *req + wantResp *resp + wantErrMatch func(error) bool + }{ + "single ClusterQueue and single LocalQueue setup with two workloads and default query parameters": { + clusterQueues: []*kueue.ClusterQueue{ + utiltesting.MakeClusterQueue(cqNameA).Obj(), + }, + queues: []*kueue.LocalQueue{ + utiltesting.MakeLocalQueue(lqNameA, nsNameA).ClusterQueue(cqNameA).Obj(), + }, + workloads: []*kueue.Workload{ + utiltesting.MakeWorkload("a", nsNameA).Queue(lqNameA).Priority(highPrio).Creation(now).Obj(), + utiltesting.MakeWorkload("b", nsNameA).Queue(lqNameA).Priority(lowPrio).Creation(now).Obj(), + }, + req: &req{ + nsName: nsNameA, + queueName: lqNameA, + queryParams: defaultQueryParams, + }, + wantResp: &resp{ + wantPendingWorkloads: []visibility.PendingWorkload{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "a", + Namespace: nsNameA, + CreationTimestamp: metav1.NewTime(now), + }, + LocalQueueName: lqNameA, + Priority: highPrio, + PositionInClusterQueue: 0, + PositionInLocalQueue: 0, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "b", + Namespace: nsNameA, + CreationTimestamp: metav1.NewTime(now), + }, + LocalQueueName: lqNameA, + Priority: lowPrio, + PositionInClusterQueue: 1, + PositionInLocalQueue: 1, + }}, + }, + }, + "single ClusterQueue and two LocalQueue setup with four workloads and default query parameters; LocalQueue A request": { + clusterQueues: []*kueue.ClusterQueue{ + utiltesting.MakeClusterQueue(cqNameA).Obj(), + }, + queues: []*kueue.LocalQueue{ + utiltesting.MakeLocalQueue(lqNameA, nsNameA).ClusterQueue(cqNameA).Obj(), + utiltesting.MakeLocalQueue(lqNameB, nsNameA).ClusterQueue(cqNameA).Obj(), + }, + workloads: []*kueue.Workload{ + utiltesting.MakeWorkload("lqA-high-prio", nsNameA).Queue(lqNameA).Priority(highPrio).Creation(now).Obj(), + utiltesting.MakeWorkload("lqA-low-prio", nsNameA).Queue(lqNameA).Priority(lowPrio).Creation(now).Obj(), + utiltesting.MakeWorkload("lqB-high-prio", nsNameA).Queue(lqNameB).Priority(highPrio).Creation(now.Add(time.Second)).Obj(), + utiltesting.MakeWorkload("lqB-low-prio", nsNameA).Queue(lqNameB).Priority(lowPrio).Creation(now.Add(time.Second)).Obj(), + }, + req: &req{ + nsName: nsNameA, + queueName: lqNameA, + queryParams: defaultQueryParams, + }, + wantResp: &resp{ + wantPendingWorkloads: []visibility.PendingWorkload{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "lqA-high-prio", + Namespace: nsNameA, + CreationTimestamp: metav1.NewTime(now), + }, + LocalQueueName: lqNameA, + Priority: highPrio, + PositionInClusterQueue: 0, + PositionInLocalQueue: 0, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "lqA-low-prio", + Namespace: nsNameA, + CreationTimestamp: metav1.NewTime(now), + }, + LocalQueueName: lqNameA, + Priority: lowPrio, + PositionInClusterQueue: 2, + PositionInLocalQueue: 1, + }}, + }, + }, + "single ClusterQueue and two LocalQueue setup with four workloads and default query parameters; LocalQueue B request": { + clusterQueues: []*kueue.ClusterQueue{ + utiltesting.MakeClusterQueue(cqNameA).Obj(), + }, + queues: []*kueue.LocalQueue{ + utiltesting.MakeLocalQueue(lqNameA, nsNameA).ClusterQueue(cqNameA).Obj(), + utiltesting.MakeLocalQueue(lqNameB, nsNameA).ClusterQueue(cqNameA).Obj(), + }, + workloads: []*kueue.Workload{ + utiltesting.MakeWorkload("lqA-high-prio", nsNameA).Queue(lqNameA).Priority(highPrio).Creation(now).Obj(), + utiltesting.MakeWorkload("lqA-low-prio", nsNameA).Queue(lqNameA).Priority(lowPrio).Creation(now).Obj(), + utiltesting.MakeWorkload("lqB-high-prio", nsNameA).Queue(lqNameB).Priority(highPrio).Creation(now.Add(time.Second)).Obj(), + utiltesting.MakeWorkload("lqB-low-prio", nsNameA).Queue(lqNameB).Priority(lowPrio).Creation(now.Add(time.Second)).Obj(), + }, + req: &req{ + nsName: nsNameA, + queueName: lqNameB, + queryParams: defaultQueryParams, + }, + wantResp: &resp{ + wantPendingWorkloads: []visibility.PendingWorkload{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "lqB-high-prio", + Namespace: nsNameA, + CreationTimestamp: metav1.NewTime(now.Add(time.Second)), + }, + LocalQueueName: lqNameB, + Priority: highPrio, + PositionInClusterQueue: 1, + PositionInLocalQueue: 0, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "lqB-low-prio", + Namespace: nsNameA, + CreationTimestamp: metav1.NewTime(now.Add(time.Second)), + }, + LocalQueueName: lqNameB, + Priority: lowPrio, + PositionInClusterQueue: 3, + PositionInLocalQueue: 1, + }, + }, + }, + }, + "two Namespaces, two ClusterQueue and two LocalQueue setup with four workloads and default query parameters, LocalQueue A request": { + clusterQueues: []*kueue.ClusterQueue{ + utiltesting.MakeClusterQueue(cqNameA).Obj(), + utiltesting.MakeClusterQueue(cqNameB).Obj(), + }, + queues: []*kueue.LocalQueue{ + utiltesting.MakeLocalQueue(lqNameA, nsNameA).ClusterQueue(cqNameA).Obj(), + utiltesting.MakeLocalQueue(lqNameB, nsNameB).ClusterQueue(cqNameB).Obj(), + }, + workloads: []*kueue.Workload{ + utiltesting.MakeWorkload("lqA-high-prio", nsNameA).Queue(lqNameA).Priority(highPrio).Creation(now).Obj(), + utiltesting.MakeWorkload("lqA-low-prio", nsNameA).Queue(lqNameA).Priority(lowPrio).Creation(now).Obj(), + utiltesting.MakeWorkload("lqB-high-prio", nsNameB).Queue(lqNameB).Priority(highPrio).Creation(now.Add(time.Second)).Obj(), + utiltesting.MakeWorkload("lqB-low-prio", nsNameB).Queue(lqNameB).Priority(lowPrio).Creation(now.Add(time.Second)).Obj(), + }, + req: &req{ + nsName: nsNameA, + queueName: lqNameA, + queryParams: defaultQueryParams, + }, + wantResp: &resp{ + wantPendingWorkloads: []visibility.PendingWorkload{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "lqA-high-prio", + Namespace: nsNameA, + CreationTimestamp: metav1.NewTime(now), + }, + LocalQueueName: lqNameA, + Priority: highPrio, + PositionInClusterQueue: 0, + PositionInLocalQueue: 0, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "lqA-low-prio", + Namespace: nsNameA, + CreationTimestamp: metav1.NewTime(now), + }, + LocalQueueName: lqNameA, + Priority: lowPrio, + PositionInClusterQueue: 1, + PositionInLocalQueue: 1, + }, + }, + }, + }, + "two Namespaces, two ClusterQueue and two LocalQueue setup with four workloads and default query parameters, LocalQueue B request": { + clusterQueues: []*kueue.ClusterQueue{ + utiltesting.MakeClusterQueue(cqNameA).Obj(), + utiltesting.MakeClusterQueue(cqNameB).Obj(), + }, + queues: []*kueue.LocalQueue{ + utiltesting.MakeLocalQueue(lqNameA, nsNameA).ClusterQueue(cqNameA).Obj(), + utiltesting.MakeLocalQueue(lqNameB, nsNameB).ClusterQueue(cqNameB).Obj(), + }, + workloads: []*kueue.Workload{ + utiltesting.MakeWorkload("lqA-high-prio", nsNameA).Queue(lqNameA).Priority(highPrio).Creation(now).Obj(), + utiltesting.MakeWorkload("lqA-low-prio", nsNameA).Queue(lqNameA).Priority(lowPrio).Creation(now).Obj(), + utiltesting.MakeWorkload("lqB-high-prio", nsNameB).Queue(lqNameB).Priority(highPrio).Creation(now.Add(time.Second)).Obj(), + utiltesting.MakeWorkload("lqB-low-prio", nsNameB).Queue(lqNameB).Priority(lowPrio).Creation(now.Add(time.Second)).Obj(), + }, + req: &req{ + nsName: nsNameB, + queueName: lqNameB, + queryParams: defaultQueryParams, + }, + wantResp: &resp{ + wantPendingWorkloads: []visibility.PendingWorkload{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "lqB-high-prio", + Namespace: nsNameB, + CreationTimestamp: metav1.NewTime(now.Add(time.Second)), + }, + LocalQueueName: lqNameB, + Priority: highPrio, + PositionInClusterQueue: 0, + PositionInLocalQueue: 0, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "lqB-low-prio", + Namespace: nsNameB, + CreationTimestamp: metav1.NewTime(now.Add(time.Second)), + }, + LocalQueueName: lqNameB, + Priority: lowPrio, + PositionInClusterQueue: 1, + PositionInLocalQueue: 1, + }, + }, + }, + }, + "limit query parameter set": { + clusterQueues: []*kueue.ClusterQueue{ + utiltesting.MakeClusterQueue(cqNameA).Obj(), + }, + queues: []*kueue.LocalQueue{ + utiltesting.MakeLocalQueue(lqNameA, nsNameA).ClusterQueue(cqNameA).Obj(), + }, + workloads: []*kueue.Workload{ + utiltesting.MakeWorkload("a", nsNameA).Queue(lqNameA).Priority(highPrio).Creation(now).Obj(), + utiltesting.MakeWorkload("b", nsNameA).Queue(lqNameA).Priority(highPrio).Creation(now.Add(time.Second)).Obj(), + utiltesting.MakeWorkload("c", nsNameA).Queue(lqNameA).Priority(highPrio).Creation(now.Add(time.Second * 2)).Obj(), + }, + req: &req{ + nsName: nsNameA, + queueName: lqNameA, + queryParams: &visibility.PendingWorkloadOptions{ + Limit: 2, + }, + }, + wantResp: &resp{ + wantPendingWorkloads: []visibility.PendingWorkload{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "a", + Namespace: nsNameA, + CreationTimestamp: metav1.NewTime(now), + }, + LocalQueueName: lqNameA, + Priority: highPrio, + PositionInClusterQueue: 0, + PositionInLocalQueue: 0, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "b", + Namespace: nsNameA, + CreationTimestamp: metav1.NewTime(now.Add(time.Second)), + }, + LocalQueueName: lqNameA, + Priority: highPrio, + PositionInClusterQueue: 1, + PositionInLocalQueue: 1, + }, + }, + }, + }, + "offset query parameter set": { + clusterQueues: []*kueue.ClusterQueue{ + utiltesting.MakeClusterQueue(cqNameA).Obj(), + }, + queues: []*kueue.LocalQueue{ + utiltesting.MakeLocalQueue(lqNameA, nsNameA).ClusterQueue(cqNameA).Obj(), + }, + workloads: []*kueue.Workload{ + utiltesting.MakeWorkload("a", nsNameA).Queue(lqNameA).Priority(highPrio).Creation(now).Obj(), + utiltesting.MakeWorkload("b", nsNameA).Queue(lqNameA).Priority(highPrio).Creation(now.Add(time.Second)).Obj(), + utiltesting.MakeWorkload("c", nsNameA).Queue(lqNameA).Priority(highPrio).Creation(now.Add(time.Second * 2)).Obj(), + }, + req: &req{ + nsName: nsNameA, + queueName: lqNameA, + queryParams: &visibility.PendingWorkloadOptions{ + Offset: 1, + Limit: constants.DefaultPendingWorkloadsLimit, + }, + }, + wantResp: &resp{ + wantPendingWorkloads: []visibility.PendingWorkload{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "b", + Namespace: nsNameA, + CreationTimestamp: metav1.NewTime(now.Add(time.Second)), + }, + LocalQueueName: lqNameA, + Priority: highPrio, + PositionInClusterQueue: 1, + PositionInLocalQueue: 1, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "c", + Namespace: nsNameA, + CreationTimestamp: metav1.NewTime(now.Add(time.Second * 2)), + }, + LocalQueueName: lqNameA, + Priority: highPrio, + PositionInClusterQueue: 2, + PositionInLocalQueue: 2, + }, + }, + }, + }, + "limit and offset query parameters set": { + clusterQueues: []*kueue.ClusterQueue{ + utiltesting.MakeClusterQueue(cqNameA).Obj(), + }, + queues: []*kueue.LocalQueue{ + utiltesting.MakeLocalQueue(lqNameA, nsNameA).ClusterQueue(cqNameA).Obj(), + }, + workloads: []*kueue.Workload{ + utiltesting.MakeWorkload("a", nsNameA).Queue(lqNameA).Priority(highPrio).Creation(now).Obj(), + utiltesting.MakeWorkload("b", nsNameA).Queue(lqNameA).Priority(highPrio).Creation(now.Add(time.Second)).Obj(), + utiltesting.MakeWorkload("c", nsNameA).Queue(lqNameA).Priority(highPrio).Creation(now.Add(time.Second * 2)).Obj(), + }, + req: &req{ + nsName: nsNameA, + queueName: lqNameA, + queryParams: &visibility.PendingWorkloadOptions{ + Offset: 1, + Limit: 1, + }, + }, + wantResp: &resp{ + wantPendingWorkloads: []visibility.PendingWorkload{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "b", + Namespace: nsNameA, + CreationTimestamp: metav1.NewTime(now.Add(time.Second)), + }, + LocalQueueName: lqNameA, + Priority: highPrio, + PositionInClusterQueue: 1, + PositionInLocalQueue: 1, + }, + }, + }, + }, + "nonexistent queue name": { + req: &req{ + queueName: "nonexistent-queue", + queryParams: defaultQueryParams, + }, + wantResp: &resp{ + wantErr: errors.NewNotFound(visibility.Resource("localqueue"), "invalid-name"), + }, + wantErrMatch: errors.IsNotFound, + }, + } + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + manager := queue.NewManager(utiltesting.NewFakeClient(), nil) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + go manager.CleanUpOnContext(ctx) + pendingWorkloadsInLqRest := NewPendingWorkloadsInLqREST(manager) + for _, cq := range tc.clusterQueues { + if err := manager.AddClusterQueue(ctx, cq); err != nil { + t.Fatalf("Adding cluster queue %s: %v", cq.Name, err) + } + } + for _, q := range tc.queues { + if err := manager.AddLocalQueue(ctx, q); err != nil { + t.Fatalf("Adding queue %q: %v", q.Name, err) + } + } + for _, w := range tc.workloads { + manager.AddOrUpdateWorkload(w) + } + + ctx = request.WithNamespace(ctx, tc.req.nsName) + info, err := pendingWorkloadsInLqRest.Get(ctx, tc.req.queueName, tc.req.queryParams) + switch { + case tc.wantErrMatch != nil: + if !tc.wantErrMatch(err) { + t.Errorf("Error differs: (-want,+got):\n%s", cmp.Diff(tc.wantResp.wantErr.Error(), err.Error())) + } + case err != nil: + t.Error(err) + default: + pendingWorkloadsInfo := info.(*visibility.PendingWorkloadsSummary) + if diff := cmp.Diff(tc.wantResp.wantPendingWorkloads, pendingWorkloadsInfo.Items, cmpopts.EquateEmpty()); diff != "" { + t.Errorf("Pending workloads differ: (-want,+got):\n%s", diff) + } + } + }) + } +} diff --git a/pkg/visibility/api/v1beta1/storage.go b/pkg/visibility/api/v1beta1/storage.go new file mode 100644 index 0000000000..58e1a4db03 --- /dev/null +++ b/pkg/visibility/api/v1beta1/storage.go @@ -0,0 +1,32 @@ +/* +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 v1beta1 + +import ( + "k8s.io/apiserver/pkg/registry/rest" + + "sigs.k8s.io/kueue/pkg/queue" +) + +func NewStorage(mgr *queue.Manager) map[string]rest.Storage { + return map[string]rest.Storage{ + "clusterqueues": NewCqREST(), + "clusterqueues/pendingworkloads": NewPendingWorkloadsInCqREST(mgr), + "localqueues": NewLqREST(), + "localqueues/pendingworkloads": NewPendingWorkloadsInLqREST(mgr), + } +} diff --git a/pkg/visibility/api/v1beta1/test_utils.go b/pkg/visibility/api/v1beta1/test_utils.go new file mode 100644 index 0000000000..b0c5047e19 --- /dev/null +++ b/pkg/visibility/api/v1beta1/test_utils.go @@ -0,0 +1,32 @@ +/* +Copyright 2023 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 v1beta1 + +import ( + visibility "sigs.k8s.io/kueue/apis/visibility/v1beta1" +) + +type req struct { + nsName string + queueName string + queryParams *visibility.PendingWorkloadOptions +} + +type resp struct { + wantErr error + wantPendingWorkloads []visibility.PendingWorkload +} diff --git a/pkg/visibility/api/v1beta1/utils.go b/pkg/visibility/api/v1beta1/utils.go new file mode 100644 index 0000000000..5974d8e7c0 --- /dev/null +++ b/pkg/visibility/api/v1beta1/utils.go @@ -0,0 +1,48 @@ +/* +Copyright 2023 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 v1beta1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + visibility "sigs.k8s.io/kueue/apis/visibility/v1beta1" + "sigs.k8s.io/kueue/pkg/workload" +) + +func newPendingWorkload(wlInfo *workload.Info, positionInLq int32, positionInCq int) *visibility.PendingWorkload { + ownerReferences := make([]metav1.OwnerReference, 0, len(wlInfo.Obj.OwnerReferences)) + for _, ref := range wlInfo.Obj.OwnerReferences { + ownerReferences = append(ownerReferences, metav1.OwnerReference{ + APIVersion: ref.APIVersion, + Kind: ref.Kind, + Name: ref.Name, + UID: ref.UID, + }) + } + return &visibility.PendingWorkload{ + ObjectMeta: metav1.ObjectMeta{ + Name: wlInfo.Obj.Name, + Namespace: wlInfo.Obj.Namespace, + OwnerReferences: ownerReferences, + CreationTimestamp: wlInfo.Obj.CreationTimestamp, + }, + PositionInClusterQueue: int32(positionInCq), + Priority: *wlInfo.Obj.Spec.Priority, + LocalQueueName: wlInfo.Obj.Spec.QueueName, + PositionInLocalQueue: positionInLq, + } +} diff --git a/pkg/visibility/server.go b/pkg/visibility/server.go index 14c8a0b90d..7cae946f1f 100644 --- a/pkg/visibility/server.go +++ b/pkg/visibility/server.go @@ -1,16 +1,18 @@ -// Copyright 2023 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. +/* +Copyright 2023 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 visibility @@ -22,7 +24,8 @@ import ( "strings" generatedopenapi "sigs.k8s.io/kueue/apis/visibility/openapi" - "sigs.k8s.io/kueue/apis/visibility/v1alpha1" + visibilityv1alpha1 "sigs.k8s.io/kueue/apis/visibility/v1alpha1" + visibilityv1beta1 "sigs.k8s.io/kueue/apis/visibility/v1beta1" "sigs.k8s.io/kueue/pkg/queue" "sigs.k8s.io/kueue/pkg/visibility/api" @@ -58,7 +61,7 @@ func CreateAndStartVisibilityServer(ctx context.Context, kueueMgr *queue.Manager } if err := api.Install(visibilityServer, kueueMgr); err != nil { - setupLog.Error(err, "Unable to install visibility.kueue.x-k8s.io/v1alpha1 API") + setupLog.Error(err, "Unable to install visibility.kueue.x-k8s.io API") os.Exit(1) } @@ -69,7 +72,10 @@ func CreateAndStartVisibilityServer(ctx context.Context, kueueMgr *queue.Manager } func applyVisibilityServerOptions(config *genericapiserver.RecommendedConfig) error { - o := genericoptions.NewRecommendedOptions("", api.Codecs.LegacyCodec(v1alpha1.SchemeGroupVersion)) + o := genericoptions.NewRecommendedOptions("", api.Codecs.LegacyCodec( + visibilityv1alpha1.SchemeGroupVersion, + visibilityv1beta1.SchemeGroupVersion, + )) o.Etcd = nil o.SecureServing.BindPort = 8082 // The directory where TLS certs will be created diff --git a/site/content/en/docs/installation/_index.md b/site/content/en/docs/installation/_index.md index 962c843216..fae220ffdc 100644 --- a/site/content/en/docs/installation/_index.md +++ b/site/content/en/docs/installation/_index.md @@ -243,7 +243,8 @@ The currently supported features are: | `ProvisioningACC` | `false` | Alpha | 0.5 | 0.6 | | `ProvisioningACC` | `true` | Beta | 0.7 | | | `QueueVisibility` | `false` | Alpha | 0.5 | | -| `VisibilityOnDemand` | `false` | Alpha | 0.6 | | +| `VisibilityOnDemand` | `false` | Alpha | 0.6 | 0.8 | +| `VisibilityOnDemand` | `true` | Beta | 0.9 | | | `PrioritySortingWithinCohort` | `true` | Beta | 0.6 | | | `LendingLimit` | `false` | Alpha | 0.6 | 0.8 | | `LendingLimit` | `true` | Beta | 0.9 | | 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 19bee460a8..570e3808d7 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 @@ -22,10 +22,6 @@ Make sure the following conditions are met: - The kubectl command-line tool has communication with your cluster. - [Kueue is installed](/docs/installation) in version v0.6.0 or later. -### Enable the VisibilityOnDemand feature gate - -VisibilityOnDemand is an `Alpha` feature disabled by default. To use the visibility API change [the feature gates configuration](/docs/installation/#change-the-feature-gates-configuration) and set `VisibilityOnDemand=true`. - ### Configure API Priority and Fairness: To install the [API Priority and Fairness](https://kubernetes.io/docs/concepts/cluster-administration/flow-control/) configuration for the visibility API apply one of the manifests, depending on your Kubernetes version: @@ -37,7 +33,13 @@ To install the [API Priority and Fairness](https://kubernetes.io/docs/concepts/c ## Monitor pending workloads on demand -{{< feature-state state="alpha" for_version="v0.6" >}} +{{< feature-state state="beta" for_version="v0.9" >}} +{{% alert title="Note" color="primary" %}} + +`VisibilityOnDemand` is a Beta feature enabled by default. + +You can disable it by setting the `VisibilityOnDemand` feature gate. Check the [Installation](/docs/installation/#change-the-feature-gates-configuration) guide for details on feature gate configuration. +{{% /alert %}} To install a simple setup of ClusterQueue @@ -66,7 +68,7 @@ for i in {1..6}; do kubectl create -f https://kueue.sigs.k8s.io/examples/jobs/sa To view pending workloads in ClusterQueue `cluster-queue` run the following command: ```shell -kubectl get --raw "/apis/visibility.kueue.x-k8s.io/v1alpha1/clusterqueues/cluster-queue/pendingworkloads" +kubectl get --raw "/apis/visibility.kueue.x-k8s.io/v1beta1/clusterqueues/cluster-queue/pendingworkloads" ``` You should get results similar to: @@ -74,7 +76,7 @@ You should get results similar to: ```json { "kind": "PendingWorkloadsSummary", - "apiVersion": "visibility.kueue.x-k8s.io/v1alpha1", + "apiVersion": "visibility.kueue.x-k8s.io/v1beta1", "metadata": { "creationTimestamp": null }, @@ -147,7 +149,7 @@ You can pass optional query parameters: To view only 1 pending workloads use, starting from position 1 in ClusterQueue run: ```shell -kubectl get --raw "/apis/visibility.kueue.x-k8s.io/v1alpha1/clusterqueues/cluster-queue/pendingworkloads?limit=1&offset=1" +kubectl get --raw "/apis/visibility.kueue.x-k8s.io/v1beta1/clusterqueues/cluster-queue/pendingworkloads?limit=1&offset=1" ``` You should get results similar to @@ -155,7 +157,7 @@ You should get results similar to ``` json { "kind": "PendingWorkloadsSummary", - "apiVersion": "visibility.kueue.x-k8s.io/v1alpha1", + "apiVersion": "visibility.kueue.x-k8s.io/v1beta1", "metadata": { "creationTimestamp": null }, @@ -188,7 +190,7 @@ You should get results similar to Similarly to ClusterQueue, to view pending workloads in LocalQueue `user-queue` run the following command: ```shell -kubectl get --raw /apis/visibility.kueue.x-k8s.io/v1alpha1/namespaces/default/localqueues/user-queue/pendingworkloads +kubectl get --raw /apis/visibility.kueue.x-k8s.io/v1beta1/namespaces/default/localqueues/user-queue/pendingworkloads ``` You should get results similar to: @@ -196,7 +198,7 @@ You should get results similar to: ``` json { "kind": "PendingWorkloadsSummary", - "apiVersion": "visibility.kueue.x-k8s.io/v1alpha1", + "apiVersion": "visibility.kueue.x-k8s.io/v1beta1", "metadata": { "creationTimestamp": null }, @@ -269,7 +271,7 @@ You can pass optional query parameters: To view only 1 pending workloads use, starting from position 1 in LocalQueue run: ```shell -kubectl get --raw "/apis/visibility.kueue.x-k8s.io/v1alpha1/namespaces/default/localqueues/user-queue/pendingworkloads?limit=1&offset=1" +kubectl get --raw "/apis/visibility.kueue.x-k8s.io/v1beta1/namespaces/default/localqueues/user-queue/pendingworkloads?limit=1&offset=1" ``` You should get results similar to @@ -277,7 +279,7 @@ You should get results similar to ``` json { "kind": "PendingWorkloadsSummary", - "apiVersion": "visibility.kueue.x-k8s.io/v1alpha1", + "apiVersion": "visibility.kueue.x-k8s.io/v1beta1", "metadata": { "creationTimestamp": null }, diff --git a/test/e2e/config/common/manager_e2e_patch.yaml b/test/e2e/config/common/manager_e2e_patch.yaml index 8de3324961..2a5c3b0486 100644 --- a/test/e2e/config/common/manager_e2e_patch.yaml +++ b/test/e2e/config/common/manager_e2e_patch.yaml @@ -3,4 +3,4 @@ value: IfNotPresent - op: add path: /spec/template/spec/containers/0/args/- - value: --feature-gates=VisibilityOnDemand=true,MultiKueue=true,MultiKueueBatchJobWithManagedBy=true + value: --feature-gates=MultiKueue=true,MultiKueueBatchJobWithManagedBy=true diff --git a/test/e2e/singlecluster/suite_test.go b/test/e2e/singlecluster/suite_test.go index 8efdd700b5..13ac780d7f 100644 --- a/test/e2e/singlecluster/suite_test.go +++ b/test/e2e/singlecluster/suite_test.go @@ -29,7 +29,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - visibilityv1alpha1 "sigs.k8s.io/kueue/client-go/clientset/versioned/typed/visibility/v1alpha1" + visibilityv1beta1 "sigs.k8s.io/kueue/client-go/clientset/versioned/typed/visibility/v1beta1" "sigs.k8s.io/kueue/test/util" ) @@ -37,8 +37,8 @@ var ( kueuectlPath = filepath.Join("..", "..", "..", "bin", "kubectl-kueue") k8sClient client.WithWatch ctx context.Context - visibilityClient visibilityv1alpha1.VisibilityV1alpha1Interface - impersonatedVisibilityClient visibilityv1alpha1.VisibilityV1alpha1Interface + visibilityClient visibilityv1beta1.VisibilityV1beta1Interface + impersonatedVisibilityClient visibilityv1beta1.VisibilityV1beta1Interface ) func TestAPIs(t *testing.T) { diff --git a/test/e2e/singlecluster/visibility_test.go b/test/e2e/singlecluster/visibility_test.go index a0ae7f8c19..9b8082c6c0 100644 --- a/test/e2e/singlecluster/visibility_test.go +++ b/test/e2e/singlecluster/visibility_test.go @@ -30,7 +30,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" kueue "sigs.k8s.io/kueue/apis/kueue/v1beta1" - visibility "sigs.k8s.io/kueue/apis/visibility/v1alpha1" + visibility "sigs.k8s.io/kueue/apis/visibility/v1beta1" "sigs.k8s.io/kueue/pkg/util/testing" testingjob "sigs.k8s.io/kueue/pkg/util/testingjobs/job" "sigs.k8s.io/kueue/test/util" diff --git a/test/util/e2e.go b/test/util/e2e.go index a6607a04db..426bb6f44a 100644 --- a/test/util/e2e.go +++ b/test/util/e2e.go @@ -20,9 +20,9 @@ import ( kueuealpha "sigs.k8s.io/kueue/apis/kueue/v1alpha1" kueue "sigs.k8s.io/kueue/apis/kueue/v1beta1" - visibility "sigs.k8s.io/kueue/apis/visibility/v1alpha1" + visibility "sigs.k8s.io/kueue/apis/visibility/v1beta1" kueueclientset "sigs.k8s.io/kueue/client-go/clientset/versioned" - visibilityv1alpha1 "sigs.k8s.io/kueue/client-go/clientset/versioned/typed/visibility/v1alpha1" + visibilityv1beta1 "sigs.k8s.io/kueue/client-go/clientset/versioned/typed/visibility/v1beta1" ) const ( @@ -61,7 +61,7 @@ func CreateClientUsingCluster(kContext string) (client.WithWatch, *rest.Config) return client, cfg } -func CreateVisibilityClient(user string) visibilityv1alpha1.VisibilityV1alpha1Interface { +func CreateVisibilityClient(user string) visibilityv1beta1.VisibilityV1beta1Interface { cfg, err := config.GetConfigWithContext("") if err != nil { fmt.Printf("unable to get kubeconfig: %s", err) @@ -78,7 +78,7 @@ func CreateVisibilityClient(user string) visibilityv1alpha1.VisibilityV1alpha1In fmt.Printf("unable to create kueue clientset: %s", err) os.Exit(1) } - visibilityClient := kueueClient.VisibilityV1alpha1() + visibilityClient := kueueClient.VisibilityV1beta1() return visibilityClient }