Skip to content

Commit

Permalink
Add validation of Kubernetes feature gates
Browse files Browse the repository at this point in the history
  • Loading branch information
stoyanr committed Jun 8, 2021
1 parent 4d8c1f3 commit ae6cef4
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 7 deletions.
2 changes: 1 addition & 1 deletion pkg/admission/validator/shoot.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ func (s *shoot) validateContext(valContext *validationContext) field.ErrorList {
allErrors = append(allErrors, gcpvalidation.ValidateNetworking(valContext.shoot.Spec.Networking, networkPath)...)
allErrors = append(allErrors, gcpvalidation.ValidateInfrastructureConfig(valContext.infrastructureConfig, valContext.shoot.Spec.Networking.Nodes, valContext.shoot.Spec.Networking.Pods, valContext.shoot.Spec.Networking.Services, infrastructureConfigPath)...)
allErrors = append(allErrors, gcpvalidation.ValidateWorkers(valContext.shoot.Spec.Provider.Workers, workersPath)...)
allErrors = append(allErrors, gcpvalidation.ValidateControlPlaneConfig(valContext.controlPlaneConfig, allowedZones, workersZones(valContext.shoot.Spec.Provider.Workers), controlPlaneConfigPath)...)
allErrors = append(allErrors, gcpvalidation.ValidateControlPlaneConfig(valContext.controlPlaneConfig, allowedZones, workersZones(valContext.shoot.Spec.Provider.Workers), valContext.shoot.Spec.Kubernetes.Version, controlPlaneConfigPath)...)

// WorkerConfig
for i, worker := range valContext.shoot.Spec.Provider.Workers {
Expand Down
10 changes: 8 additions & 2 deletions pkg/apis/gcp/validation/controlplane.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ package validation

import (
apisgcp "github.com/gardener/gardener-extension-provider-gcp/pkg/apis/gcp"
"k8s.io/apimachinery/pkg/util/sets"

corevalidation "github.com/gardener/gardener/pkg/apis/core/validation"
apivalidation "k8s.io/apimachinery/pkg/api/validation"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation/field"
)

// ValidateControlPlaneConfig validates a ControlPlaneConfig object.
func ValidateControlPlaneConfig(controlPlaneConfig *apisgcp.ControlPlaneConfig, allowedZones, workerZones sets.String, fldPath *field.Path) field.ErrorList {
func ValidateControlPlaneConfig(controlPlaneConfig *apisgcp.ControlPlaneConfig, allowedZones, workerZones sets.String, version string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}

if len(controlPlaneConfig.Zone) == 0 {
Expand All @@ -35,6 +36,11 @@ func ValidateControlPlaneConfig(controlPlaneConfig *apisgcp.ControlPlaneConfig,
if !workerZones.Has(controlPlaneConfig.Zone) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("zone"), controlPlaneConfig.Zone, "must be part of at least one worker zone"))
}

if controlPlaneConfig.CloudControllerManager != nil {
allErrs = append(allErrs, corevalidation.ValidateFeatureGates(controlPlaneConfig.CloudControllerManager.FeatureGates, version, fldPath.Child("cloudControllerManager", "featureGates"))...)
}

return allErrs
}

Expand Down
31 changes: 27 additions & 4 deletions pkg/apis/gcp/validation/controlplane_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@ var _ = Describe("ControlPlaneConfig validation", func() {

Describe("#ValidateControlPlaneConfig", func() {
It("should return no errors for a valid configuration", func() {
Expect(ValidateControlPlaneConfig(controlPlane, allowedZones, workerZones, fldPath)).To(BeEmpty())
Expect(ValidateControlPlaneConfig(controlPlane, allowedZones, workerZones, "", fldPath)).To(BeEmpty())
})

It("should require that the control-plane config zone be part of the worker pool zone configuration", func() {
controlPlane.Zone = ""
workerZonesNotSupported := sets.NewString("zone3", "zone4")
errorList := ValidateControlPlaneConfig(controlPlane, allowedZones, workerZonesNotSupported, fldPath)
errorList := ValidateControlPlaneConfig(controlPlane, allowedZones, workerZonesNotSupported, "", fldPath)

Expect(errorList).To(ConsistOf(PointTo(MatchFields(IgnoreExtras, Fields{
"Type": Equal(field.ErrorTypeInvalid),
Expand All @@ -62,7 +62,7 @@ var _ = Describe("ControlPlaneConfig validation", func() {
It("should require the name of a zone", func() {
controlPlane.Zone = ""

errorList := ValidateControlPlaneConfig(controlPlane, allowedZones, workerZones, fldPath)
errorList := ValidateControlPlaneConfig(controlPlane, allowedZones, workerZones, "", fldPath)

Expect(errorList).To(ConsistOf(PointTo(MatchFields(IgnoreExtras, Fields{
"Type": Equal(field.ErrorTypeRequired),
Expand All @@ -76,7 +76,7 @@ var _ = Describe("ControlPlaneConfig validation", func() {
It("should require a name of a zone that is part of the regions", func() {
controlPlane.Zone = "bar"

errorList := ValidateControlPlaneConfig(controlPlane, allowedZones, workerZones, fldPath)
errorList := ValidateControlPlaneConfig(controlPlane, allowedZones, workerZones, "", fldPath)

Expect(errorList).To(ConsistOf(PointTo(MatchFields(IgnoreExtras, Fields{
"Type": Equal(field.ErrorTypeNotSupported),
Expand All @@ -86,6 +86,29 @@ var _ = Describe("ControlPlaneConfig validation", func() {
"Field": Equal("zone"),
}))))
})

It("should fail with invalid CCM feature gates", func() {
controlPlane.CloudControllerManager = &apisgcp.CloudControllerManagerConfig{
FeatureGates: map[string]bool{
"AnyVolumeDataSource": true,
"CustomResourceValidation": true,
"Foo": true,
},
}

errorList := ValidateControlPlaneConfig(controlPlane, allowedZones, workerZones, "1.18.14", fldPath)

Expect(errorList).To(ConsistOf(
PointTo(MatchFields(IgnoreExtras, Fields{
"Type": Equal(field.ErrorTypeForbidden),
"Field": Equal("cloudControllerManager.featureGates.CustomResourceValidation"),
})),
PointTo(MatchFields(IgnoreExtras, Fields{
"Type": Equal(field.ErrorTypeInvalid),
"Field": Equal("cloudControllerManager.featureGates.Foo"),
})),
))
})
})

Describe("#ValidateControlPlaneConfigUpdate", func() {
Expand Down

0 comments on commit ae6cef4

Please sign in to comment.