Repository: doitintl/kube-no-trouble
Pull request #346 (2022-09-01 10:27:18)

feat: Add support for detecting snapshot.storage.k8s.io/v1beta1
This PR adds support for detecting now deprecated [^1] `snapshot.storage.k8s.io/v1beta1` resources:
- `VolumeSnapshot`
- `VolumeSnapshotClass`
- `VolumeSnapshotContent`

Fixes https://github.com/doitintl/kube-no-trouble/issues/87


Other minor changes introduced:
- [test: Reduce test noise level](https://github.com/doitintl/kube-no-trouble/commit/78e9edfd9e289d3c63714ea5cf3b5b6aa9c9d58f): reduce log level in tests to `WARN` to improve readability of tests output

[^1]: https://github.com/kubernetes-csi/external-snapshotter/tree/master/client/config/crd

stepanstipl: _SonarCLoud is complaining about repeating `snapshot.storage.k8s.io` and suggesting a constant, but I don't think it's a problem in this case._
dark0dave: Detection looks fine.
dark0dave: Also if you want to change noise level please open another pr, feels separate to this.
stepanstipl: Ok, fair enough, I will move that bit to another PR.

Patch:
diff --git a/fixtures/volumesnapshot-v1beta1.yaml b/fixtures/volumesnapshot-v1beta1.yaml
new file mode 100644
index 0000000..86a102b
--- /dev/null
+++ b/fixtures/volumesnapshot-v1beta1.yaml
@@ -0,0 +1,8 @@
+apiVersion: snapshot.storage.k8s.io/v1beta1
+kind: VolumeSnapshot
+metadata:
+  name: new-snapshot-demo
+spec:
+  volumeSnapshotClassName: csi-hostpath-snapclass
+  source:
+    persistentVolumeClaimName: hpvc
diff --git a/fixtures/volumesnapshotclass-v1beta1.yaml b/fixtures/volumesnapshotclass-v1beta1.yaml
new file mode 100644
index 0000000..41df498
--- /dev/null
+++ b/fixtures/volumesnapshotclass-v1beta1.yaml
@@ -0,0 +1,6 @@
+apiVersion: snapshot.storage.k8s.io/v1beta1
+kind: VolumeSnapshotClass
+metadata:
+  name: csi-hostpath-snapclass
+driver: hostpath.csi.k8s.io
+deletionPolicy: Delete
diff --git a/fixtures/volumesnapshotcontent-v1beta1.yaml b/fixtures/volumesnapshotcontent-v1beta1.yaml
new file mode 100644
index 0000000..e7da915
--- /dev/null
+++ b/fixtures/volumesnapshotcontent-v1beta1.yaml
@@ -0,0 +1,15 @@
+apiVersion: snapshot.storage.k8s.io/v1beta1
+kind: VolumeSnapshotContent
+metadata:
+  name: new-snapshot-content-test
+  annotations:
+    - snapshot.storage.kubernetes.io/allowVolumeModeChange: "true"
+spec:
+  deletionPolicy: Delete
+  driver: hostpath.csi.k8s.io
+  source:
+    snapshotHandle: 7bdd0de3-aaeb-11e8-9aae-0242ac110002
+  sourceVolumeMode: Filesystem
+  volumeSnapshotRef:
+    name: new-snapshot-test
+    namespace: default
diff --git a/pkg/collector/cluster.go b/pkg/collector/cluster.go
index 3b15a78..68624e3 100644
--- a/pkg/collector/cluster.go
+++ b/pkg/collector/cluster.go
@@ -99,6 +99,9 @@ func (c *ClusterCollector) Get() ([]map[string]interface{}, error) {
 		schema.GroupVersionResource{Group: "policy", Version: "v1beta1", Resource: "podsecuritypolicies"},
 		schema.GroupVersionResource{Group: "discovery.k8s.io", Version: "v1", Resource: "endpointslices"},
 		schema.GroupVersionResource{Group: "batch", Version: "v1", Resource: "cronjobs"},
+		schema.GroupVersionResource{Group: "snapshot.storage.k8s.io", Version: "v1", Resource: "volumesnapshots"},
+		schema.GroupVersionResource{Group: "snapshot.storage.k8s.io", Version: "v1", Resource: "volumesnapshotclasses"},
+		schema.GroupVersionResource{Group: "snapshot.storage.k8s.io", Version: "v1", Resource: "volumesnapshotcontents"},
 	}
 	gvrs = append(gvrs, c.additionalResources...)
 
diff --git a/pkg/rules/rego/deprecated-future.rego b/pkg/rules/rego/deprecated-future.rego
new file mode 100644
index 0000000..f0d4f58
--- /dev/null
+++ b/pkg/rules/rego/deprecated-future.rego
@@ -0,0 +1,53 @@
+package deprecatedFuture
+
+main[return] {
+	resource := input[_]
+	api := deprecated_resource(resource)
+	return := {
+		"Name": get_default(resource.metadata, "name", "<undefined>"),
+		# Namespace does not have to be defined in case of local manifests
+		"Namespace": get_default(resource.metadata, "namespace", "<undefined>"),
+		"Kind": resource.kind,
+		"ApiVersion": api.old,
+		"ReplaceWith": api.new,
+		"RuleSet": "Deprecated APIs to be removed in future",
+		"Since": api.since,
+	}
+}
+
+deprecated_resource(r) = api {
+	api := deprecated_api(r.kind, r.apiVersion)
+}
+
+deprecated_api(kind, api_version) = api {
+	deprecated_apis = {
+		"VolumeSnapshot": {
+			"old": ["snapshot.storage.k8s.io/v1beta1"],
+			"new": "snapshot.storage.k8s.io/v1",
+			"since": "1.21",
+		},
+		"VolumeSnapshotClass": {
+			"old": ["snapshot.storage.k8s.io/v1beta1"],
+			"new": "snapshot.storage.k8s.io/v1",
+			"since": "1.21",
+		},
+		"VolumeSnapshotContent": {
+			"old": ["snapshot.storage.k8s.io/v1beta1"],
+			"new": "snapshot.storage.k8s.io/v1",
+			"since": "1.21",
+		},
+	}
+
+	deprecated_apis[kind].old[_] == api_version
+	api := {
+		"old": api_version,
+		"new": deprecated_apis[kind].new,
+		"since": deprecated_apis[kind].since,
+	}
+}
+
+get_default(val, key, _) = val[key]
+
+get_default(val, key, fallback) = fallback {
+	not val[key]
+}


Test patch:
diff --git a/test/rules_future_test.go b/test/rules_future_test.go
new file mode 100644
index 0000000..124fbad
--- /dev/null
+++ b/test/rules_future_test.go
@@ -0,0 +1,15 @@
+package test
+
+import (
+	"testing"
+)
+
+func TestRegoFuture(t *testing.T) {
+	testCases := []resourceFixtureTestCase{
+		{"VolumeSnapshot", []string{"../fixtures/volumesnapshot-v1beta1.yaml"}, []string{"VolumeSnapshot"}},
+		{"VolumeSnapshotClass", []string{"../fixtures/volumesnapshotclass-v1beta1.yaml"}, []string{"VolumeSnapshotClass"}},
+		{"VolumeSnapshotContent", []string{"../fixtures/volumesnapshotcontent-v1beta1.yaml"}, []string{"VolumeSnapshotContent"}},
+	}
+
+	testReourcesUsingFixtures(t, testCases)
+}