Move snapshot validations to validation-webhook directory

Signed-off-by: prateekpandey14 <prateekpandey14@gmail.com>
This commit is contained in:
prateekpandey14
2021-03-03 22:37:40 +05:30
parent de6c35a89c
commit 533ed886dc
4 changed files with 114 additions and 91 deletions

View File

@@ -34,6 +34,7 @@ import (
crdv1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
"github.com/kubernetes-csi/external-snapshotter/v4/pkg/metrics"
"github.com/kubernetes-csi/external-snapshotter/v4/pkg/utils"
webhook "github.com/kubernetes-csi/external-snapshotter/v4/pkg/validation-webhook"
)
// ==================================================================
@@ -1505,7 +1506,7 @@ func (ctrl *csiSnapshotCommonController) setAnnVolumeSnapshotBeingDeleted(conten
// checkAndSetInvalidContentLabel adds a label to unlabeled invalid content objects and removes the label from valid ones.
func (ctrl *csiSnapshotCommonController) checkAndSetInvalidContentLabel(content *crdv1.VolumeSnapshotContent) (*crdv1.VolumeSnapshotContent, error) {
hasLabel := utils.MapContainsKey(content.ObjectMeta.Labels, utils.VolumeSnapshotContentInvalidLabel)
err := utils.ValidateV1SnapshotContent(content)
err := webhook.ValidateV1SnapshotContent(content)
if err != nil {
klog.Errorf("syncContent[%s]: Invalid content detected, %s", content.Name, err.Error())
}
@@ -1546,7 +1547,7 @@ func (ctrl *csiSnapshotCommonController) checkAndSetInvalidContentLabel(content
// checkAndSetInvalidSnapshotLabel adds a label to unlabeled invalid snapshot objects and removes the label from valid ones.
func (ctrl *csiSnapshotCommonController) checkAndSetInvalidSnapshotLabel(snapshot *crdv1.VolumeSnapshot) (*crdv1.VolumeSnapshot, error) {
hasLabel := utils.MapContainsKey(snapshot.ObjectMeta.Labels, utils.VolumeSnapshotInvalidLabel)
err := utils.ValidateV1Snapshot(snapshot)
err := webhook.ValidateV1Snapshot(snapshot)
if err != nil {
klog.Errorf("syncSnapshot[%s]: Invalid snapshot detected, %s", utils.SnapshotKey(snapshot), err.Error())
}

View File

@@ -25,7 +25,6 @@ import (
"time"
crdv1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
crdv1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1beta1"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -122,87 +121,6 @@ var SnapshotterListSecretParams = secretParamsMap{
secretNamespaceKey: PrefixedSnapshotterListSecretNamespaceKey,
}
// ValidateV1Snapshot performs additional strict validation.
// Do NOT rely on this function to fully validate snapshot objects.
// This function will only check the additional rules provided by the webhook.
func ValidateV1Snapshot(snapshot *crdv1.VolumeSnapshot) error {
if snapshot == nil {
return fmt.Errorf("VolumeSnapshot is nil")
}
vscname := snapshot.Spec.VolumeSnapshotClassName
if vscname != nil && *vscname == "" {
return fmt.Errorf("Spec.VolumeSnapshotClassName must not be the empty string")
}
return nil
}
// ValidateV1Beta1Snapshot performs additional strict validation.
// Do NOT rely on this function to fully validate snapshot objects.
// This function will only check the additional rules provided by the webhook.
func ValidateV1Beta1Snapshot(snapshot *crdv1beta1.VolumeSnapshot) error {
if snapshot == nil {
return fmt.Errorf("VolumeSnapshot is nil")
}
source := snapshot.Spec.Source
if source.PersistentVolumeClaimName != nil && source.VolumeSnapshotContentName != nil {
return fmt.Errorf("only one of Spec.Source.PersistentVolumeClaimName = %s and Spec.Source.VolumeSnapshotContentName = %s should be set", *source.PersistentVolumeClaimName, *source.VolumeSnapshotContentName)
}
if source.PersistentVolumeClaimName == nil && source.VolumeSnapshotContentName == nil {
return fmt.Errorf("one of Spec.Source.PersistentVolumeClaimName and Spec.Source.VolumeSnapshotContentName should be set")
}
vscname := snapshot.Spec.VolumeSnapshotClassName
if vscname != nil && *vscname == "" {
return fmt.Errorf("Spec.VolumeSnapshotClassName must not be the empty string")
}
return nil
}
// ValidateV1SnapshotContent performs additional strict validation.
// Do NOT rely on this function to fully validate snapshot content objects.
// This function will only check the additional rules provided by the webhook.
func ValidateV1SnapshotContent(snapcontent *crdv1.VolumeSnapshotContent) error {
if snapcontent == nil {
return fmt.Errorf("VolumeSnapshotContent is nil")
}
vsref := snapcontent.Spec.VolumeSnapshotRef
if vsref.Name == "" || vsref.Namespace == "" {
return fmt.Errorf("both Spec.VolumeSnapshotRef.Name = %s and Spec.VolumeSnapshotRef.Namespace = %s must be set", vsref.Name, vsref.Namespace)
}
return nil
}
// ValidateV1Beta1SnapshotContent performs additional strict validation.
// Do NOT rely on this function to fully validate snapshot content objects.
// This function will only check the additional rules provided by the webhook.
func ValidateV1Beta1SnapshotContent(snapcontent *crdv1beta1.VolumeSnapshotContent) error {
if snapcontent == nil {
return fmt.Errorf("VolumeSnapshotContent is nil")
}
source := snapcontent.Spec.Source
if source.VolumeHandle != nil && source.SnapshotHandle != nil {
return fmt.Errorf("only one of Spec.Source.VolumeHandle = %s and Spec.Source.SnapshotHandle = %s should be set", *source.VolumeHandle, *source.SnapshotHandle)
}
if source.VolumeHandle == nil && source.SnapshotHandle == nil {
return fmt.Errorf("one of Spec.Source.VolumeHandle and Spec.Source.SnapshotHandle should be set")
}
vsref := snapcontent.Spec.VolumeSnapshotRef
if vsref.Name == "" || vsref.Namespace == "" {
return fmt.Errorf("both Spec.VolumeSnapshotRef.Name = %s and Spec.VolumeSnapshotRef.Namespace = %s must be set", vsref.Name, vsref.Namespace)
}
return nil
}
// MapContainsKey checks if a given map of string to string contains the provided string.
func MapContainsKey(m map[string]string, s string) bool {
_, r := m[s]

View File

@@ -22,7 +22,6 @@ import (
volumesnapshotv1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
volumesnapshotv1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1beta1"
"github.com/kubernetes-csi/external-snapshotter/v4/pkg/utils"
v1 "k8s.io/api/admission/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/klog/v2"
@@ -126,7 +125,7 @@ func decideSnapshotV1beta1(snapshot, oldSnapshot *volumesnapshotv1beta1.VolumeSn
// Which allows the remover of finalizers and therefore deletion of this object
// Don't rely on the pointers to be nil, because the deserialization method will convert it to
// The empty struct value. Instead check the operation type.
if err := utils.ValidateV1Beta1Snapshot(oldSnapshot); err != nil {
if err := ValidateV1Beta1Snapshot(oldSnapshot); err != nil {
return reviewResponse
}
@@ -139,7 +138,7 @@ func decideSnapshotV1beta1(snapshot, oldSnapshot *volumesnapshotv1beta1.VolumeSn
}
// Enforce strict validation for CREATE requests. Immutable checks don't apply for CREATE requests.
// Enforce strict validation for UPDATE requests where old is valid and passes immutability check.
if err := utils.ValidateV1Beta1Snapshot(snapshot); err != nil {
if err := ValidateV1Beta1Snapshot(snapshot); err != nil {
reviewResponse.Allowed = false
reviewResponse.Result.Message = err.Error()
}
@@ -162,7 +161,7 @@ func decideSnapshotV1(snapshot, oldSnapshot *volumesnapshotv1.VolumeSnapshot, is
}
// Enforce strict validation for CREATE requests. Immutable checks don't apply for CREATE requests.
// Enforce strict validation for UPDATE requests where old is valid and passes immutability check.
if err := utils.ValidateV1Snapshot(snapshot); err != nil {
if err := ValidateV1Snapshot(snapshot); err != nil {
reviewResponse.Allowed = false
reviewResponse.Result.Message = err.Error()
}
@@ -181,7 +180,7 @@ func decideSnapshotContentV1beta1(snapcontent, oldSnapcontent *volumesnapshotv1b
// Which allows the remover of finalizers and therefore deletion of this object
// Don't rely on the pointers to be nil, because the deserialization method will convert it to
// The empty struct value. Instead check the operation type.
if err := utils.ValidateV1Beta1SnapshotContent(oldSnapcontent); err != nil {
if err := ValidateV1Beta1SnapshotContent(oldSnapcontent); err != nil {
return reviewResponse
}
@@ -194,7 +193,7 @@ func decideSnapshotContentV1beta1(snapcontent, oldSnapcontent *volumesnapshotv1b
}
// Enforce strict validation for all CREATE requests. Immutable checks don't apply for CREATE requests.
// Enforce strict validation for UPDATE requests where old is valid and passes immutability check.
if err := utils.ValidateV1Beta1SnapshotContent(snapcontent); err != nil {
if err := ValidateV1Beta1SnapshotContent(snapcontent); err != nil {
reviewResponse.Allowed = false
reviewResponse.Result.Message = err.Error()
}
@@ -217,7 +216,7 @@ func decideSnapshotContentV1(snapcontent, oldSnapcontent *volumesnapshotv1.Volum
}
// Enforce strict validation for all CREATE requests. Immutable checks don't apply for CREATE requests.
// Enforce strict validation for UPDATE requests where old is valid and passes immutability check.
if err := utils.ValidateV1SnapshotContent(snapcontent); err != nil {
if err := ValidateV1SnapshotContent(snapcontent); err != nil {
reviewResponse.Allowed = false
reviewResponse.Result.Message = err.Error()
}

View File

@@ -0,0 +1,105 @@
/*
Copyright 2021 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 webhook
import (
"fmt"
crdv1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
crdv1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1beta1"
)
// ValidateV1Snapshot performs additional strict validation.
// Do NOT rely on this function to fully validate snapshot objects.
// This function will only check the additional rules provided by the webhook.
func ValidateV1Snapshot(snapshot *crdv1.VolumeSnapshot) error {
if snapshot == nil {
return fmt.Errorf("VolumeSnapshot is nil")
}
vscname := snapshot.Spec.VolumeSnapshotClassName
if vscname != nil && *vscname == "" {
return fmt.Errorf("Spec.VolumeSnapshotClassName must not be the empty string")
}
return nil
}
// ValidateV1Beta1Snapshot performs additional strict validation.
// Do NOT rely on this function to fully validate snapshot objects.
// This function will only check the additional rules provided by the webhook.
func ValidateV1Beta1Snapshot(snapshot *crdv1beta1.VolumeSnapshot) error {
if snapshot == nil {
return fmt.Errorf("VolumeSnapshot is nil")
}
source := snapshot.Spec.Source
if source.PersistentVolumeClaimName != nil && source.VolumeSnapshotContentName != nil {
return fmt.Errorf("only one of Spec.Source.PersistentVolumeClaimName = %s and Spec.Source.VolumeSnapshotContentName = %s should be set", *source.PersistentVolumeClaimName, *source.VolumeSnapshotContentName)
}
if source.PersistentVolumeClaimName == nil && source.VolumeSnapshotContentName == nil {
return fmt.Errorf("one of Spec.Source.PersistentVolumeClaimName and Spec.Source.VolumeSnapshotContentName should be set")
}
vscname := snapshot.Spec.VolumeSnapshotClassName
if vscname != nil && *vscname == "" {
return fmt.Errorf("Spec.VolumeSnapshotClassName must not be the empty string")
}
return nil
}
// ValidateV1SnapshotContent performs additional strict validation.
// Do NOT rely on this function to fully validate snapshot content objects.
// This function will only check the additional rules provided by the webhook.
func ValidateV1SnapshotContent(snapcontent *crdv1.VolumeSnapshotContent) error {
if snapcontent == nil {
return fmt.Errorf("VolumeSnapshotContent is nil")
}
vsref := snapcontent.Spec.VolumeSnapshotRef
if vsref.Name == "" || vsref.Namespace == "" {
return fmt.Errorf("both Spec.VolumeSnapshotRef.Name = %s and Spec.VolumeSnapshotRef.Namespace = %s must be set", vsref.Name, vsref.Namespace)
}
return nil
}
// ValidateV1Beta1SnapshotContent performs additional strict validation.
// Do NOT rely on this function to fully validate snapshot content objects.
// This function will only check the additional rules provided by the webhook.
func ValidateV1Beta1SnapshotContent(snapcontent *crdv1beta1.VolumeSnapshotContent) error {
if snapcontent == nil {
return fmt.Errorf("VolumeSnapshotContent is nil")
}
source := snapcontent.Spec.Source
if source.VolumeHandle != nil && source.SnapshotHandle != nil {
return fmt.Errorf("only one of Spec.Source.VolumeHandle = %s and Spec.Source.SnapshotHandle = %s should be set", *source.VolumeHandle, *source.SnapshotHandle)
}
if source.VolumeHandle == nil && source.SnapshotHandle == nil {
return fmt.Errorf("one of Spec.Source.VolumeHandle and Spec.Source.SnapshotHandle should be set")
}
vsref := snapcontent.Spec.VolumeSnapshotRef
if vsref.Name == "" || vsref.Namespace == "" {
return fmt.Errorf("both Spec.VolumeSnapshotRef.Name = %s and Spec.VolumeSnapshotRef.Namespace = %s must be set", vsref.Name, vsref.Namespace)
}
return nil
}