diff --git a/pkg/api/defaulting_test.go b/pkg/api/defaulting_test.go index d0a87923f52..d5e61c01b30 100644 --- a/pkg/api/defaulting_test.go +++ b/pkg/api/defaulting_test.go @@ -54,47 +54,49 @@ func TestVerifyDefaulting(t *testing.T) { func TestDefaulting(t *testing.T) { // these are the known types with defaulters - you must add to this list if you add a top level defaulter typesWithDefaulting := map[schema.GroupVersionKind]struct{}{ - {Group: "", Version: "v1", Kind: "ConfigMap"}: {}, - {Group: "", Version: "v1", Kind: "ConfigMapList"}: {}, - {Group: "", Version: "v1", Kind: "Endpoints"}: {}, - {Group: "", Version: "v1", Kind: "EndpointsList"}: {}, - {Group: "", Version: "v1", Kind: "Namespace"}: {}, - {Group: "", Version: "v1", Kind: "NamespaceList"}: {}, - {Group: "", Version: "v1", Kind: "Node"}: {}, - {Group: "", Version: "v1", Kind: "NodeList"}: {}, - {Group: "", Version: "v1", Kind: "PersistentVolume"}: {}, - {Group: "", Version: "v1", Kind: "PersistentVolumeList"}: {}, - {Group: "", Version: "v1", Kind: "PersistentVolumeClaim"}: {}, - {Group: "", Version: "v1", Kind: "PersistentVolumeClaimList"}: {}, - {Group: "", Version: "v1", Kind: "PodAttachOptions"}: {}, - {Group: "", Version: "v1", Kind: "PodExecOptions"}: {}, - {Group: "", Version: "v1", Kind: "Pod"}: {}, - {Group: "", Version: "v1", Kind: "PodList"}: {}, - {Group: "", Version: "v1", Kind: "PodTemplate"}: {}, - {Group: "", Version: "v1", Kind: "PodTemplateList"}: {}, - {Group: "", Version: "v1", Kind: "ReplicationController"}: {}, - {Group: "", Version: "v1", Kind: "ReplicationControllerList"}: {}, - {Group: "", Version: "v1", Kind: "Secret"}: {}, - {Group: "", Version: "v1", Kind: "SecretList"}: {}, - {Group: "", Version: "v1", Kind: "Service"}: {}, - {Group: "", Version: "v1", Kind: "ServiceList"}: {}, - {Group: "apps", Version: "v1beta1", Kind: "StatefulSet"}: {}, - {Group: "apps", Version: "v1beta1", Kind: "StatefulSetList"}: {}, - {Group: "autoscaling", Version: "v1", Kind: "HorizontalPodAutoscaler"}: {}, - {Group: "autoscaling", Version: "v1", Kind: "HorizontalPodAutoscalerList"}: {}, - {Group: "batch", Version: "v1", Kind: "Job"}: {}, - {Group: "batch", Version: "v1", Kind: "JobList"}: {}, - {Group: "batch", Version: "v2alpha1", Kind: "CronJob"}: {}, - {Group: "batch", Version: "v2alpha1", Kind: "CronJobList"}: {}, - {Group: "batch", Version: "v2alpha1", Kind: "Job"}: {}, - {Group: "batch", Version: "v2alpha1", Kind: "JobList"}: {}, - {Group: "batch", Version: "v2alpha1", Kind: "JobTemplate"}: {}, - {Group: "batch", Version: "v2alpha1", Kind: "ScheduledJob"}: {}, - {Group: "batch", Version: "v2alpha1", Kind: "ScheduledJobList"}: {}, - {Group: "componentconfig", Version: "v1alpha1", Kind: "KubeProxyConfiguration"}: {}, - {Group: "componentconfig", Version: "v1alpha1", Kind: "KubeSchedulerConfiguration"}: {}, - {Group: "componentconfig", Version: "v1alpha1", Kind: "KubeletConfiguration"}: {}, - {Group: "kubeadm.k8s.io", Version: "v1alpha1", Kind: "MasterConfiguration"}: {}, + {Group: "", Version: "v1", Kind: "ConfigMap"}: {}, + {Group: "", Version: "v1", Kind: "ConfigMapList"}: {}, + {Group: "", Version: "v1", Kind: "Endpoints"}: {}, + {Group: "", Version: "v1", Kind: "EndpointsList"}: {}, + {Group: "", Version: "v1", Kind: "Namespace"}: {}, + {Group: "", Version: "v1", Kind: "NamespaceList"}: {}, + {Group: "", Version: "v1", Kind: "Node"}: {}, + {Group: "", Version: "v1", Kind: "NodeList"}: {}, + {Group: "", Version: "v1", Kind: "PersistentVolume"}: {}, + {Group: "", Version: "v1", Kind: "PersistentVolumeList"}: {}, + {Group: "", Version: "v1", Kind: "PersistentVolumeClaim"}: {}, + {Group: "", Version: "v1", Kind: "PersistentVolumeClaimList"}: {}, + {Group: "", Version: "v1", Kind: "PodAttachOptions"}: {}, + {Group: "", Version: "v1", Kind: "PodExecOptions"}: {}, + {Group: "", Version: "v1", Kind: "Pod"}: {}, + {Group: "", Version: "v1", Kind: "PodList"}: {}, + {Group: "", Version: "v1", Kind: "PodTemplate"}: {}, + {Group: "", Version: "v1", Kind: "PodTemplateList"}: {}, + {Group: "", Version: "v1", Kind: "ReplicationController"}: {}, + {Group: "", Version: "v1", Kind: "ReplicationControllerList"}: {}, + {Group: "", Version: "v1", Kind: "Secret"}: {}, + {Group: "", Version: "v1", Kind: "SecretList"}: {}, + {Group: "", Version: "v1", Kind: "Service"}: {}, + {Group: "", Version: "v1", Kind: "ServiceList"}: {}, + {Group: "apps", Version: "v1beta1", Kind: "StatefulSet"}: {}, + {Group: "apps", Version: "v1beta1", Kind: "StatefulSetList"}: {}, + {Group: "autoscaling", Version: "v1", Kind: "HorizontalPodAutoscaler"}: {}, + {Group: "autoscaling", Version: "v1", Kind: "HorizontalPodAutoscalerList"}: {}, + {Group: "batch", Version: "v1", Kind: "Job"}: {}, + {Group: "batch", Version: "v1", Kind: "JobList"}: {}, + {Group: "batch", Version: "v2alpha1", Kind: "CronJob"}: {}, + {Group: "batch", Version: "v2alpha1", Kind: "CronJobList"}: {}, + {Group: "batch", Version: "v2alpha1", Kind: "Job"}: {}, + {Group: "batch", Version: "v2alpha1", Kind: "JobList"}: {}, + {Group: "batch", Version: "v2alpha1", Kind: "JobTemplate"}: {}, + {Group: "batch", Version: "v2alpha1", Kind: "ScheduledJob"}: {}, + {Group: "batch", Version: "v2alpha1", Kind: "ScheduledJobList"}: {}, + {Group: "certificates.k8s.io", Version: "v1alpha1", Kind: "CertificateSigningRequest"}: {}, + {Group: "certificates.k8s.io", Version: "v1alpha1", Kind: "CertificateSigningRequestList"}: {}, + {Group: "componentconfig", Version: "v1alpha1", Kind: "KubeProxyConfiguration"}: {}, + {Group: "componentconfig", Version: "v1alpha1", Kind: "KubeSchedulerConfiguration"}: {}, + {Group: "componentconfig", Version: "v1alpha1", Kind: "KubeletConfiguration"}: {}, + {Group: "kubeadm.k8s.io", Version: "v1alpha1", Kind: "MasterConfiguration"}: {}, // This object contains only int fields which currently breaks the defaulting test because // it's pretty stupid. Once we add non integer fields, we should uncomment this. // {Group: "kubeadm.k8s.io", Version: "v1alpha1", Kind: "NodeConfiguration"}: {}, diff --git a/pkg/api/testing/BUILD b/pkg/api/testing/BUILD index 0db0b5831ef..67bc91d959a 100644 --- a/pkg/api/testing/BUILD +++ b/pkg/api/testing/BUILD @@ -23,6 +23,7 @@ go_library( "//pkg/api/v1:go_default_library", "//pkg/apis/autoscaling:go_default_library", "//pkg/apis/batch:go_default_library", + "//pkg/apis/certificates:go_default_library", "//pkg/apis/extensions:go_default_library", "//pkg/apis/policy:go_default_library", "//pkg/apis/rbac:go_default_library", diff --git a/pkg/api/testing/fuzzer.go b/pkg/api/testing/fuzzer.go index 7e6916600c7..c2736c690c2 100644 --- a/pkg/api/testing/fuzzer.go +++ b/pkg/api/testing/fuzzer.go @@ -34,6 +34,7 @@ import ( "k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/apis/batch" + "k8s.io/kubernetes/pkg/apis/certificates" "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/policy" "k8s.io/kubernetes/pkg/apis/rbac" @@ -567,6 +568,10 @@ func FuzzerFor(t *testing.T, version schema.GroupVersion, src rand.Source) *fuzz c.FuzzNoCustom(s) // fuzz self without calling this function again s.PodDisruptionsAllowed = int32(c.Rand.Intn(2)) }, + func(obj *certificates.CertificateSigningRequestSpec, c fuzz.Continue) { + c.FuzzNoCustom(obj) // fuzz self without calling this function again + obj.Usages = []certificates.KeyUsage{certificates.UsageKeyEncipherment} + }, ) return f } diff --git a/pkg/apis/certificates/v1alpha1/BUILD b/pkg/apis/certificates/v1alpha1/BUILD index e376ad8250e..1bd3e0ce870 100644 --- a/pkg/apis/certificates/v1alpha1/BUILD +++ b/pkg/apis/certificates/v1alpha1/BUILD @@ -11,6 +11,7 @@ go_library( name = "go_default_library", srcs = [ "conversion.go", + "defaults.go", "doc.go", "generated.pb.go", "register.go", diff --git a/pkg/apis/certificates/v1alpha1/defaults.go b/pkg/apis/certificates/v1alpha1/defaults.go new file mode 100644 index 00000000000..d4bea72072d --- /dev/null +++ b/pkg/apis/certificates/v1alpha1/defaults.go @@ -0,0 +1,31 @@ +/* +Copyright 2017 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/apimachinery/pkg/runtime" + +func addDefaultingFuncs(scheme *runtime.Scheme) error { + RegisterDefaults(scheme) + return scheme.AddDefaultingFuncs( + SetDefaults_CertificateSigningRequestSpec, + ) +} +func SetDefaults_CertificateSigningRequestSpec(obj *CertificateSigningRequestSpec) { + if obj.Usages == nil { + obj.Usages = []KeyUsage{UsageDigitalSignature, UsageKeyEncipherment} + } +} diff --git a/pkg/apis/certificates/v1alpha1/register.go b/pkg/apis/certificates/v1alpha1/register.go index e0e871855b0..7c0410b362e 100644 --- a/pkg/apis/certificates/v1alpha1/register.go +++ b/pkg/apis/certificates/v1alpha1/register.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors. +Copyright 2017 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. @@ -40,7 +40,7 @@ func Resource(resource string) schema.GroupResource { } var ( - SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addConversionFuncs) + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addConversionFuncs, addDefaultingFuncs) AddToScheme = SchemeBuilder.AddToScheme ) diff --git a/pkg/apis/certificates/validation/validation.go b/pkg/apis/certificates/validation/validation.go index 3d6e19f40ea..494045cf7b8 100644 --- a/pkg/apis/certificates/validation/validation.go +++ b/pkg/apis/certificates/validation/validation.go @@ -50,8 +50,14 @@ func ValidateCertificateSigningRequest(csr *certificates.CertificateSigningReque isNamespaced := false allErrs := apivalidation.ValidateObjectMeta(&csr.ObjectMeta, isNamespaced, ValidateCertificateRequestName, field.NewPath("metadata")) err := validateCSR(csr) + + specPath := field.NewPath("spec") + if err != nil { - allErrs = append(allErrs, field.Invalid(field.NewPath("request"), csr.Spec.Request, fmt.Sprintf("%v", err))) + allErrs = append(allErrs, field.Invalid(specPath.Child("request"), csr.Spec.Request, fmt.Sprintf("%v", err))) + } + if len(csr.Spec.Usages) == 0 { + allErrs = append(allErrs, field.Required(specPath.Child("usages"), "usages must be provided")) } return allErrs }