Skip to content

Commit b52f2e6

Browse files
authored
Merge pull request #693 from shawn-hurley/backport-674
Backport 674: Adding validation for default snapshot classes per driver
2 parents 917d9e7 + 46afba6 commit b52f2e6

File tree

5 files changed

+427
-21
lines changed

5 files changed

+427
-21
lines changed

pkg/validation-webhook/scheme.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package webhook
1818

1919
import (
20+
snapshot "github.com/kubernetes-csi/external-snapshotter/client/v6/clientset/versioned/scheme"
2021
admissionv1 "k8s.io/api/admission/v1"
2122
admissionv1beta1 "k8s.io/api/admission/v1beta1"
2223
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
@@ -40,4 +41,5 @@ func addToScheme(scheme *runtime.Scheme) {
4041
utilruntime.Must(admissionregistrationv1beta1.AddToScheme(scheme))
4142
utilruntime.Must(admissionv1.AddToScheme(scheme))
4243
utilruntime.Must(admissionregistrationv1.AddToScheme(scheme))
44+
utilruntime.Must(snapshot.AddToScheme(scheme))
4345
}

pkg/validation-webhook/snapshot.go

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@ import (
2222

2323
volumesnapshotv1 "github.com/kubernetes-csi/external-snapshotter/client/v6/apis/volumesnapshot/v1"
2424
volumesnapshotv1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v6/apis/volumesnapshot/v1beta1"
25+
storagelisters "github.com/kubernetes-csi/external-snapshotter/client/v6/listers/volumesnapshot/v1"
26+
"github.com/kubernetes-csi/external-snapshotter/v6/pkg/utils"
2527
v1 "k8s.io/api/admission/v1"
2628
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29+
"k8s.io/apimachinery/pkg/labels"
2730
"k8s.io/klog/v2"
2831
)
2932

@@ -36,10 +39,26 @@ var (
3639
SnapshotContentV1Beta1GVR = metav1.GroupVersionResource{Group: volumesnapshotv1beta1.GroupName, Version: "v1beta1", Resource: "volumesnapshotcontents"}
3740
// SnapshotContentV1GVR is GroupVersionResource for v1 VolumeSnapshotContents
3841
SnapshotContentV1GVR = metav1.GroupVersionResource{Group: volumesnapshotv1.GroupName, Version: "v1", Resource: "volumesnapshotcontents"}
42+
// SnapshotContentV1GVR is GroupVersionResource for v1 VolumeSnapshotContents
43+
SnapshotClassV1GVR = metav1.GroupVersionResource{Group: volumesnapshotv1.GroupName, Version: "v1", Resource: "volumesnapshotclasses"}
3944
)
4045

46+
type SnapshotAdmitter interface {
47+
Admit(v1.AdmissionReview) *v1.AdmissionResponse
48+
}
49+
50+
type admitter struct {
51+
lister storagelisters.VolumeSnapshotClassLister
52+
}
53+
54+
func NewSnapshotAdmitter(lister storagelisters.VolumeSnapshotClassLister) SnapshotAdmitter {
55+
return &admitter{
56+
lister: lister,
57+
}
58+
}
59+
4160
// Add a label {"added-label": "yes"} to the object
42-
func admitSnapshot(ar v1.AdmissionReview) *v1.AdmissionResponse {
61+
func (a admitter) Admit(ar v1.AdmissionReview) *v1.AdmissionResponse {
4362
klog.V(2).Info("admitting volumesnapshots or volumesnapshotcontents")
4463

4564
reviewResponse := &v1.AdmissionResponse{
@@ -106,6 +125,18 @@ func admitSnapshot(ar v1.AdmissionReview) *v1.AdmissionResponse {
106125
return toV1AdmissionResponse(err)
107126
}
108127
return decideSnapshotContentV1(snapcontent, oldSnapcontent, isUpdate)
128+
case SnapshotClassV1GVR:
129+
snapClass := &volumesnapshotv1.VolumeSnapshotClass{}
130+
if _, _, err := deserializer.Decode(raw, nil, snapClass); err != nil {
131+
klog.Error(err)
132+
return toV1AdmissionResponse(err)
133+
}
134+
oldSnapClass := &volumesnapshotv1.VolumeSnapshotClass{}
135+
if _, _, err := deserializer.Decode(oldRaw, nil, oldSnapClass); err != nil {
136+
klog.Error(err)
137+
return toV1AdmissionResponse(err)
138+
}
139+
return decideSnapshotClassV1(snapClass, oldSnapClass, a.lister)
109140
default:
110141
err := fmt.Errorf("expect resource to be %s or %s", SnapshotV1Beta1GVR, SnapshotContentV1Beta1GVR)
111142
klog.Error(err)
@@ -223,6 +254,43 @@ func decideSnapshotContentV1(snapcontent, oldSnapcontent *volumesnapshotv1.Volum
223254
return reviewResponse
224255
}
225256

257+
func decideSnapshotClassV1(snapClass, oldSnapClass *volumesnapshotv1.VolumeSnapshotClass, lister storagelisters.VolumeSnapshotClassLister) *v1.AdmissionResponse {
258+
reviewResponse := &v1.AdmissionResponse{
259+
Allowed: true,
260+
Result: &metav1.Status{},
261+
}
262+
263+
// Only Validate when a new snapClass is being set as a default.
264+
if snapClass.Annotations[utils.IsDefaultSnapshotClassAnnotation] != "true" {
265+
return reviewResponse
266+
}
267+
268+
// If Old snapshot class has this, then we can assume that it was validated if driver is the same.
269+
if oldSnapClass.Annotations[utils.IsDefaultSnapshotClassAnnotation] == "true" && oldSnapClass.Driver == snapClass.Driver {
270+
return reviewResponse
271+
}
272+
273+
ret, err := lister.List(labels.Everything())
274+
if err != nil {
275+
reviewResponse.Allowed = false
276+
reviewResponse.Result.Message = err.Error()
277+
return reviewResponse
278+
}
279+
280+
for _, snapshotClass := range ret {
281+
if snapshotClass.Annotations[utils.IsDefaultSnapshotClassAnnotation] != "true" {
282+
continue
283+
}
284+
if snapshotClass.Driver == snapClass.Driver {
285+
reviewResponse.Allowed = false
286+
reviewResponse.Result.Message = fmt.Sprintf("default snapshot class: %v already exits for driver: %v", snapshotClass.Name, snapClass.Driver)
287+
return reviewResponse
288+
}
289+
}
290+
291+
return reviewResponse
292+
}
293+
226294
func strPtrDereference(s *string) string {
227295
if s == nil {
228296
return "<nil string pointer>"

0 commit comments

Comments
 (0)