Update controller based on snapshot v1 apis
This commit is contained in:
@@ -20,6 +20,7 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
volumesnapshotv1 "github.com/kubernetes-csi/external-snapshotter/client/v3/apis/volumesnapshot/v1"
|
||||
volumesnapshotv1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v3/apis/volumesnapshot/v1beta1"
|
||||
"github.com/kubernetes-csi/external-snapshotter/v3/pkg/utils"
|
||||
v1 "k8s.io/api/admission/v1"
|
||||
@@ -28,10 +29,14 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// SnapshotV1Beta1GVR is GroupVersionResource for volumesnapshots
|
||||
// SnapshotV1Beta1GVR is GroupVersionResource for v1beta1 VolumeSnapshots
|
||||
SnapshotV1Beta1GVR = metav1.GroupVersionResource{Group: volumesnapshotv1beta1.GroupName, Version: "v1beta1", Resource: "volumesnapshots"}
|
||||
// SnapshotContentV1Beta1GVR is GroupVersionResource for volumesnapshotcontents
|
||||
// SnapshotV1GVR is GroupVersionResource for v1 VolumeSnapshots
|
||||
SnapshotV1GVR = metav1.GroupVersionResource{Group: volumesnapshotv1.GroupName, Version: "v1", Resource: "volumesnapshots"}
|
||||
// SnapshotContentV1Beta1GVR is GroupVersionResource for v1beta1 VolumeSnapshotContents
|
||||
SnapshotContentV1Beta1GVR = metav1.GroupVersionResource{Group: volumesnapshotv1beta1.GroupName, Version: "v1beta1", Resource: "volumesnapshotcontents"}
|
||||
// SnapshotContentV1GVR is GroupVersionResource for v1 VolumeSnapshotContents
|
||||
SnapshotContentV1GVR = metav1.GroupVersionResource{Group: volumesnapshotv1.GroupName, Version: "v1", Resource: "volumesnapshotcontents"}
|
||||
)
|
||||
|
||||
// Add a label {"added-label": "yes"} to the object
|
||||
@@ -65,7 +70,19 @@ func admitSnapshot(ar v1.AdmissionReview) *v1.AdmissionResponse {
|
||||
klog.Error(err)
|
||||
return toV1AdmissionResponse(err)
|
||||
}
|
||||
return decideSnapshot(snapshot, oldSnapshot, isUpdate)
|
||||
return decideSnapshotV1beta1(snapshot, oldSnapshot, isUpdate)
|
||||
case SnapshotV1GVR:
|
||||
snapshot := &volumesnapshotv1.VolumeSnapshot{}
|
||||
if _, _, err := deserializer.Decode(raw, nil, snapshot); err != nil {
|
||||
klog.Error(err)
|
||||
return toV1AdmissionResponse(err)
|
||||
}
|
||||
oldSnapshot := &volumesnapshotv1.VolumeSnapshot{}
|
||||
if _, _, err := deserializer.Decode(oldRaw, nil, oldSnapshot); err != nil {
|
||||
klog.Error(err)
|
||||
return toV1AdmissionResponse(err)
|
||||
}
|
||||
return decideSnapshotV1(snapshot, oldSnapshot, isUpdate)
|
||||
case SnapshotContentV1Beta1GVR:
|
||||
snapcontent := &volumesnapshotv1beta1.VolumeSnapshotContent{}
|
||||
if _, _, err := deserializer.Decode(raw, nil, snapcontent); err != nil {
|
||||
@@ -77,7 +94,19 @@ func admitSnapshot(ar v1.AdmissionReview) *v1.AdmissionResponse {
|
||||
klog.Error(err)
|
||||
return toV1AdmissionResponse(err)
|
||||
}
|
||||
return decideSnapshotContent(snapcontent, oldSnapcontent, isUpdate)
|
||||
return decideSnapshotContentV1beta1(snapcontent, oldSnapcontent, isUpdate)
|
||||
case SnapshotContentV1GVR:
|
||||
snapcontent := &volumesnapshotv1.VolumeSnapshotContent{}
|
||||
if _, _, err := deserializer.Decode(raw, nil, snapcontent); err != nil {
|
||||
klog.Error(err)
|
||||
return toV1AdmissionResponse(err)
|
||||
}
|
||||
oldSnapcontent := &volumesnapshotv1.VolumeSnapshotContent{}
|
||||
if _, _, err := deserializer.Decode(oldRaw, nil, oldSnapcontent); err != nil {
|
||||
klog.Error(err)
|
||||
return toV1AdmissionResponse(err)
|
||||
}
|
||||
return decideSnapshotContentV1(snapcontent, oldSnapcontent, isUpdate)
|
||||
default:
|
||||
err := fmt.Errorf("expect resource to be %s or %s", SnapshotV1Beta1GVR, SnapshotContentV1Beta1GVR)
|
||||
klog.Error(err)
|
||||
@@ -85,7 +114,7 @@ func admitSnapshot(ar v1.AdmissionReview) *v1.AdmissionResponse {
|
||||
}
|
||||
}
|
||||
|
||||
func decideSnapshot(snapshot, oldSnapshot *volumesnapshotv1beta1.VolumeSnapshot, isUpdate bool) *v1.AdmissionResponse {
|
||||
func decideSnapshotV1beta1(snapshot, oldSnapshot *volumesnapshotv1beta1.VolumeSnapshot, isUpdate bool) *v1.AdmissionResponse {
|
||||
reviewResponse := &v1.AdmissionResponse{
|
||||
Allowed: true,
|
||||
Result: &metav1.Status{},
|
||||
@@ -97,12 +126,12 @@ func decideSnapshot(snapshot, oldSnapshot *volumesnapshotv1beta1.VolumeSnapshot,
|
||||
// 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.ValidateSnapshot(oldSnapshot); err != nil {
|
||||
if err := utils.ValidateV1Beta1Snapshot(oldSnapshot); err != nil {
|
||||
return reviewResponse
|
||||
}
|
||||
|
||||
// if it is an UPDATE and oldSnapshot is valid, check immutable fields
|
||||
if err := checkSnapshotImmutableFields(snapshot, oldSnapshot); err != nil {
|
||||
if err := checkSnapshotImmutableFieldsV1beta1(snapshot, oldSnapshot); err != nil {
|
||||
reviewResponse.Allowed = false
|
||||
reviewResponse.Result.Message = err.Error()
|
||||
return reviewResponse
|
||||
@@ -110,14 +139,37 @@ func decideSnapshot(snapshot, oldSnapshot *volumesnapshotv1beta1.VolumeSnapshot,
|
||||
}
|
||||
// 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.ValidateSnapshot(snapshot); err != nil {
|
||||
if err := utils.ValidateV1Beta1Snapshot(snapshot); err != nil {
|
||||
reviewResponse.Allowed = false
|
||||
reviewResponse.Result.Message = err.Error()
|
||||
}
|
||||
return reviewResponse
|
||||
}
|
||||
|
||||
func decideSnapshotContent(snapcontent, oldSnapcontent *volumesnapshotv1beta1.VolumeSnapshotContent, isUpdate bool) *v1.AdmissionResponse {
|
||||
func decideSnapshotV1(snapshot, oldSnapshot *volumesnapshotv1.VolumeSnapshot, isUpdate bool) *v1.AdmissionResponse {
|
||||
reviewResponse := &v1.AdmissionResponse{
|
||||
Allowed: true,
|
||||
Result: &metav1.Status{},
|
||||
}
|
||||
|
||||
if isUpdate {
|
||||
// if it is an UPDATE and oldSnapshot is valid, check immutable fields
|
||||
if err := checkSnapshotImmutableFieldsV1(snapshot, oldSnapshot); err != nil {
|
||||
reviewResponse.Allowed = false
|
||||
reviewResponse.Result.Message = err.Error()
|
||||
return reviewResponse
|
||||
}
|
||||
}
|
||||
// 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 {
|
||||
reviewResponse.Allowed = false
|
||||
reviewResponse.Result.Message = err.Error()
|
||||
}
|
||||
return reviewResponse
|
||||
}
|
||||
|
||||
func decideSnapshotContentV1beta1(snapcontent, oldSnapcontent *volumesnapshotv1beta1.VolumeSnapshotContent, isUpdate bool) *v1.AdmissionResponse {
|
||||
reviewResponse := &v1.AdmissionResponse{
|
||||
Allowed: true,
|
||||
Result: &metav1.Status{},
|
||||
@@ -129,12 +181,12 @@ func decideSnapshotContent(snapcontent, oldSnapcontent *volumesnapshotv1beta1.Vo
|
||||
// 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.ValidateSnapshotContent(oldSnapcontent); err != nil {
|
||||
if err := utils.ValidateV1Beta1SnapshotContent(oldSnapcontent); err != nil {
|
||||
return reviewResponse
|
||||
}
|
||||
|
||||
// if it is an UPDATE and oldSnapcontent is valid, check immutable fields
|
||||
if err := checkSnapshotContentImmutableFields(snapcontent, oldSnapcontent); err != nil {
|
||||
if err := checkSnapshotContentImmutableFieldsV1beta1(snapcontent, oldSnapcontent); err != nil {
|
||||
reviewResponse.Allowed = false
|
||||
reviewResponse.Result.Message = err.Error()
|
||||
return reviewResponse
|
||||
@@ -142,7 +194,30 @@ func decideSnapshotContent(snapcontent, oldSnapcontent *volumesnapshotv1beta1.Vo
|
||||
}
|
||||
// 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.ValidateSnapshotContent(snapcontent); err != nil {
|
||||
if err := utils.ValidateV1Beta1SnapshotContent(snapcontent); err != nil {
|
||||
reviewResponse.Allowed = false
|
||||
reviewResponse.Result.Message = err.Error()
|
||||
}
|
||||
return reviewResponse
|
||||
}
|
||||
|
||||
func decideSnapshotContentV1(snapcontent, oldSnapcontent *volumesnapshotv1.VolumeSnapshotContent, isUpdate bool) *v1.AdmissionResponse {
|
||||
reviewResponse := &v1.AdmissionResponse{
|
||||
Allowed: true,
|
||||
Result: &metav1.Status{},
|
||||
}
|
||||
|
||||
if isUpdate {
|
||||
// if it is an UPDATE and oldSnapcontent is valid, check immutable fields
|
||||
if err := checkSnapshotContentImmutableFieldsV1(snapcontent, oldSnapcontent); err != nil {
|
||||
reviewResponse.Allowed = false
|
||||
reviewResponse.Result.Message = err.Error()
|
||||
return reviewResponse
|
||||
}
|
||||
}
|
||||
// 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 {
|
||||
reviewResponse.Allowed = false
|
||||
reviewResponse.Result.Message = err.Error()
|
||||
}
|
||||
@@ -155,7 +230,8 @@ func strPtrDereference(s *string) string {
|
||||
}
|
||||
return *s
|
||||
}
|
||||
func checkSnapshotImmutableFields(snapshot, oldSnapshot *volumesnapshotv1beta1.VolumeSnapshot) error {
|
||||
|
||||
func checkSnapshotImmutableFieldsV1beta1(snapshot, oldSnapshot *volumesnapshotv1beta1.VolumeSnapshot) error {
|
||||
if snapshot == nil {
|
||||
return fmt.Errorf("VolumeSnapshot is nil")
|
||||
}
|
||||
@@ -176,7 +252,48 @@ func checkSnapshotImmutableFields(snapshot, oldSnapshot *volumesnapshotv1beta1.V
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkSnapshotContentImmutableFields(snapcontent, oldSnapcontent *volumesnapshotv1beta1.VolumeSnapshotContent) error {
|
||||
func checkSnapshotImmutableFieldsV1(snapshot, oldSnapshot *volumesnapshotv1.VolumeSnapshot) error {
|
||||
if snapshot == nil {
|
||||
return fmt.Errorf("VolumeSnapshot is nil")
|
||||
}
|
||||
if oldSnapshot == nil {
|
||||
return fmt.Errorf("old VolumeSnapshot is nil")
|
||||
}
|
||||
|
||||
source := snapshot.Spec.Source
|
||||
oldSource := oldSnapshot.Spec.Source
|
||||
|
||||
if !reflect.DeepEqual(source.PersistentVolumeClaimName, oldSource.PersistentVolumeClaimName) {
|
||||
return fmt.Errorf("Spec.Source.PersistentVolumeClaimName is immutable but was changed from %s to %s", strPtrDereference(oldSource.PersistentVolumeClaimName), strPtrDereference(source.PersistentVolumeClaimName))
|
||||
}
|
||||
if !reflect.DeepEqual(source.VolumeSnapshotContentName, oldSource.VolumeSnapshotContentName) {
|
||||
return fmt.Errorf("Spec.Source.VolumeSnapshotContentName is immutable but was changed from %s to %s", strPtrDereference(oldSource.VolumeSnapshotContentName), strPtrDereference(source.VolumeSnapshotContentName))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkSnapshotContentImmutableFieldsV1beta1(snapcontent, oldSnapcontent *volumesnapshotv1beta1.VolumeSnapshotContent) error {
|
||||
if snapcontent == nil {
|
||||
return fmt.Errorf("VolumeSnapshotContent is nil")
|
||||
}
|
||||
if oldSnapcontent == nil {
|
||||
return fmt.Errorf("old VolumeSnapshotContent is nil")
|
||||
}
|
||||
|
||||
source := snapcontent.Spec.Source
|
||||
oldSource := oldSnapcontent.Spec.Source
|
||||
|
||||
if !reflect.DeepEqual(source.VolumeHandle, oldSource.VolumeHandle) {
|
||||
return fmt.Errorf("Spec.Source.VolumeHandle is immutable but was changed from %s to %s", strPtrDereference(oldSource.VolumeHandle), strPtrDereference(source.VolumeHandle))
|
||||
}
|
||||
if !reflect.DeepEqual(source.SnapshotHandle, oldSource.SnapshotHandle) {
|
||||
return fmt.Errorf("Spec.Source.SnapshotHandle is immutable but was changed from %s to %s", strPtrDereference(oldSource.SnapshotHandle), strPtrDereference(source.SnapshotHandle))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkSnapshotContentImmutableFieldsV1(snapcontent, oldSnapcontent *volumesnapshotv1.VolumeSnapshotContent) error {
|
||||
if snapcontent == nil {
|
||||
return fmt.Errorf("VolumeSnapshotContent is nil")
|
||||
}
|
||||
|
Reference in New Issue
Block a user