mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 11:50:44 +00:00
Merge pull request #82707 from liggitt/allow-1.16-review-versions
Allow v1 review versions in 1.17+
This commit is contained in:
commit
3ef3b6a5ba
@ -23,6 +23,7 @@ go_library(
|
|||||||
importpath = "k8s.io/kubernetes/pkg/apis/admissionregistration/validation",
|
importpath = "k8s.io/kubernetes/pkg/apis/admissionregistration/validation",
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/apis/admissionregistration:go_default_library",
|
"//pkg/apis/admissionregistration:go_default_library",
|
||||||
|
"//pkg/apis/admissionregistration/v1:go_default_library",
|
||||||
"//pkg/apis/admissionregistration/v1beta1:go_default_library",
|
"//pkg/apis/admissionregistration/v1beta1:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/api/validation:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/api/validation:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/validation:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/validation:go_default_library",
|
||||||
|
@ -28,7 +28,8 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
"k8s.io/apiserver/pkg/util/webhook"
|
"k8s.io/apiserver/pkg/util/webhook"
|
||||||
"k8s.io/kubernetes/pkg/apis/admissionregistration"
|
"k8s.io/kubernetes/pkg/apis/admissionregistration"
|
||||||
"k8s.io/kubernetes/pkg/apis/admissionregistration/v1beta1"
|
admissionregistrationv1 "k8s.io/kubernetes/pkg/apis/admissionregistration/v1"
|
||||||
|
admissionregistrationv1beta1 "k8s.io/kubernetes/pkg/apis/admissionregistration/v1beta1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func hasWildcard(slice []string) bool {
|
func hasWildcard(slice []string) bool {
|
||||||
@ -155,8 +156,8 @@ func validateRule(rule *admissionregistration.Rule, fldPath *field.Path, allowSu
|
|||||||
// AcceptedAdmissionReviewVersions contains the list of AdmissionReview versions the *prior* version of the API server understands.
|
// AcceptedAdmissionReviewVersions contains the list of AdmissionReview versions the *prior* version of the API server understands.
|
||||||
// 1.15: server understands v1beta1; accepted versions are ["v1beta1"]
|
// 1.15: server understands v1beta1; accepted versions are ["v1beta1"]
|
||||||
// 1.16: server understands v1, v1beta1; accepted versions are ["v1beta1"]
|
// 1.16: server understands v1, v1beta1; accepted versions are ["v1beta1"]
|
||||||
// 1.17: server understands v1, v1beta1; accepted versions are ["v1","v1beta1"]
|
// 1.17+: server understands v1, v1beta1; accepted versions are ["v1","v1beta1"]
|
||||||
var AcceptedAdmissionReviewVersions = []string{v1beta1.SchemeGroupVersion.Version}
|
var AcceptedAdmissionReviewVersions = []string{admissionregistrationv1.SchemeGroupVersion.Version, admissionregistrationv1beta1.SchemeGroupVersion.Version}
|
||||||
|
|
||||||
func isAcceptedAdmissionReviewVersion(v string) bool {
|
func isAcceptedAdmissionReviewVersion(v string) bool {
|
||||||
for _, version := range AcceptedAdmissionReviewVersions {
|
for _, version := range AcceptedAdmissionReviewVersions {
|
||||||
|
@ -65,7 +65,7 @@ func TestValidateValidatingWebhookConfiguration(t *testing.T) {
|
|||||||
SideEffects: &unknownSideEffect,
|
SideEffects: &unknownSideEffect,
|
||||||
},
|
},
|
||||||
}, false),
|
}, false),
|
||||||
expectedError: `webhooks[0].admissionReviewVersions: Required value: must specify one of v1beta1`,
|
expectedError: `webhooks[0].admissionReviewVersions: Required value: must specify one of v1, v1beta1`,
|
||||||
}, {
|
}, {
|
||||||
name: "should fail on bad AdmissionReviewVersion value",
|
name: "should fail on bad AdmissionReviewVersion value",
|
||||||
config: newValidatingWebhookConfiguration([]admissionregistration.ValidatingWebhook{
|
config: newValidatingWebhookConfiguration([]admissionregistration.ValidatingWebhook{
|
||||||
@ -415,7 +415,7 @@ func TestValidateValidatingWebhookConfiguration(t *testing.T) {
|
|||||||
SideEffects: &unknownSideEffect,
|
SideEffects: &unknownSideEffect,
|
||||||
},
|
},
|
||||||
}, false),
|
}, false),
|
||||||
expectedError: `webhooks[0].admissionReviewVersions: Required value: must specify one of v1beta1`,
|
expectedError: `webhooks[0].admissionReviewVersions: Required value: must specify one of v1, v1beta1`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "SideEffects are required",
|
name: "SideEffects are required",
|
||||||
@ -1034,7 +1034,7 @@ func TestValidateMutatingWebhookConfiguration(t *testing.T) {
|
|||||||
SideEffects: &unknownSideEffect,
|
SideEffects: &unknownSideEffect,
|
||||||
},
|
},
|
||||||
}, false),
|
}, false),
|
||||||
expectedError: `webhooks[0].admissionReviewVersions: Required value: must specify one of v1beta1`,
|
expectedError: `webhooks[0].admissionReviewVersions: Required value: must specify one of v1, v1beta1`,
|
||||||
}, {
|
}, {
|
||||||
name: "should fail on bad AdmissionReviewVersion value",
|
name: "should fail on bad AdmissionReviewVersion value",
|
||||||
config: newMutatingWebhookConfiguration([]admissionregistration.MutatingWebhook{
|
config: newMutatingWebhookConfiguration([]admissionregistration.MutatingWebhook{
|
||||||
@ -1384,7 +1384,7 @@ func TestValidateMutatingWebhookConfiguration(t *testing.T) {
|
|||||||
SideEffects: &unknownSideEffect,
|
SideEffects: &unknownSideEffect,
|
||||||
},
|
},
|
||||||
}, false),
|
}, false),
|
||||||
expectedError: `webhooks[0].admissionReviewVersions: Required value: must specify one of v1beta1`,
|
expectedError: `webhooks[0].admissionReviewVersions: Required value: must specify one of v1, v1beta1`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "SideEffects are required",
|
name: "SideEffects are required",
|
||||||
@ -1795,7 +1795,7 @@ func TestValidateMutatingWebhookConfigurationUpdate(t *testing.T) {
|
|||||||
expectedError string
|
expectedError string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "should pass on valid new AdmissionReviewVersion",
|
name: "should pass on valid new AdmissionReviewVersion (v1beta1)",
|
||||||
config: newMutatingWebhookConfiguration([]admissionregistration.MutatingWebhook{
|
config: newMutatingWebhookConfiguration([]admissionregistration.MutatingWebhook{
|
||||||
{
|
{
|
||||||
Name: "webhook.k8s.io",
|
Name: "webhook.k8s.io",
|
||||||
@ -1813,6 +1813,25 @@ func TestValidateMutatingWebhookConfigurationUpdate(t *testing.T) {
|
|||||||
}, true),
|
}, true),
|
||||||
expectedError: ``,
|
expectedError: ``,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "should pass on valid new AdmissionReviewVersion (v1)",
|
||||||
|
config: newMutatingWebhookConfiguration([]admissionregistration.MutatingWebhook{
|
||||||
|
{
|
||||||
|
Name: "webhook.k8s.io",
|
||||||
|
ClientConfig: validClientConfig,
|
||||||
|
SideEffects: &unknownSideEffect,
|
||||||
|
AdmissionReviewVersions: []string{"v1"},
|
||||||
|
},
|
||||||
|
}, true),
|
||||||
|
oldconfig: newMutatingWebhookConfiguration([]admissionregistration.MutatingWebhook{
|
||||||
|
{
|
||||||
|
Name: "webhook.k8s.io",
|
||||||
|
ClientConfig: validClientConfig,
|
||||||
|
SideEffects: &unknownSideEffect,
|
||||||
|
},
|
||||||
|
}, true),
|
||||||
|
expectedError: ``,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "should pass on invalid AdmissionReviewVersion with invalid previous versions",
|
name: "should pass on invalid AdmissionReviewVersion with invalid previous versions",
|
||||||
config: newMutatingWebhookConfiguration([]admissionregistration.MutatingWebhook{
|
config: newMutatingWebhookConfiguration([]admissionregistration.MutatingWebhook{
|
||||||
|
@ -14,6 +14,7 @@ go_library(
|
|||||||
deps = [
|
deps = [
|
||||||
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apihelpers:go_default_library",
|
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apihelpers:go_default_library",
|
||||||
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library",
|
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
|
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
|
||||||
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema:go_default_library",
|
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema:go_default_library",
|
||||||
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/defaulting:go_default_library",
|
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/defaulting:go_default_library",
|
||||||
|
@ -33,7 +33,8 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/util/webhook"
|
"k8s.io/apiserver/pkg/util/webhook"
|
||||||
|
|
||||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||||
|
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||||
structuralschema "k8s.io/apiextensions-apiserver/pkg/apiserver/schema"
|
structuralschema "k8s.io/apiextensions-apiserver/pkg/apiserver/schema"
|
||||||
apiservervalidation "k8s.io/apiextensions-apiserver/pkg/apiserver/validation"
|
apiservervalidation "k8s.io/apiextensions-apiserver/pkg/apiserver/validation"
|
||||||
apiextensionsfeatures "k8s.io/apiextensions-apiserver/pkg/features"
|
apiextensionsfeatures "k8s.io/apiextensions-apiserver/pkg/features"
|
||||||
@ -313,8 +314,8 @@ func validateEnumStrings(fldPath *field.Path, value string, accepted []string, r
|
|||||||
// AcceptedConversionReviewVersions contains the list of ConversionReview versions the *prior* version of the API server understands.
|
// AcceptedConversionReviewVersions contains the list of ConversionReview versions the *prior* version of the API server understands.
|
||||||
// 1.15: server understands v1beta1; accepted versions are ["v1beta1"]
|
// 1.15: server understands v1beta1; accepted versions are ["v1beta1"]
|
||||||
// 1.16: server understands v1, v1beta1; accepted versions are ["v1beta1"]
|
// 1.16: server understands v1, v1beta1; accepted versions are ["v1beta1"]
|
||||||
// TODO(liggitt): 1.17: server understands v1, v1beta1; accepted versions are ["v1","v1beta1"]
|
// 1.17+: server understands v1, v1beta1; accepted versions are ["v1","v1beta1"]
|
||||||
var acceptedConversionReviewVersions = sets.NewString(v1beta1.SchemeGroupVersion.Version)
|
var acceptedConversionReviewVersions = sets.NewString(apiextensionsv1.SchemeGroupVersion.Version, apiextensionsv1beta1.SchemeGroupVersion.Version)
|
||||||
|
|
||||||
func isAcceptedConversionReviewVersion(v string) bool {
|
func isAcceptedConversionReviewVersion(v string) bool {
|
||||||
return acceptedConversionReviewVersions.Has(v)
|
return acceptedConversionReviewVersions.Has(v)
|
||||||
@ -1007,7 +1008,7 @@ func allowedAtRootSchema(field string) bool {
|
|||||||
|
|
||||||
// requireOpenAPISchema returns true if the request group version requires a schema
|
// requireOpenAPISchema returns true if the request group version requires a schema
|
||||||
func requireOpenAPISchema(requestGV schema.GroupVersion, oldCRDSpec *apiextensions.CustomResourceDefinitionSpec) bool {
|
func requireOpenAPISchema(requestGV schema.GroupVersion, oldCRDSpec *apiextensions.CustomResourceDefinitionSpec) bool {
|
||||||
if requestGV == v1beta1.SchemeGroupVersion {
|
if requestGV == apiextensionsv1beta1.SchemeGroupVersion {
|
||||||
// for backwards compatibility
|
// for backwards compatibility
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -1038,7 +1039,7 @@ func allowDefaults(requestGV schema.GroupVersion, oldCRDSpec *apiextensions.Cust
|
|||||||
if !utilfeature.DefaultFeatureGate.Enabled(apiextensionsfeatures.CustomResourceDefaulting) {
|
if !utilfeature.DefaultFeatureGate.Enabled(apiextensionsfeatures.CustomResourceDefaulting) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if requestGV == v1beta1.SchemeGroupVersion {
|
if requestGV == apiextensionsv1beta1.SchemeGroupVersion {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@ -1212,7 +1213,7 @@ func schemaHasKubernetesExtensions(s *apiextensions.JSONSchemaProps) bool {
|
|||||||
|
|
||||||
// requireStructuralSchema returns true if schemas specified must be structural
|
// requireStructuralSchema returns true if schemas specified must be structural
|
||||||
func requireStructuralSchema(requestGV schema.GroupVersion, oldCRDSpec *apiextensions.CustomResourceDefinitionSpec) bool {
|
func requireStructuralSchema(requestGV schema.GroupVersion, oldCRDSpec *apiextensions.CustomResourceDefinitionSpec) bool {
|
||||||
if requestGV == v1beta1.SchemeGroupVersion {
|
if requestGV == apiextensionsv1beta1.SchemeGroupVersion {
|
||||||
// for compatibility
|
// for compatibility
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -1282,7 +1283,7 @@ func schemaHasUnprunedDefaults(schema *apiextensions.JSONSchemaProps) (bool, err
|
|||||||
|
|
||||||
// requireValidPropertyType returns true if valid openapi v3 types should be required for the given API version
|
// requireValidPropertyType returns true if valid openapi v3 types should be required for the given API version
|
||||||
func requireValidPropertyType(requestGV schema.GroupVersion, oldCRDSpec *apiextensions.CustomResourceDefinitionSpec) bool {
|
func requireValidPropertyType(requestGV schema.GroupVersion, oldCRDSpec *apiextensions.CustomResourceDefinitionSpec) bool {
|
||||||
if requestGV == v1beta1.SchemeGroupVersion {
|
if requestGV == apiextensionsv1beta1.SchemeGroupVersion {
|
||||||
// for compatibility
|
// for compatibility
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -1297,7 +1298,7 @@ func requireValidPropertyType(requestGV schema.GroupVersion, oldCRDSpec *apiexte
|
|||||||
func validateAPIApproval(newCRD, oldCRD *apiextensions.CustomResourceDefinition, requestGV schema.GroupVersion) field.ErrorList {
|
func validateAPIApproval(newCRD, oldCRD *apiextensions.CustomResourceDefinition, requestGV schema.GroupVersion) field.ErrorList {
|
||||||
// check to see if we need confirm API approval for kube group.
|
// check to see if we need confirm API approval for kube group.
|
||||||
|
|
||||||
if requestGV == v1beta1.SchemeGroupVersion {
|
if requestGV == apiextensionsv1beta1.SchemeGroupVersion {
|
||||||
// no-op for compatibility with v1beta1
|
// no-op for compatibility with v1beta1
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -1323,19 +1324,19 @@ func validateAPIApproval(newCRD, oldCRD *apiextensions.CustomResourceDefinition,
|
|||||||
// in v1, we require valid approval strings
|
// in v1, we require valid approval strings
|
||||||
switch newApprovalState {
|
switch newApprovalState {
|
||||||
case apihelpers.APIApprovalInvalid:
|
case apihelpers.APIApprovalInvalid:
|
||||||
return field.ErrorList{field.Invalid(field.NewPath("metadata", "annotations").Key(v1beta1.KubeAPIApprovedAnnotation), newCRD.Annotations[v1beta1.KubeAPIApprovedAnnotation], reason)}
|
return field.ErrorList{field.Invalid(field.NewPath("metadata", "annotations").Key(apiextensionsv1beta1.KubeAPIApprovedAnnotation), newCRD.Annotations[apiextensionsv1beta1.KubeAPIApprovedAnnotation], reason)}
|
||||||
case apihelpers.APIApprovalMissing:
|
case apihelpers.APIApprovalMissing:
|
||||||
return field.ErrorList{field.Required(field.NewPath("metadata", "annotations").Key(v1beta1.KubeAPIApprovedAnnotation), reason)}
|
return field.ErrorList{field.Required(field.NewPath("metadata", "annotations").Key(apiextensionsv1beta1.KubeAPIApprovedAnnotation), reason)}
|
||||||
case apihelpers.APIApproved, apihelpers.APIApprovalBypassed:
|
case apihelpers.APIApproved, apihelpers.APIApprovalBypassed:
|
||||||
// success
|
// success
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
return field.ErrorList{field.Invalid(field.NewPath("metadata", "annotations").Key(v1beta1.KubeAPIApprovedAnnotation), newCRD.Annotations[v1beta1.KubeAPIApprovedAnnotation], reason)}
|
return field.ErrorList{field.Invalid(field.NewPath("metadata", "annotations").Key(apiextensionsv1beta1.KubeAPIApprovedAnnotation), newCRD.Annotations[apiextensionsv1beta1.KubeAPIApprovedAnnotation], reason)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func validatePreserveUnknownFields(crd, oldCRD *apiextensions.CustomResourceDefinition, requestGV schema.GroupVersion) field.ErrorList {
|
func validatePreserveUnknownFields(crd, oldCRD *apiextensions.CustomResourceDefinition, requestGV schema.GroupVersion) field.ErrorList {
|
||||||
if requestGV == v1beta1.SchemeGroupVersion {
|
if requestGV == apiextensionsv1beta1.SchemeGroupVersion {
|
||||||
// no-op for compatibility with v1beta1
|
// no-op for compatibility with v1beta1
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -780,7 +780,7 @@ func TestValidateCustomResourceDefinition(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "webhook conversion with preserveUnknownFields=false",
|
name: "webhook conversion with preserveUnknownFields=false, conversionReviewVersions=[v1beta1]",
|
||||||
resource: &apiextensions.CustomResourceDefinition{
|
resource: &apiextensions.CustomResourceDefinition{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com"},
|
ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com"},
|
||||||
Spec: apiextensions.CustomResourceDefinitionSpec{
|
Spec: apiextensions.CustomResourceDefinitionSpec{
|
||||||
@ -824,6 +824,51 @@ func TestValidateCustomResourceDefinition(t *testing.T) {
|
|||||||
},
|
},
|
||||||
errors: []validationMatch{},
|
errors: []validationMatch{},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "webhook conversion with preserveUnknownFields=false, conversionReviewVersions=[v1]",
|
||||||
|
resource: &apiextensions.CustomResourceDefinition{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com"},
|
||||||
|
Spec: apiextensions.CustomResourceDefinitionSpec{
|
||||||
|
Group: "group.com",
|
||||||
|
Scope: apiextensions.ResourceScope("Cluster"),
|
||||||
|
Names: apiextensions.CustomResourceDefinitionNames{
|
||||||
|
Plural: "plural",
|
||||||
|
Singular: "singular",
|
||||||
|
Kind: "Plural",
|
||||||
|
ListKind: "PluralList",
|
||||||
|
},
|
||||||
|
Versions: []apiextensions.CustomResourceDefinitionVersion{
|
||||||
|
{
|
||||||
|
Name: "version1",
|
||||||
|
Served: true,
|
||||||
|
Storage: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "version2",
|
||||||
|
Served: true,
|
||||||
|
Storage: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Conversion: &apiextensions.CustomResourceConversion{
|
||||||
|
Strategy: apiextensions.ConversionStrategyType("Webhook"),
|
||||||
|
WebhookClientConfig: &apiextensions.WebhookClientConfig{
|
||||||
|
URL: strPtr("https://example.com/webhook"),
|
||||||
|
},
|
||||||
|
ConversionReviewVersions: []string{"v1"},
|
||||||
|
},
|
||||||
|
Validation: &apiextensions.CustomResourceValidation{
|
||||||
|
OpenAPIV3Schema: &apiextensions.JSONSchemaProps{
|
||||||
|
Type: "object",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreserveUnknownFields: pointer.BoolPtr(false),
|
||||||
|
},
|
||||||
|
Status: apiextensions.CustomResourceDefinitionStatus{
|
||||||
|
StoredVersions: []string{"version1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errors: []validationMatch{},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "no_storage_version",
|
name: "no_storage_version",
|
||||||
resource: &apiextensions.CustomResourceDefinition{
|
resource: &apiextensions.CustomResourceDefinition{
|
||||||
|
Loading…
Reference in New Issue
Block a user