diff --git a/cmd/dra-example-kubeletplugin/health.go b/cmd/dra-example-kubeletplugin/health.go index 47f813d7..14d393aa 100644 --- a/cmd/dra-example-kubeletplugin/health.go +++ b/cmd/dra-example-kubeletplugin/health.go @@ -31,7 +31,7 @@ import ( "google.golang.org/grpc/health/grpc_health_v1" "google.golang.org/grpc/status" "k8s.io/klog/v2" - drapb "k8s.io/kubelet/pkg/apis/dra/v1beta1" + drapb "k8s.io/kubelet/pkg/apis/dra/v1" registerapi "k8s.io/kubelet/pkg/apis/pluginregistration/v1" "sigs.k8s.io/dra-example-driver/pkg/consts" diff --git a/cmd/dra-example-webhook/main.go b/cmd/dra-example-webhook/main.go index 5ab47082..b7ce2172 100644 --- a/cmd/dra-example-webhook/main.go +++ b/cmd/dra-example-webhook/main.go @@ -27,11 +27,9 @@ import ( "github.com/urfave/cli/v2" admissionv1 "k8s.io/api/admission/v1" - resourceapi "k8s.io/api/resource/v1beta1" + resourceapi "k8s.io/api/resource/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/serializer" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/klog/v2" configapi "sigs.k8s.io/dra-example-driver/api/example.com/resource/gpu/v1alpha1" @@ -39,19 +37,6 @@ import ( "sigs.k8s.io/dra-example-driver/pkg/flags" ) -var ( - resourceClaimResource = metav1.GroupVersionResource{ - Group: resourceapi.SchemeGroupVersion.Group, - Version: resourceapi.SchemeGroupVersion.Version, - Resource: "resourceclaims", - } - resourceClaimTemplateResource = metav1.GroupVersionResource{ - Group: resourceapi.SchemeGroupVersion.Group, - Version: resourceapi.SchemeGroupVersion.Version, - Resource: "resourceclaimtemplates", - } -) - type Flags struct { loggingConfig *flags.LoggingConfig @@ -60,13 +45,6 @@ type Flags struct { port int } -var scheme = runtime.NewScheme() -var codecs = serializer.NewCodecFactory(scheme) - -func init() { - utilruntime.Must(admissionv1.AddToScheme(scheme)) -} - func main() { if err := newApp().Run(os.Args); err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) @@ -219,13 +197,10 @@ func admitResourceClaimParameters(ar admissionv1.AdmissionReview) *admissionv1.A var deviceConfigs []resourceapi.DeviceClaimConfiguration var specPath string - raw := ar.Request.Object.Raw - deserializer := codecs.UniversalDeserializer() - switch ar.Request.Resource { - case resourceClaimResource: - claim := resourceapi.ResourceClaim{} - if _, _, err := deserializer.Decode(raw, nil, &claim); err != nil { + case resourceClaimResourceV1, resourceClaimResourceV1Beta1, resourceClaimResourceV1Beta2: + claim, err := extractResourceClaim(ar) + if err != nil { klog.Error(err) return &admissionv1.AdmissionResponse{ Result: &metav1.Status{ @@ -236,9 +211,9 @@ func admitResourceClaimParameters(ar admissionv1.AdmissionReview) *admissionv1.A } deviceConfigs = claim.Spec.Devices.Config specPath = "spec" - case resourceClaimTemplateResource: - claimTemplate := resourceapi.ResourceClaimTemplate{} - if _, _, err := deserializer.Decode(raw, nil, &claimTemplate); err != nil { + case resourceClaimTemplateResourceV1, resourceClaimTemplateResourceV1Beta1, resourceClaimTemplateResourceV1Beta2: + claimTemplate, err := extractResourceClaimTemplate(ar) + if err != nil { klog.Error(err) return &admissionv1.AdmissionResponse{ Result: &metav1.Status{ @@ -250,7 +225,14 @@ func admitResourceClaimParameters(ar admissionv1.AdmissionReview) *admissionv1.A deviceConfigs = claimTemplate.Spec.Spec.Devices.Config specPath = "spec.spec" default: - msg := fmt.Sprintf("expected resource to be %s or %s, got %s", resourceClaimResource, resourceClaimTemplateResource, ar.Request.Resource) + msg := fmt.Sprintf( + "expected resource to be one of %v, got %s", + []metav1.GroupVersionResource{ + resourceClaimResourceV1, resourceClaimResourceV1Beta1, resourceClaimResourceV1Beta2, + resourceClaimTemplateResourceV1, resourceClaimTemplateResourceV1Beta1, resourceClaimTemplateResourceV1Beta2, + }, + ar.Request.Resource, + ) klog.Error(msg) return &admissionv1.AdmissionResponse{ Result: &metav1.Status{ diff --git a/cmd/dra-example-webhook/main_test.go b/cmd/dra-example-webhook/main_test.go index 9096ecf2..249c128a 100644 --- a/cmd/dra-example-webhook/main_test.go +++ b/cmd/dra-example-webhook/main_test.go @@ -19,6 +19,7 @@ package main import ( "bytes" "encoding/json" + "fmt" "io" "net/http" "net/http/httptest" @@ -28,7 +29,8 @@ import ( "github.com/stretchr/testify/require" admissionv1 "k8s.io/api/admission/v1" - resourceapi "k8s.io/api/resource/v1beta1" + resourceapi "k8s.io/api/resource/v1" + resourcev1beta1 "k8s.io/api/resource/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" @@ -47,6 +49,40 @@ func TestReadyEndpoint(t *testing.T) { } func TestResourceClaimValidatingWebhook(t *testing.T) { + unknownResource := metav1.GroupVersionResource{ + Group: "resource.k8s.io", + Version: "v1", + Resource: "unknownresources", + } + + validGPUConfig := &configapi.GpuConfig{ + Sharing: &configapi.GpuSharing{ + Strategy: configapi.TimeSlicingStrategy, + TimeSlicingConfig: &configapi.TimeSlicingConfig{ + Interval: configapi.DefaultTimeSlice, + }, + }, + } + + invalidGPUConfigs := []*configapi.GpuConfig{ + { + Sharing: &configapi.GpuSharing{ + Strategy: configapi.TimeSlicingStrategy, + TimeSlicingConfig: &configapi.TimeSlicingConfig{ + Interval: "InvalidInterval", + }, + }, + }, + { + Sharing: &configapi.GpuSharing{ + Strategy: configapi.SpacePartitioningStrategy, + SpacePartitioningConfig: &configapi.SpacePartitioningConfig{ + PartitionCount: -1, + }, + }, + }, + } + tests := map[string]struct { admissionReview *admissionv1.AdmissionReview requestContentType string @@ -64,86 +100,72 @@ func TestResourceClaimValidatingWebhook(t *testing.T) { }, "valid GpuConfig in ResourceClaim": { admissionReview: admissionReviewWithObject( - resourceClaimWithGpuConfigs( - &configapi.GpuConfig{ - Sharing: &configapi.GpuSharing{ - Strategy: configapi.TimeSlicingStrategy, - TimeSlicingConfig: &configapi.TimeSlicingConfig{ - Interval: configapi.DefaultTimeSlice, - }, - }, - }, - ), - resourceClaimResource, + resourceClaimWithGpuConfigs(validGPUConfig), + resourceClaimResourceV1, ), expectedAllowed: true, }, "invalid GpuConfigs in ResourceClaim": { admissionReview: admissionReviewWithObject( - resourceClaimWithGpuConfigs( - &configapi.GpuConfig{ - Sharing: &configapi.GpuSharing{ - Strategy: configapi.TimeSlicingStrategy, - TimeSlicingConfig: &configapi.TimeSlicingConfig{ - Interval: "InvalidInterval", - }, - }, - }, - &configapi.GpuConfig{ - Sharing: &configapi.GpuSharing{ - Strategy: configapi.SpacePartitioningStrategy, - SpacePartitioningConfig: &configapi.SpacePartitioningConfig{ - PartitionCount: -1, - }, - }, - }, - ), - resourceClaimResource, + resourceClaimWithGpuConfigs(invalidGPUConfigs...), + resourceClaimResourceV1, ), expectedAllowed: false, expectedMessage: "2 configs failed to validate: object at spec.devices.config[0].opaque.parameters is invalid: unknown time-slice interval: InvalidInterval; object at spec.devices.config[1].opaque.parameters is invalid: invalid partition count: -1", }, "valid GpuConfig in ResourceClaimTemplate": { admissionReview: admissionReviewWithObject( - resourceClaimTemplateWithGpuConfigs( - &configapi.GpuConfig{ - Sharing: &configapi.GpuSharing{ - Strategy: configapi.TimeSlicingStrategy, - TimeSlicingConfig: &configapi.TimeSlicingConfig{ - Interval: configapi.DefaultTimeSlice, - }, - }, - }, - ), - resourceClaimTemplateResource, + resourceClaimTemplateWithGpuConfigs(validGPUConfig), + resourceClaimTemplateResourceV1, ), expectedAllowed: true, }, "invalid GpuConfigs in ResourceClaimTemplate": { admissionReview: admissionReviewWithObject( - resourceClaimTemplateWithGpuConfigs( - &configapi.GpuConfig{ - Sharing: &configapi.GpuSharing{ - Strategy: configapi.TimeSlicingStrategy, - TimeSlicingConfig: &configapi.TimeSlicingConfig{ - Interval: "InvalidInterval", - }, - }, - }, - &configapi.GpuConfig{ - Sharing: &configapi.GpuSharing{ - Strategy: configapi.SpacePartitioningStrategy, - SpacePartitioningConfig: &configapi.SpacePartitioningConfig{ - PartitionCount: -1, - }, - }, - }, - ), - resourceClaimTemplateResource, + resourceClaimTemplateWithGpuConfigs(invalidGPUConfigs...), + resourceClaimTemplateResourceV1, + ), + expectedAllowed: false, + expectedMessage: "2 configs failed to validate: object at spec.spec.devices.config[0].opaque.parameters is invalid: unknown time-slice interval: InvalidInterval; object at spec.spec.devices.config[1].opaque.parameters is invalid: invalid partition count: -1", + }, + "valid GpuConfig in ResourceClaim v1beta1": { + admissionReview: admissionReviewWithObject( + toResourceClaimV1Beta1(resourceClaimWithGpuConfigs(validGPUConfig)), + resourceClaimResourceV1Beta1, + ), + expectedAllowed: true, + }, + "invalid GpuConfigs in ResourceClaim v1beta1": { + admissionReview: admissionReviewWithObject( + toResourceClaimV1Beta1(resourceClaimWithGpuConfigs(invalidGPUConfigs...)), + resourceClaimResourceV1Beta1, + ), + expectedAllowed: false, + expectedMessage: "2 configs failed to validate: object at spec.devices.config[0].opaque.parameters is invalid: unknown time-slice interval: InvalidInterval; object at spec.devices.config[1].opaque.parameters is invalid: invalid partition count: -1", + }, + "valid GpuConfig in ResourceClaimTemplate v1beta1": { + admissionReview: admissionReviewWithObject( + toResourceClaimTemplateV1Beta1(resourceClaimTemplateWithGpuConfigs(validGPUConfig)), + resourceClaimTemplateResourceV1Beta1, + ), + expectedAllowed: true, + }, + "invalid GpuConfigs in ResourceClaimTemplate v1beta1": { + admissionReview: admissionReviewWithObject( + toResourceClaimTemplateV1Beta1(resourceClaimTemplateWithGpuConfigs(invalidGPUConfigs...)), + resourceClaimTemplateResourceV1Beta1, ), expectedAllowed: false, expectedMessage: "2 configs failed to validate: object at spec.spec.devices.config[0].opaque.parameters is invalid: unknown time-slice interval: InvalidInterval; object at spec.spec.devices.config[1].opaque.parameters is invalid: invalid partition count: -1", }, + "unknown resource type": { + admissionReview: admissionReviewWithObject( + resourceClaimWithGpuConfigs(validGPUConfig), + unknownResource, + ), + expectedAllowed: false, + expectedMessage: "expected resource to be one of [{resource.k8s.io v1 resourceclaims} {resource.k8s.io v1beta1 resourceclaims} {resource.k8s.io v1beta2 resourceclaims} {resource.k8s.io v1 resourceclaimtemplates} {resource.k8s.io v1beta1 resourceclaimtemplates} {resource.k8s.io v1beta2 resourceclaimtemplates}], got {resource.k8s.io v1 unknownresources}", + }, } s := httptest.NewServer(newMux()) @@ -238,3 +260,19 @@ func resourceClaimSpecWithGpuConfigs(gpuConfigs ...*configapi.GpuConfig) resourc } return resourceClaimSpec } + +func toResourceClaimV1Beta1(v1Claim *resourceapi.ResourceClaim) *resourcev1beta1.ResourceClaim { + v1beta1Claim := &resourcev1beta1.ResourceClaim{} + if err := scheme.Convert(v1Claim, v1beta1Claim, nil); err != nil { + panic(fmt.Sprintf("failed to convert ResourceClaim to v1beta1: %v", err)) + } + return v1beta1Claim +} + +func toResourceClaimTemplateV1Beta1(v1Template *resourceapi.ResourceClaimTemplate) *resourcev1beta1.ResourceClaimTemplate { + v1beta1Template := &resourcev1beta1.ResourceClaimTemplate{} + if err := scheme.Convert(v1Template, v1beta1Template, nil); err != nil { + panic(fmt.Sprintf("failed to convert ResourceClaimTemplate to v1beta1: %v", err)) + } + return v1beta1Template +} diff --git a/cmd/dra-example-webhook/resource.go b/cmd/dra-example-webhook/resource.go new file mode 100644 index 00000000..cad84140 --- /dev/null +++ b/cmd/dra-example-webhook/resource.go @@ -0,0 +1,154 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "fmt" + + admissionv1 "k8s.io/api/admission/v1" + resourcev1 "k8s.io/api/resource/v1" + resourcev1beta1 "k8s.io/api/resource/v1beta1" + resourcev1beta2 "k8s.io/api/resource/v1beta2" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + + // This will register the conversions between api versions. + _ "k8s.io/dynamic-resource-allocation/client" +) + +// Resource definitions for different API versions. +var ( + // v1 resources. + resourceClaimResourceV1 = metav1.GroupVersionResource{ + Group: "resource.k8s.io", + Version: "v1", + Resource: "resourceclaims", + } + resourceClaimTemplateResourceV1 = metav1.GroupVersionResource{ + Group: "resource.k8s.io", + Version: "v1", + Resource: "resourceclaimtemplates", + } + + // v1beta1 resources. + resourceClaimResourceV1Beta1 = metav1.GroupVersionResource{ + Group: "resource.k8s.io", + Version: "v1beta1", + Resource: "resourceclaims", + } + resourceClaimTemplateResourceV1Beta1 = metav1.GroupVersionResource{ + Group: "resource.k8s.io", + Version: "v1beta1", + Resource: "resourceclaimtemplates", + } + + // v1beta2 resources. + resourceClaimResourceV1Beta2 = metav1.GroupVersionResource{ + Group: "resource.k8s.io", + Version: "v1beta2", + Resource: "resourceclaims", + } + resourceClaimTemplateResourceV1Beta2 = metav1.GroupVersionResource{ + Group: "resource.k8s.io", + Version: "v1beta2", + Resource: "resourceclaimtemplates", + } +) + +var scheme = runtime.NewScheme() +var codecs = serializer.NewCodecFactory(scheme) + +func init() { + utilruntime.Must(admissionv1.AddToScheme(scheme)) + utilruntime.Must(resourcev1.AddToScheme(scheme)) + utilruntime.Must(resourcev1beta1.AddToScheme(scheme)) + utilruntime.Must(resourcev1beta2.AddToScheme(scheme)) +} + +// extractResourceClaim extracts and converts a ResourceClaim from an AdmissionReview to v1 format. +func extractResourceClaim(ar admissionv1.AdmissionReview) (*resourcev1.ResourceClaim, error) { + raw := ar.Request.Object.Raw + deserializer := codecs.UniversalDeserializer() + + // Decode to the appropriate version first + var obj runtime.Object + var err error + + switch ar.Request.Resource { + case resourceClaimResourceV1: + // Decode as v1 + obj = &resourcev1.ResourceClaim{} + case resourceClaimResourceV1Beta1: + // Decode as v1beta1 + obj = &resourcev1beta1.ResourceClaim{} + case resourceClaimResourceV1Beta2: + // Decode as v1beta2 + obj = &resourcev1beta2.ResourceClaim{} + default: + return nil, fmt.Errorf("unsupported resource version: %s", ar.Request.Resource) + } + + if _, _, err = deserializer.Decode(raw, nil, obj); err != nil { + return nil, err + } + + // Convert to v1 using Kubernetes conversion + var v1Claim resourcev1.ResourceClaim + if err := scheme.Convert(obj, &v1Claim, nil); err != nil { + return nil, fmt.Errorf("failed to convert to v1: %w", err) + } + + return &v1Claim, nil +} + +// extractResourceClaimTemplate extracts and converts a ResourceClaimTemplate from an AdmissionReview to v1 format. +func extractResourceClaimTemplate(ar admissionv1.AdmissionReview) (*resourcev1.ResourceClaimTemplate, error) { + raw := ar.Request.Object.Raw + deserializer := codecs.UniversalDeserializer() + + // Decode to the appropriate version first + var obj runtime.Object + var err error + + switch ar.Request.Resource { + case resourceClaimTemplateResourceV1: + // Decode as v1 + obj = &resourcev1.ResourceClaimTemplate{} + case resourceClaimTemplateResourceV1Beta1: + // Decode as v1beta1 + obj = &resourcev1beta1.ResourceClaimTemplate{} + case resourceClaimTemplateResourceV1Beta2: + // Decode as v1beta2 + obj = &resourcev1beta2.ResourceClaimTemplate{} + default: + return nil, fmt.Errorf("unsupported resource version: %s", ar.Request.Resource) + } + + if _, _, err = deserializer.Decode(raw, nil, obj); err != nil { + return nil, err + } + + // Convert to v1 using Kubernetes conversion + var v1Template resourcev1.ResourceClaimTemplate + if err := scheme.Convert(obj, &v1Template, nil); err != nil { + return nil, fmt.Errorf("failed to convert to v1: %w", err) + } + + return &v1Template, nil +} diff --git a/cmd/dra-example-webhook/resource_test.go b/cmd/dra-example-webhook/resource_test.go new file mode 100644 index 00000000..f996ce2b --- /dev/null +++ b/cmd/dra-example-webhook/resource_test.go @@ -0,0 +1,158 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + admissionv1 "k8s.io/api/admission/v1" + resourcev1 "k8s.io/api/resource/v1" + resourcev1beta1 "k8s.io/api/resource/v1beta1" + resourcev1beta2 "k8s.io/api/resource/v1beta2" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +func TestExtractResourceClaim(t *testing.T) { + // Create test objects for each version + v1Claim := &resourcev1.ResourceClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-v1-claim", + Namespace: "default", + }, + Spec: resourcev1.ResourceClaimSpec{ + Devices: resourcev1.DeviceClaim{ + Requests: []resourcev1.DeviceRequest{ + { + Name: "test-device", + Exactly: &resourcev1.ExactDeviceRequest{ + DeviceClassName: "test-class", + }, + }, + }, + }, + }, + } + + v1beta1Claim := &resourcev1beta1.ResourceClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-v1beta1-claim", + Namespace: "default", + }, + Spec: resourcev1beta1.ResourceClaimSpec{ + Devices: resourcev1beta1.DeviceClaim{ + Requests: []resourcev1beta1.DeviceRequest{ + { + Name: "test-device", + DeviceClassName: "test-class", + }, + }, + }, + }, + } + + v1beta2Claim := &resourcev1beta2.ResourceClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-v1beta2-claim", + Namespace: "default", + }, + Spec: resourcev1beta2.ResourceClaimSpec{ + Devices: resourcev1beta2.DeviceClaim{ + Requests: []resourcev1beta2.DeviceRequest{ + { + Name: "test-device", + Exactly: &resourcev1beta2.ExactDeviceRequest{ + DeviceClassName: "test-class", + }, + }, + }, + }, + }, + } + + tests := []struct { + name string + resource metav1.GroupVersionResource + obj runtime.Object + expectedName string + expectError bool + }{ + { + name: "v1 ResourceClaim", + resource: resourceClaimResourceV1, + obj: v1Claim, + expectedName: "test-v1-claim", + expectError: false, + }, + { + name: "v1beta1 ResourceClaim", + resource: resourceClaimResourceV1Beta1, + obj: v1beta1Claim, + expectedName: "test-v1beta1-claim", + expectError: false, + }, + { + name: "v1beta2 ResourceClaim", + resource: resourceClaimResourceV1Beta2, + obj: v1beta2Claim, + expectedName: "test-v1beta2-claim", + expectError: false, + }, + { + name: "Unsupported version", + resource: metav1.GroupVersionResource{Group: "resource.k8s.io", Version: "v2", Resource: "resourceclaims"}, + obj: v1Claim, + expectedName: "", + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Serialize the object + data, err := json.Marshal(tt.obj) + assert.NoError(t, err) + + // Create AdmissionReview + ar := admissionv1.AdmissionReview{ + Request: &admissionv1.AdmissionRequest{ + Resource: tt.resource, + Object: runtime.RawExtension{ + Raw: data, + }, + }, + } + + // Call the function + result, err := extractResourceClaim(ar) + + if tt.expectError { + assert.Error(t, err) + assert.Nil(t, result) + } else { + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, tt.expectedName, result.Name) + assert.Equal(t, "default", result.Namespace) + assert.Equal(t, "test-device", result.Spec.Devices.Requests[0].Name) + assert.Equal(t, "test-class", result.Spec.Devices.Requests[0].Exactly.DeviceClassName) + } + }) + } +} diff --git a/deployments/helm/dra-example-driver/templates/_helpers.tpl b/deployments/helm/dra-example-driver/templates/_helpers.tpl index 1f8a7100..63ec53df 100644 --- a/deployments/helm/dra-example-driver/templates/_helpers.tpl +++ b/deployments/helm/dra-example-driver/templates/_helpers.tpl @@ -106,3 +106,18 @@ Create the name of the service account to use for the webhook {{- default "default-webhook" .Values.webhook.serviceAccount.name }} {{- end }} {{- end }} + +{{/* +Get the latest available resource.k8s.io API version +Returns the highest available version or empty string if none found +*/}} +{{- define "dra-example-driver.resourceApiVersion" -}} +{{- if .Capabilities.APIVersions.Has "resource.k8s.io/v1" -}} +resource.k8s.io/v1 +{{- else if .Capabilities.APIVersions.Has "resource.k8s.io/v1beta2" -}} +resource.k8s.io/v1beta2 +{{- else if .Capabilities.APIVersions.Has "resource.k8s.io/v1beta1" -}} +resource.k8s.io/v1beta1 +{{- else -}} +{{- end -}} +{{- end -}} diff --git a/deployments/helm/dra-example-driver/templates/deviceclass.yaml b/deployments/helm/dra-example-driver/templates/deviceclass.yaml index 6a275aa5..8fd7085b 100644 --- a/deployments/helm/dra-example-driver/templates/deviceclass.yaml +++ b/deployments/helm/dra-example-driver/templates/deviceclass.yaml @@ -1,5 +1,5 @@ --- -apiVersion: resource.k8s.io/v1beta1 +apiVersion: {{ include "dra-example-driver.resourceApiVersion" . }} kind: DeviceClass metadata: name: gpu.example.com diff --git a/deployments/helm/dra-example-driver/templates/validatingadmissionpolicy.yaml b/deployments/helm/dra-example-driver/templates/validatingadmissionpolicy.yaml index 6de662ee..249d7c0d 100644 --- a/deployments/helm/dra-example-driver/templates/validatingadmissionpolicy.yaml +++ b/deployments/helm/dra-example-driver/templates/validatingadmissionpolicy.yaml @@ -7,7 +7,7 @@ spec: matchConstraints: resourceRules: - apiGroups: ["resource.k8s.io"] - apiVersions: ["v1beta1"] + apiVersions: ["v1beta1", "v1beta2", "v1"] operations: ["CREATE", "UPDATE", "DELETE"] resources: ["resourceslices"] matchConditions: diff --git a/deployments/helm/dra-example-driver/templates/validatingwebhookconfiguration.yaml b/deployments/helm/dra-example-driver/templates/validatingwebhookconfiguration.yaml index 4d5abef8..38a57347 100644 --- a/deployments/helm/dra-example-driver/templates/validatingwebhookconfiguration.yaml +++ b/deployments/helm/dra-example-driver/templates/validatingwebhookconfiguration.yaml @@ -12,7 +12,7 @@ webhooks: - name: "dra.example.com" rules: - apiGroups: ["resource.k8s.io"] - apiVersions: ["v1beta1"] + apiVersions: ["v1beta1", "v1beta2", "v1"] operations: ["CREATE", "UPDATE"] resources: ["resourceclaims", "resourceclaimtemplates"] scope: "Namespaced"