From ee7c037ec64cc5ee0834f902f66789ed83435311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Huss?= Date: Sat, 16 Nov 2024 15:29:21 +0100 Subject: [PATCH] StorageClass improvements --- Cargo.lock | 24 ++-- Cargo.toml | 2 +- agent/scripts/lib/build_context.rhai | 53 +------- agent/scripts/lib/storage_class_enrich.rhai | 119 ++++++++++++++++++ agent/scripts/lib/storage_class_selector.rhai | 48 +++++++ 5 files changed, 184 insertions(+), 62 deletions(-) create mode 100644 agent/scripts/lib/storage_class_enrich.rhai create mode 100644 agent/scripts/lib/storage_class_selector.rhai diff --git a/Cargo.lock b/Cargo.lock index 5a3c6a2..5ac3a02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -415,9 +415,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "axum" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" +checksum = "49c41b948da08fb481a94546cd874843adc1142278b0af4badf9b1b78599d68d" dependencies = [ "async-trait", "axum-core", @@ -1540,7 +1540,7 @@ dependencies = [ "hyper", "hyper-util", "log", - "rustls 0.23.16", + "rustls 0.23.17", "rustls-native-certs 0.8.0", "rustls-pki-types", "tokio", @@ -2003,7 +2003,7 @@ dependencies = [ "k8s-openapi", "kube-core", "pem", - "rustls 0.23.16", + "rustls 0.23.17", "rustls-pemfile", "secrecy", "serde", @@ -2090,9 +2090,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.162" +version = "0.2.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" +checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" [[package]] name = "libredox" @@ -2752,7 +2752,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.16", + "rustls 0.23.17", "socket2", "thiserror 2.0.3", "tokio", @@ -2770,7 +2770,7 @@ dependencies = [ "rand", "ring", "rustc-hash", - "rustls 0.23.16", + "rustls 0.23.17", "rustls-pki-types", "slab", "thiserror 2.0.3", @@ -2919,7 +2919,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.16", + "rustls 0.23.17", "rustls-pemfile", "rustls-pki-types", "serde", @@ -3036,9 +3036,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.16" +version = "0.23.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" +checksum = "7f1a745511c54ba6d4465e8d5dfbd81b45791756de28d4981af70d6dca128f1e" dependencies = [ "log", "once_cell", @@ -3699,7 +3699,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.16", + "rustls 0.23.17", "rustls-pki-types", "tokio", ] diff --git a/Cargo.toml b/Cargo.toml index f027622..9c3191a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,7 +66,7 @@ fmt = { cmd=[ ]} precommit = { cmd=[ "cargo update", - "cargo clippy --fix --allow-dirty", + "cargo clippy --fix --allow-dirty --allow-staged", "cargo cmd generate", "cargo +nightly fmt" ]} diff --git a/agent/scripts/lib/build_context.rhai b/agent/scripts/lib/build_context.rhai index 82d01b1..14b65ab 100644 --- a/agent/scripts/lib/build_context.rhai +++ b/agent/scripts/lib/build_context.rhai @@ -1,50 +1,5 @@ -// TODO: implement more from: https://storageclass.info/csidrivers/ -// https://github.com/storageclass/storageclass.github.io/blob/main/data/csidrivers.yaml -fn get_prefered_sc(scs) { - let pref = #{ - "many_block": (), - "many_safe": (), - "many_cheap": (), - "many_only": (), - "only_block": (), - "only_performance": (), - "only_cheap": (), - "only_safe": (), - }; - if scs.some(|s| s.provisioner == "smb.csi.k8s.io") { - let smb = scs.find(|s| s.provisioner == "smb.csi.k8s.io").name; - pref["many_safe"] = smb; - pref["many_cheap"] = smb; - } - if scs.some(|s| s.provisioner == "k8s-sigs.io/nfs-provisioner") { - let nfs = scs.find(|s| s.provisioner == "k8s-sigs.io/nfs-provisioner").name; - pref["many_safe"] = nfs; - pref["many_cheap"] = nfs; - } - if scs.some(|s| s.provisioner == "rancher.io/local-path") { - let lp = scs.find(|s| s.provisioner == "rancher.io/local-path").name; - pref["only_performance"] = lp; - pref["only_cheap"] = lp; - } - if scs.some(|s| s.provisioner.ends_with("nfs.csi.ceph.com")) { - let nfs = scs.find(|s| s.provisioner.ends_with("nfs.csi.ceph.com")).name; - pref["many_safe"] = nfs; - pref["many_cheap"] = nfs; - } - if scs.some(|s| s.provisioner.ends_with("cephfs.csi.ceph.com")) { - let cfs = scs.find(|s| s.provisioner.ends_with("cephfs.csi.ceph.com")).name; - pref["many_safe"] = cfs; - } - if scs.some(|s| s.provisioner.ends_with("rbd.csi.ceph.com")) { - let rbd = scs.find(|s| s.provisioner.ends_with("rbd.csi.ceph.com")).name; - pref["many_block"] = rbd; - pref["only_block"] = rbd; - pref["only_safe"] = rbd; - pref["many_only"] = rbd; - } - pref -} +import "storage_class_enrich" as sce; fn appslug(pkg, inst) { if pkg == inst { inst @@ -81,7 +36,7 @@ fn get_values(options, defaults) { fn run(instance, args) { let pkg = read_package_yaml(`${args.package_dir}/package.yaml`); - let scs = k8s_resource("StorageClass").list().items.map(|s| #{ name: s.metadata.name, provisioner: s.provisioner }); + let scs = sce::classes_enrich(k8s_resource("StorageClass").list().items.map(|s| #{ name: s.metadata.name, provisioner: s.provisioner, is_default: s.metadata.annotations != () && s.metadata.annotations["storageclass.kubernetes.io/is-default-class"]=="true" })); let current = ""; let controller = #{}; try { @@ -96,8 +51,8 @@ fn run(instance, args) { cluster_config["storage_classes"] = scs; let crds = k8s_resource("CustomResourceDefinition").list_meta().items; cluster_config["crds"] = crds.map(|c| c.metadata.name); - if ! ("prefered" in cluster_config) { - cluster_config["prefered"] = get_prefered_sc(scs); + if ! ("prefered_storage" in cluster_config) { + cluster_config["prefered_storage"] = sce::get_prefered_sc(scs); } if ! ("ha" in cluster_config) { let nodes = k8s_resource("Nodes").list_meta().items.map(|c| c.metadata.name); diff --git a/agent/scripts/lib/storage_class_enrich.rhai b/agent/scripts/lib/storage_class_enrich.rhai new file mode 100644 index 0000000..b7a86e0 --- /dev/null +++ b/agent/scripts/lib/storage_class_enrich.rhai @@ -0,0 +1,119 @@ +// TODO: implement more from: https://storageclass.info/csidrivers/ +// https://github.com/storageclass/storageclass.github.io/blob/main/data/csidrivers.yaml +const KNOWN_CLASS = [ + #{ + "driverClass": "cephfs.csi.ceph.com", + "accessModes": #{"readOnlyMany": true, "readWriteMany": true, "readWriteOnce": true, "readWriteOncePod": false}, + "capabilities": #{"clone": true, "dynamic": true, "expansion": true, "raw": false, "snapshot": true, "topology": false, "tracking": false}, + }, #{ + "driverClass": "rbd.csi.ceph.com", + "accessModes": #{"readOnlyMany": true, "readWriteMany": true, "readWriteOnce": true, "readWriteOncePod": true}, + "capabilities": #{"clone": true, "dynamic": true, "expansion": true, "raw": true, "snapshot": true, "topology": true, "tracking": false}, + }, #{ + "driverClass": "smb.csi.k8s.io", + "accessModes": #{"readOnlyMany": true, "readWriteMany": true, "readWriteOnce": true, "readWriteOncePod": false}, + "capabilities": #{"dynamic": true}, + }, #{ + "driverClass": "nfs.csi.k8s.io", + "accessModes": #{"readOnlyMany": true, "readWriteMany": true, "readWriteOnce": true, "readWriteOncePod": false}, + "capabilities": #{"dynamic": true}, + }, #{ + "driverClass": "k8s-sigs.io/nfs-provisioner", + "accessModes": #{"readOnlyMany": true, "readWriteMany": true, "readWriteOnce": true, "readWriteOncePod": false}, + "capabilities": #{"dynamic": true}, + }, #{ + "driverClass": "rancher.io/local-path", + "accessModes": #{"readOnlyMany": false, "readWriteMany": false, "readWriteOnce": true, "readWriteOncePod": true}, + "capabilities": #{"dynamic": true}, + }, #{ + "driverClass": "csi.scaleway.com", + "accessModes": #{"readOnlyMany": true, "readWriteMany": true, "readWriteOnce": true, "readWriteOncePod": true}, + "capabilities": #{"clone": false, "dynamic": true, "expansion": true, "raw": true, "snapshot": true, "topology": true, "tracking": false}, + }, #{ + "driverClass": "filestore.csi.storage.gke.io", + "accessModes": #{"readOnlyMany": true, "readWriteMany": true, "readWriteOnce": true, "readWriteOncePod": false}, + "capabilities": #{"dynamic": true, "file": true}, + }, #{ + "driverClass": "file.csi.azure.com", + "accessModes": #{"readOnlyMany": true, "readWriteMany": true, "readWriteOnce": true, "readWriteOncePod": false}, + "capabilities": #{"clone": false, "dynamic": true, "expansion": true, "file": true, "raw": false, "snapshot": false, "topology": false, "tracking": false}, + }, #{ + "driverClass": "efs.csi.aws.com", + "accessModes": #{"readOnlyMany": true, "readWriteMany": true, "readWriteOnce": true, "readWriteOncePod": false}, + "capabilities": #{"dynamic": true, "file": true}, + } +]; + +fn get_default_access_modes_from_all(all) { + if all.contains("ReadWriteMany") { + ["ReadWriteMany"] + } else if all.contains("ReadOnlyMany") && all.contains("ReadWriteOnce") { + ["ReadOnlyMany", "ReadWriteOnce"] + } else if all.contains("ReadWriteOncePod") { + ["ReadWriteOncePod"] + } else { + all + } +} + +fn classes_enrich(scs) { + let enriched = []; + for i in scs { + i["volumeMode"] = "Filesystem"; + let f = global::KNOWN_CLASS.find(|k| i.provisioner.contains(k.driverClass)); + if f != () { + i["capabilities"] = f.capabilities; + let keys = f.accessModes.keys(); + i["allAccessModes"] = keys.filter(|k| f.accessModes[k]).map(|s| {s.replace("read","Read");s}); + if (f.capabilities.raw == true) { + let b = i; + b["volumeMode"] = "Block"; + i["allAccessModes"] = keys.filter(|k| f.accessModes[k] && k != "ReadWriteMany"); + b["accessModes"] = get_default_access_modes_from_all(b["allAccessModes"]); + enriched.push(b); + } + i["accessModes"] = get_default_access_modes_from_all(i["allAccessModes"]); + } else { + i["capabilities"] = #{}; + i["allAccessModes"] = ["ReadWriteOnce"]; + i["accessModes"] = ["ReadWriteOnce"]; + } + enriched.push(i); + } + enriched +} + +fn get_prefered_sc(scs) { + let pref = #{ + "block_readWriteMany": (), + "block_readWriteOnce": (), + "fs_cheap_readWriteMany": (), + "fs_fast_readWriteMany": (), + "fs_readWriteMany": (), + "fs_cheap_readWriteOnce": (), + "fs_fast_readWriteOnce": (), + "fs_readWriteOnce": (), + }; + let block = scs.filter(|s| s.volumeMode=="Block"); + let fs_only = scs.filter(|s| s.volumeMode=="Filesystem" && [["ReadWriteOncePod"],["ReadWriteOnce"]].contains(s.accessModes)); + let fs_many = scs.filter(|s| s.volumeMode=="Filesystem" && s.accessModes==["ReadWriteMany"]); + if block.len() > 0 { + let many = block.filter(|s| s.accessModes==["ReadWriteMany"]); + let others = block.filter(|s| s.accessModes!=["ReadWriteMany"]); + if many.len() > 0 { + pref["block_readWriteMany"] = many[0].name; + } + if others.len() > 0 { + pref["block_readWriteOnce"] = others[0].name; + } else { + pref["block_readWriteOnce"] = many[0].name; + } + } + if fs_many.len() > 0 { + pref["fs_readWriteMany"] = fs_many[0].name; + } + if fs_only.len() > 0 { + pref["fs_readWriteOnce"] = fs_only[0].name; + } + pref +} diff --git a/agent/scripts/lib/storage_class_selector.rhai b/agent/scripts/lib/storage_class_selector.rhai new file mode 100644 index 0000000..5553e21 --- /dev/null +++ b/agent/scripts/lib/storage_class_selector.rhai @@ -0,0 +1,48 @@ +fn for_deployments(context, typed) { + let scs = context.cluster.storage_classes; + if typed=="fast" && context.cluster.prefered_storage.fs_fast_readWriteMany != () { + scs.find(|s| s.name == context.cluster.prefered_storage.fs_fast_readWriteMany && s.volumeMode == "Filesystem") + } else if typed=="cheap" && context.cluster.prefered_storage.fs_cheap_readWriteMany != () { + scs.find(|s| s.name == context.cluster.prefered_storage.fs_cheap_readWriteMany && s.volumeMode == "Filesystem") + } else if context.cluster.prefered_storage.fs_readWriteMany != () { + scs.find(|s| s.name == context.cluster.prefered_storage.fs_readWriteMany && s.volumeMode == "Filesystem") + } else if typed=="fast" && context.cluster.prefered_storage.fs_fast_readWriteOnce != () { + scs.find(|s| s.name == context.cluster.prefered_storage.fs_fast_readWriteOnce && s.volumeMode == "Filesystem") + } else if typed=="cheap" && context.cluster.prefered_storage.fs_cheap_readWriteOnce != () { + scs.find(|s| s.name == context.cluster.prefered_storage.fs_cheap_readWriteOnce && s.volumeMode == "Filesystem") + } else if context.cluster.prefered_storage.fs_readWriteOnce != () { + scs.find(|s| s.name == context.cluster.prefered_storage.fs_readWriteOnce && s.volumeMode == "Filesystem") + } else { + scs.find(|s| s.is_default) + } +} +fn for_deployments(context) { + for_deployments(context, ()); +} + +fn for_statefulsets(context, typed) { + let scs = context.cluster.storage_classes; + if typed=="fast" && context.cluster.prefered_storage.fs_fast_readWriteOnce != () { + scs.find(|s| s.name == context.cluster.prefered_storage.fs_fast_readWriteOnce && s.volumeMode == "Filesystem") + } else if typed=="cheap" && context.cluster.prefered_storage.fs_cheap_readWriteOnce != () { + scs.find(|s| s.name == context.cluster.prefered_storage.fs_cheap_readWriteOnce && s.volumeMode == "Filesystem") + } else if context.cluster.prefered_storage.fs_readWriteOnce != () { + scs.find(|s| s.name == context.cluster.prefered_storage.fs_readWriteOnce && s.volumeMode == "Filesystem") + } else { + scs.find(|s| s.is_default) + } +} +fn for_statefulsets(context) { + for_statefulsets(context, ()); +} + +fn for_vm(context) { + let scs = context.cluster.storage_classes; + if context.cluster.prefered_storage.block_readWriteMany != () { + scs.find(|s| s.name == context.cluster.prefered_storage.block_readWriteMany && s.volumeMode == "Block") + } else if context.cluster.prefered_storage.block_readWriteOnce != () { + scs.find(|s| s.name == context.cluster.prefered_storage.block_readWriteOnce && s.volumeMode == "Block") + } else { + scs.find(|s| s.is_default) + } +}