mirror of
https://github.com/kubernetes/kubernetes.git
synced 2026-02-03 20:40:26 -05:00
Merge pull request #134072 from yongruilin/master_vg_enable-resourceclaim
Enable Declarative Validation for resource.k8s.io v1/v1beta1/v1beta2
This commit is contained in:
commit
ec4e321f00
9 changed files with 259 additions and 2 deletions
|
|
@ -35,6 +35,9 @@ func TestVersionedValidationByFuzzing(t *testing.T) {
|
|||
{Group: "certificates.k8s.io", Version: "v1"},
|
||||
{Group: "certificates.k8s.io", Version: "v1alpha1"},
|
||||
{Group: "certificates.k8s.io", Version: "v1beta1"},
|
||||
{Group: "resource.k8s.io", Version: "v1beta1"},
|
||||
{Group: "resource.k8s.io", Version: "v1beta2"},
|
||||
{Group: "resource.k8s.io", Version: "v1"},
|
||||
}
|
||||
|
||||
for _, gv := range typesWithDeclarativeValidation {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ limitations under the License.
|
|||
// +k8s:conversion-gen-external-types=k8s.io/api/resource/v1
|
||||
// +k8s:defaulter-gen=TypeMeta
|
||||
// +k8s:defaulter-gen-input=k8s.io/api/resource/v1
|
||||
// +k8s:validation-gen=TypeMeta
|
||||
// +k8s:validation-gen-input=k8s.io/api/resource/v1
|
||||
|
||||
// Package v1 is the v1 version of the resource API.
|
||||
package v1
|
||||
|
|
|
|||
34
pkg/apis/resource/v1/zz_generated.validations.go
generated
Normal file
34
pkg/apis/resource/v1/zz_generated.validations.go
generated
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
//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 validation-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
func init() { localSchemeBuilder.Register(RegisterValidations) }
|
||||
|
||||
// RegisterValidations adds validation functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
func RegisterValidations(scheme *runtime.Scheme) error {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -18,6 +18,8 @@ limitations under the License.
|
|||
// +k8s:conversion-gen-external-types=k8s.io/api/resource/v1beta1
|
||||
// +k8s:defaulter-gen=TypeMeta
|
||||
// +k8s:defaulter-gen-input=k8s.io/api/resource/v1beta1
|
||||
// +k8s:validation-gen=TypeMeta
|
||||
// +k8s:validation-gen-input=k8s.io/api/resource/v1beta1
|
||||
|
||||
// Package v1beta1 is the v1beta1 version of the resource API.
|
||||
package v1beta1
|
||||
|
|
|
|||
34
pkg/apis/resource/v1beta1/zz_generated.validations.go
generated
Normal file
34
pkg/apis/resource/v1beta1/zz_generated.validations.go
generated
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
//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 validation-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
func init() { localSchemeBuilder.Register(RegisterValidations) }
|
||||
|
||||
// RegisterValidations adds validation functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
func RegisterValidations(scheme *runtime.Scheme) error {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -18,6 +18,8 @@ limitations under the License.
|
|||
// +k8s:conversion-gen-external-types=k8s.io/api/resource/v1beta2
|
||||
// +k8s:defaulter-gen=TypeMeta
|
||||
// +k8s:defaulter-gen-input=k8s.io/api/resource/v1beta2
|
||||
// +k8s:validation-gen=TypeMeta
|
||||
// +k8s:validation-gen-input=k8s.io/api/resource/v1beta2
|
||||
|
||||
// Package v1beta2 is the v1beta2 version of the resource API.
|
||||
package v1beta2
|
||||
|
|
|
|||
34
pkg/apis/resource/v1beta2/zz_generated.validations.go
generated
Normal file
34
pkg/apis/resource/v1beta2/zz_generated.validations.go
generated
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
//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 validation-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta2
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
func init() { localSchemeBuilder.Register(RegisterValidations) }
|
||||
|
||||
// RegisterValidations adds validation functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
func RegisterValidations(scheme *runtime.Scheme) error {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
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 resourceclaim
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
"k8s.io/kubernetes/pkg/apis/resource"
|
||||
)
|
||||
|
||||
var apiVersions = []string{"v1beta1", "v1beta2", "v1"} // "v1alpha3" is excluded because it doesn't have ResourceClaim
|
||||
|
||||
func TestDeclarativeValidate(t *testing.T) {
|
||||
for _, apiVersion := range apiVersions {
|
||||
t.Run(apiVersion, func(t *testing.T) {
|
||||
testDeclarativeValidate(t, apiVersion)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testDeclarativeValidate(t *testing.T, apiVersion string) {
|
||||
ctx := genericapirequest.WithRequestInfo(genericapirequest.NewDefaultContext(), &genericapirequest.RequestInfo{
|
||||
APIGroup: "resource.k8s.io",
|
||||
APIVersion: apiVersion,
|
||||
Resource: "resourceclaims",
|
||||
})
|
||||
fakeClient := fake.NewClientset()
|
||||
mockNSClient := fakeClient.CoreV1().Namespaces()
|
||||
Strategy := NewStrategy(mockNSClient)
|
||||
testCases := map[string]struct {
|
||||
input resource.ResourceClaim
|
||||
expectedErrs field.ErrorList
|
||||
}{
|
||||
"valid": {
|
||||
input: mkValidResourceClaim(),
|
||||
},
|
||||
// TODO: Add more test cases
|
||||
}
|
||||
for k, tc := range testCases {
|
||||
t.Run(k, func(t *testing.T) {
|
||||
apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy.Validate, tc.expectedErrs)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeclarativeValidateUpdate(t *testing.T) {
|
||||
for _, apiVersion := range apiVersions {
|
||||
t.Run(apiVersion, func(t *testing.T) {
|
||||
testDeclarativeValidateUpdate(t, apiVersion)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testDeclarativeValidateUpdate(t *testing.T, apiVersion string) {
|
||||
ctx := genericapirequest.WithRequestInfo(genericapirequest.NewDefaultContext(), &genericapirequest.RequestInfo{
|
||||
APIGroup: "resource.k8s.io",
|
||||
APIVersion: apiVersion,
|
||||
Resource: "resourceclaims",
|
||||
})
|
||||
fakeClient := fake.NewClientset()
|
||||
mockNSClient := fakeClient.CoreV1().Namespaces()
|
||||
Strategy := NewStrategy(mockNSClient)
|
||||
validClaim := mkValidResourceClaim()
|
||||
testCases := map[string]struct {
|
||||
update resource.ResourceClaim
|
||||
old resource.ResourceClaim
|
||||
expectedErrs field.ErrorList
|
||||
}{
|
||||
"valid": {
|
||||
update: validClaim,
|
||||
old: validClaim,
|
||||
},
|
||||
// TODO: Add more test cases
|
||||
}
|
||||
for k, tc := range testCases {
|
||||
t.Run(k, func(t *testing.T) {
|
||||
tc.old.ResourceVersion = "1"
|
||||
tc.update.ResourceVersion = "2"
|
||||
apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.update, &tc.old, Strategy.ValidateUpdate, tc.expectedErrs)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func mkValidResourceClaim() resource.ResourceClaim {
|
||||
return resource.ResourceClaim{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "valid-claim",
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: resource.ResourceClaimSpec{
|
||||
Devices: resource.DeviceClaim{
|
||||
Requests: []resource.DeviceRequest{
|
||||
{
|
||||
Name: "req-0",
|
||||
Exactly: &resource.ExactDeviceRequest{
|
||||
DeviceClassName: "class",
|
||||
AllocationMode: resource.DeviceAllocationModeAll,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -28,6 +28,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
"k8s.io/apiserver/pkg/storage"
|
||||
"k8s.io/apiserver/pkg/storage/names"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
|
|
@ -96,7 +97,18 @@ func (s *resourceclaimStrategy) Validate(ctx context.Context, obj runtime.Object
|
|||
claim := obj.(*resource.ResourceClaim)
|
||||
|
||||
allErrs := resourceutils.AuthorizedForAdmin(ctx, claim.Spec.Devices.Requests, claim.Namespace, s.nsClient)
|
||||
return append(allErrs, validation.ValidateResourceClaim(claim)...)
|
||||
allErrs = append(allErrs, validation.ValidateResourceClaim(claim)...)
|
||||
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.DeclarativeValidation) {
|
||||
takeover := utilfeature.DefaultFeatureGate.Enabled(features.DeclarativeValidationTakeover)
|
||||
const validationIdentifier = "resourceclaim_create"
|
||||
declarativeErrs := rest.ValidateDeclaratively(ctx, legacyscheme.Scheme, claim, rest.WithTakeover(takeover), rest.WithValidationIdentifier(validationIdentifier))
|
||||
rest.CompareDeclarativeErrorsAndEmitMismatches(ctx, allErrs, declarativeErrs, takeover, validationIdentifier)
|
||||
if takeover {
|
||||
allErrs = append(allErrs.RemoveCoveredByDeclarative(), declarativeErrs...)
|
||||
}
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func (*resourceclaimStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
|
|
@ -123,7 +135,18 @@ func (s *resourceclaimStrategy) ValidateUpdate(ctx context.Context, obj, old run
|
|||
oldClaim := old.(*resource.ResourceClaim)
|
||||
// AuthorizedForAdmin isn't needed here because the spec is immutable.
|
||||
errorList := validation.ValidateResourceClaim(newClaim)
|
||||
return append(errorList, validation.ValidateResourceClaimUpdate(newClaim, oldClaim)...)
|
||||
errorList = append(errorList, validation.ValidateResourceClaimUpdate(newClaim, oldClaim)...)
|
||||
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.DeclarativeValidation) {
|
||||
takeover := utilfeature.DefaultFeatureGate.Enabled(features.DeclarativeValidationTakeover)
|
||||
const validationIdentifier = "resourceclaim_update"
|
||||
declarativeErrs := rest.ValidateUpdateDeclaratively(ctx, legacyscheme.Scheme, newClaim, oldClaim, rest.WithTakeover(takeover), rest.WithValidationIdentifier(validationIdentifier))
|
||||
rest.CompareDeclarativeErrorsAndEmitMismatches(ctx, errorList, declarativeErrs, takeover, validationIdentifier)
|
||||
if takeover {
|
||||
errorList = append(errorList.RemoveCoveredByDeclarative(), declarativeErrs...)
|
||||
}
|
||||
}
|
||||
return errorList
|
||||
}
|
||||
|
||||
func (*resourceclaimStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
|
|
|
|||
Loading…
Reference in a new issue