From 468f205bbd76caf60c4fdc738115e914033947f4 Mon Sep 17 00:00:00 2001 From: "Sean P. Kelly" Date: Fri, 14 Jun 2024 21:44:21 +0000 Subject: [PATCH] models: use settings SDK for models --- sources/Cargo.lock | 466 +++--- sources/Cargo.toml | 19 - sources/api/schnauzer/Cargo.toml | 10 + sources/api/schnauzer/src/helpers.rs | 32 +- sources/models/Cargo.toml | 27 +- sources/models/model-derive/Cargo.toml | 22 - sources/models/model-derive/README.md | 44 - sources/models/model-derive/README.tpl | 9 - sources/models/model-derive/build.rs | 3 - sources/models/model-derive/src/lib.rs | 175 -- sources/models/modeled-types/Cargo.toml | 29 - sources/models/modeled-types/README.md | 11 - sources/models/modeled-types/README.tpl | 9 - sources/models/modeled-types/build.rs | 3 - sources/models/modeled-types/src/ecs.rs | 311 ---- .../models/modeled-types/src/kubernetes.rs | 1415 ----------------- sources/models/modeled-types/src/lib.rs | 192 --- .../models/modeled-types/src/oci_defaults.rs | 188 --- sources/models/modeled-types/src/shared.rs | 1255 --------------- sources/models/scalar-derive/Cargo.toml | 26 - sources/models/scalar-derive/README.md | 216 --- sources/models/scalar-derive/README.tpl | 9 - sources/models/scalar-derive/build.rs | 3 - sources/models/scalar-derive/src/lib.rs | 612 ------- sources/models/scalar-derive/tests/tests.rs | 87 - sources/models/scalar/Cargo.toml | 17 - sources/models/scalar/README.md | 13 - sources/models/scalar/README.tpl | 9 - sources/models/scalar/build.rs | 3 - sources/models/scalar/src/lib.rs | 196 --- sources/models/src/de.rs | 333 ---- sources/models/src/lib.rs | 233 +-- sources/models/string_impls_for/Cargo.toml | 16 - sources/models/string_impls_for/README.md | 53 - sources/models/string_impls_for/README.tpl | 9 - sources/models/string_impls_for/build.rs | 3 - sources/models/string_impls_for/src/lib.rs | 142 -- sources/models/tests/data/mirrors-array | 7 - sources/models/tests/data/mirrors-table | 3 - .../models/tests/data/node-taint-empty-list | 2 - sources/models/tests/data/node-taint-list-val | 3 - .../models/tests/data/node-taint-single-val | 3 - sources/models/tests/data/test-incomplete-pem | 1 - sources/models/tests/data/test-pem | 1 - .../autoscaling/Cargo.toml | 19 - .../autoscaling/autoscaling.toml | 13 - .../autoscaling/src/lib.rs | 68 - .../autoscaling/src/main.rs | 18 - sources/settings-extensions/aws/Cargo.toml | 19 - sources/settings-extensions/aws/aws.toml | 13 - sources/settings-extensions/aws/src/lib.rs | 84 - sources/settings-extensions/aws/src/main.rs | 18 - .../bootstrap-containers/Cargo.toml | 19 - .../bootstrap-containers.toml | 13 - .../bootstrap-containers/src/lib.rs | 137 -- .../bootstrap-containers/src/main.rs | 20 - .../cloudformation/Cargo.toml | 19 - .../cloudformation/cloudformation.toml | 13 - .../cloudformation/src/lib.rs | 89 -- .../cloudformation/src/main.rs | 20 - .../container-registry/Cargo.toml | 19 - .../container-registry.toml | 13 - .../container-registry/src/de.rs | 47 - .../container-registry/src/lib.rs | 129 -- .../container-registry/src/main.rs | 18 - .../container-runtime/Cargo.toml | 19 - .../container-runtime/container-runtime.toml | 13 - .../container-runtime/src/lib.rs | 92 -- .../container-runtime/src/main.rs | 20 - sources/settings-extensions/dns/Cargo.toml | 19 - sources/settings-extensions/dns/dns.toml | 13 - sources/settings-extensions/dns/src/lib.rs | 84 - sources/settings-extensions/dns/src/main.rs | 18 - sources/settings-extensions/ecs/Cargo.toml | 19 - sources/settings-extensions/ecs/ecs.toml | 13 - sources/settings-extensions/ecs/src/lib.rs | 171 -- sources/settings-extensions/ecs/src/main.rs | 18 - .../host-containers/Cargo.toml | 19 - .../host-containers/host-containers.toml | 13 - .../host-containers/src/lib.rs | 120 -- .../host-containers/src/main.rs | 20 - sources/settings-extensions/kernel/Cargo.toml | 19 - .../settings-extensions/kernel/kernel.toml | 13 - sources/settings-extensions/kernel/src/lib.rs | 103 -- .../settings-extensions/kernel/src/main.rs | 18 - .../settings-extensions/metrics/Cargo.toml | 19 - .../settings-extensions/metrics/metrics.toml | 14 - .../settings-extensions/metrics/src/lib.rs | 80 - .../settings-extensions/metrics/src/main.rs | 18 - sources/settings-extensions/motd/Cargo.toml | 17 - sources/settings-extensions/motd/motd.toml | 13 - sources/settings-extensions/motd/src/lib.rs | 92 -- sources/settings-extensions/motd/src/main.rs | 16 - .../settings-extensions/network/Cargo.toml | 19 - .../settings-extensions/network/network.toml | 13 - .../settings-extensions/network/src/lib.rs | 86 - .../settings-extensions/network/src/main.rs | 18 - sources/settings-extensions/ntp/Cargo.toml | 19 - sources/settings-extensions/ntp/ntp.toml | 13 - sources/settings-extensions/ntp/src/lib.rs | 104 -- sources/settings-extensions/ntp/src/main.rs | 18 - .../oci-defaults/Cargo.toml | 20 - .../oci-defaults/oci-defaults.toml | 13 - .../oci-defaults/src/de.rs | 126 -- .../oci-defaults/src/lib.rs | 122 -- .../oci-defaults/src/main.rs | 18 - .../settings-extensions/oci-hooks/Cargo.toml | 19 - .../oci-hooks/oci-hooks.toml | 13 - .../settings-extensions/oci-hooks/src/lib.rs | 72 - .../settings-extensions/oci-hooks/src/main.rs | 18 - sources/settings-extensions/pki/Cargo.toml | 19 - sources/settings-extensions/pki/pki.toml | 13 - sources/settings-extensions/pki/src/lib.rs | 115 -- sources/settings-extensions/pki/src/main.rs | 18 - .../pki/tests/data/test-pem | 1 - .../settings-extensions/updates/Cargo.toml | 20 - .../updates/src/generate.rs | 7 - .../settings-extensions/updates/src/lib.rs | 94 -- .../settings-extensions/updates/src/main.rs | 18 - .../settings-extensions/updates/updates.toml | 13 - sources/settings-plugins/aws-dev/Cargo.toml | 24 +- sources/settings-plugins/aws-dev/src/lib.rs | 33 +- sources/settings-plugins/aws-ecs-1/Cargo.toml | 27 +- sources/settings-plugins/aws-ecs-1/src/lib.rs | 36 +- sources/settings-plugins/aws-ecs-2/Cargo.toml | 27 +- sources/settings-plugins/aws-ecs-2/src/lib.rs | 39 +- sources/settings-plugins/aws-k8s/Cargo.toml | 27 +- sources/settings-plugins/aws-k8s/src/lib.rs | 41 +- sources/settings-plugins/metal-dev/Cargo.toml | 22 +- sources/settings-plugins/metal-dev/src/lib.rs | 29 +- sources/settings-plugins/metal-k8s/Cargo.toml | 25 +- sources/settings-plugins/metal-k8s/src/lib.rs | 37 +- .../settings-plugins/vmware-dev/Cargo.toml | 22 +- .../settings-plugins/vmware-dev/src/lib.rs | 29 +- .../settings-plugins/vmware-k8s/Cargo.toml | 25 +- .../settings-plugins/vmware-k8s/src/lib.rs | 37 +- 136 files changed, 391 insertions(+), 9239 deletions(-) delete mode 100644 sources/models/model-derive/Cargo.toml delete mode 100644 sources/models/model-derive/README.md delete mode 100644 sources/models/model-derive/README.tpl delete mode 100644 sources/models/model-derive/build.rs delete mode 100644 sources/models/model-derive/src/lib.rs delete mode 100644 sources/models/modeled-types/Cargo.toml delete mode 100644 sources/models/modeled-types/README.md delete mode 100644 sources/models/modeled-types/README.tpl delete mode 100644 sources/models/modeled-types/build.rs delete mode 100644 sources/models/modeled-types/src/ecs.rs delete mode 100644 sources/models/modeled-types/src/kubernetes.rs delete mode 100644 sources/models/modeled-types/src/lib.rs delete mode 100644 sources/models/modeled-types/src/oci_defaults.rs delete mode 100644 sources/models/modeled-types/src/shared.rs delete mode 100644 sources/models/scalar-derive/Cargo.toml delete mode 100644 sources/models/scalar-derive/README.md delete mode 100644 sources/models/scalar-derive/README.tpl delete mode 100644 sources/models/scalar-derive/build.rs delete mode 100644 sources/models/scalar-derive/src/lib.rs delete mode 100644 sources/models/scalar-derive/tests/tests.rs delete mode 100644 sources/models/scalar/Cargo.toml delete mode 100644 sources/models/scalar/README.md delete mode 100644 sources/models/scalar/README.tpl delete mode 100644 sources/models/scalar/build.rs delete mode 100644 sources/models/scalar/src/lib.rs delete mode 100644 sources/models/src/de.rs delete mode 100644 sources/models/string_impls_for/Cargo.toml delete mode 100644 sources/models/string_impls_for/README.md delete mode 100644 sources/models/string_impls_for/README.tpl delete mode 100644 sources/models/string_impls_for/build.rs delete mode 100644 sources/models/string_impls_for/src/lib.rs delete mode 100644 sources/models/tests/data/mirrors-array delete mode 100644 sources/models/tests/data/mirrors-table delete mode 100644 sources/models/tests/data/node-taint-empty-list delete mode 100644 sources/models/tests/data/node-taint-list-val delete mode 100644 sources/models/tests/data/node-taint-single-val delete mode 100644 sources/models/tests/data/test-incomplete-pem delete mode 100644 sources/models/tests/data/test-pem delete mode 100644 sources/settings-extensions/autoscaling/Cargo.toml delete mode 100644 sources/settings-extensions/autoscaling/autoscaling.toml delete mode 100644 sources/settings-extensions/autoscaling/src/lib.rs delete mode 100644 sources/settings-extensions/autoscaling/src/main.rs delete mode 100644 sources/settings-extensions/aws/Cargo.toml delete mode 100644 sources/settings-extensions/aws/aws.toml delete mode 100644 sources/settings-extensions/aws/src/lib.rs delete mode 100644 sources/settings-extensions/aws/src/main.rs delete mode 100644 sources/settings-extensions/bootstrap-containers/Cargo.toml delete mode 100644 sources/settings-extensions/bootstrap-containers/bootstrap-containers.toml delete mode 100644 sources/settings-extensions/bootstrap-containers/src/lib.rs delete mode 100644 sources/settings-extensions/bootstrap-containers/src/main.rs delete mode 100644 sources/settings-extensions/cloudformation/Cargo.toml delete mode 100644 sources/settings-extensions/cloudformation/cloudformation.toml delete mode 100644 sources/settings-extensions/cloudformation/src/lib.rs delete mode 100644 sources/settings-extensions/cloudformation/src/main.rs delete mode 100644 sources/settings-extensions/container-registry/Cargo.toml delete mode 100644 sources/settings-extensions/container-registry/container-registry.toml delete mode 100644 sources/settings-extensions/container-registry/src/de.rs delete mode 100644 sources/settings-extensions/container-registry/src/lib.rs delete mode 100644 sources/settings-extensions/container-registry/src/main.rs delete mode 100644 sources/settings-extensions/container-runtime/Cargo.toml delete mode 100644 sources/settings-extensions/container-runtime/container-runtime.toml delete mode 100644 sources/settings-extensions/container-runtime/src/lib.rs delete mode 100644 sources/settings-extensions/container-runtime/src/main.rs delete mode 100644 sources/settings-extensions/dns/Cargo.toml delete mode 100644 sources/settings-extensions/dns/dns.toml delete mode 100644 sources/settings-extensions/dns/src/lib.rs delete mode 100644 sources/settings-extensions/dns/src/main.rs delete mode 100644 sources/settings-extensions/ecs/Cargo.toml delete mode 100644 sources/settings-extensions/ecs/ecs.toml delete mode 100644 sources/settings-extensions/ecs/src/lib.rs delete mode 100644 sources/settings-extensions/ecs/src/main.rs delete mode 100644 sources/settings-extensions/host-containers/Cargo.toml delete mode 100644 sources/settings-extensions/host-containers/host-containers.toml delete mode 100644 sources/settings-extensions/host-containers/src/lib.rs delete mode 100644 sources/settings-extensions/host-containers/src/main.rs delete mode 100644 sources/settings-extensions/kernel/Cargo.toml delete mode 100644 sources/settings-extensions/kernel/kernel.toml delete mode 100644 sources/settings-extensions/kernel/src/lib.rs delete mode 100644 sources/settings-extensions/kernel/src/main.rs delete mode 100644 sources/settings-extensions/metrics/Cargo.toml delete mode 100644 sources/settings-extensions/metrics/metrics.toml delete mode 100644 sources/settings-extensions/metrics/src/lib.rs delete mode 100644 sources/settings-extensions/metrics/src/main.rs delete mode 100644 sources/settings-extensions/motd/Cargo.toml delete mode 100644 sources/settings-extensions/motd/motd.toml delete mode 100644 sources/settings-extensions/motd/src/lib.rs delete mode 100644 sources/settings-extensions/motd/src/main.rs delete mode 100644 sources/settings-extensions/network/Cargo.toml delete mode 100644 sources/settings-extensions/network/network.toml delete mode 100644 sources/settings-extensions/network/src/lib.rs delete mode 100644 sources/settings-extensions/network/src/main.rs delete mode 100644 sources/settings-extensions/ntp/Cargo.toml delete mode 100644 sources/settings-extensions/ntp/ntp.toml delete mode 100644 sources/settings-extensions/ntp/src/lib.rs delete mode 100644 sources/settings-extensions/ntp/src/main.rs delete mode 100644 sources/settings-extensions/oci-defaults/Cargo.toml delete mode 100644 sources/settings-extensions/oci-defaults/oci-defaults.toml delete mode 100644 sources/settings-extensions/oci-defaults/src/de.rs delete mode 100644 sources/settings-extensions/oci-defaults/src/lib.rs delete mode 100644 sources/settings-extensions/oci-defaults/src/main.rs delete mode 100644 sources/settings-extensions/oci-hooks/Cargo.toml delete mode 100644 sources/settings-extensions/oci-hooks/oci-hooks.toml delete mode 100644 sources/settings-extensions/oci-hooks/src/lib.rs delete mode 100644 sources/settings-extensions/oci-hooks/src/main.rs delete mode 100644 sources/settings-extensions/pki/Cargo.toml delete mode 100644 sources/settings-extensions/pki/pki.toml delete mode 100644 sources/settings-extensions/pki/src/lib.rs delete mode 100644 sources/settings-extensions/pki/src/main.rs delete mode 100644 sources/settings-extensions/pki/tests/data/test-pem delete mode 100644 sources/settings-extensions/updates/Cargo.toml delete mode 100644 sources/settings-extensions/updates/src/generate.rs delete mode 100644 sources/settings-extensions/updates/src/lib.rs delete mode 100644 sources/settings-extensions/updates/src/main.rs delete mode 100644 sources/settings-extensions/updates/updates.toml diff --git a/sources/Cargo.lock b/sources/Cargo.lock index 8d9334436d4..b8bfbf3d0dd 100644 --- a/sources/Cargo.lock +++ b/sources/Cargo.lock @@ -224,9 +224,9 @@ dependencies = [ [[package]] name = "asn1-rs" -version = "0.5.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" +checksum = "22ad1373757efa0f70ec53939aabc7152e1591cb485208052993070ac8d2429d" dependencies = [ "asn1-rs-derive", "asn1-rs-impl", @@ -240,25 +240,25 @@ dependencies = [ [[package]] name = "asn1-rs-derive" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" +checksum = "7378575ff571966e99a744addeff0bff98b8ada0dedf1956d59e634db95eaac1" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.66", "synstructure", ] [[package]] name = "asn1-rs-impl" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.66", ] [[package]] @@ -324,6 +324,37 @@ dependencies = [ "walkdir", ] +[[package]] +name = "bottlerocket-model-derive" +version = "0.1.0" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" +dependencies = [ + "darling 0.20.8", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "bottlerocket-modeled-types" +version = "0.1.0" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" +dependencies = [ + "base64", + "bottlerocket-scalar", + "bottlerocket-scalar-derive", + "bottlerocket-string-impls-for", + "indexmap", + "lazy_static", + "regex", + "semver", + "serde", + "serde_json", + "serde_plain", + "snafu", + "url", + "x509-parser", +] + [[package]] name = "bottlerocket-release" version = "0.1.0" @@ -336,6 +367,29 @@ dependencies = [ "snafu", ] +[[package]] +name = "bottlerocket-scalar" +version = "0.1.0" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" +dependencies = [ + "serde", + "serde_plain", +] + +[[package]] +name = "bottlerocket-scalar-derive" +version = "0.1.0" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" +dependencies = [ + "bottlerocket-scalar", + "darling 0.20.8", + "proc-macro2", + "quote", + "serde", + "serde_plain", + "syn 2.0.66", +] + [[package]] name = "bottlerocket-settings-derive" version = "0.1.0" @@ -347,6 +401,40 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "bottlerocket-settings-models" +version = "0.1.0" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" +dependencies = [ + "bottlerocket-model-derive", + "bottlerocket-modeled-types", + "bottlerocket-scalar", + "bottlerocket-scalar-derive", + "bottlerocket-string-impls-for", + "libc", + "serde", + "serde_json", + "settings-extension-autoscaling", + "settings-extension-aws", + "settings-extension-bootstrap-containers", + "settings-extension-cloudformation", + "settings-extension-container-registry", + "settings-extension-container-runtime", + "settings-extension-dns", + "settings-extension-ecs", + "settings-extension-host-containers", + "settings-extension-kernel", + "settings-extension-metrics", + "settings-extension-motd", + "settings-extension-network", + "settings-extension-ntp", + "settings-extension-oci-defaults", + "settings-extension-oci-hooks", + "settings-extension-pki", + "settings-extension-updates", + "toml", +] + [[package]] name = "bottlerocket-settings-plugin" version = "0.1.0" @@ -362,7 +450,7 @@ dependencies = [ [[package]] name = "bottlerocket-settings-sdk" version = "0.1.0" -source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-sdk-v0.1.0#9cb0286b59cd4fcb5df9dd441aee8521ea5698e6" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" dependencies = [ "argh", "bottlerocket-template-helper", @@ -372,10 +460,18 @@ dependencies = [ "tracing", ] +[[package]] +name = "bottlerocket-string-impls-for" +version = "0.1.0" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" +dependencies = [ + "serde", +] + [[package]] name = "bottlerocket-template-helper" version = "0.1.0" -source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-sdk-v0.1.0#9cb0286b59cd4fcb5df9dd441aee8521ea5698e6" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" dependencies = [ "darling 0.20.8", "proc-macro2", @@ -681,9 +777,9 @@ dependencies = [ [[package]] name = "der-parser" -version = "8.2.0" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" +checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" dependencies = [ "asn1-rs", "displaydoc", @@ -1227,67 +1323,17 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "model-derive" -version = "0.1.0" -dependencies = [ - "darling 0.20.8", - "generate-readme", - "quote", - "syn 2.0.66", -] - -[[package]] -name = "modeled-types" -version = "0.1.0" -dependencies = [ - "base64", - "generate-readme", - "indexmap", - "lazy_static", - "regex", - "scalar", - "scalar-derive", - "semver", - "serde", - "serde_json", - "serde_plain", - "snafu", - "string_impls_for", - "url", - "x509-parser", -] - [[package]] name = "models" version = "0.1.0" dependencies = [ "bottlerocket-release", + "bottlerocket-settings-models", "bottlerocket-settings-plugin", "generate-readme", "libc", - "model-derive", - "modeled-types", "serde", "serde_json", - "settings-extension-autoscaling", - "settings-extension-aws", - "settings-extension-bootstrap-containers", - "settings-extension-cloudformation", - "settings-extension-container-registry", - "settings-extension-container-runtime", - "settings-extension-dns", - "settings-extension-ecs", - "settings-extension-host-containers", - "settings-extension-kernel", - "settings-extension-metrics", - "settings-extension-motd", - "settings-extension-network", - "settings-extension-ntp", - "settings-extension-oci-defaults", - "settings-extension-oci-hooks", - "settings-extension-pki", - "settings-extension-updates", "toml", ] @@ -1379,9 +1425,9 @@ dependencies = [ [[package]] name = "oid-registry" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +checksum = "1c958dd45046245b9c3c2547369bb634eb461670b2e7e0de552905801a648d1d" dependencies = [ "asn1-rs", ] @@ -1790,29 +1836,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scalar" -version = "0.1.0" -dependencies = [ - "generate-readme", - "serde", - "serde_plain", -] - -[[package]] -name = "scalar-derive" -version = "0.1.0" -dependencies = [ - "darling 0.20.8", - "generate-readme", - "proc-macro2", - "quote", - "scalar", - "serde", - "serde_plain", - "syn 2.0.66", -] - [[package]] name = "schannel" version = "0.1.23" @@ -1830,6 +1853,7 @@ dependencies = [ "argh", "async-trait", "base64", + "bottlerocket-modeled-types", "bottlerocket-release", "cached", "constants", @@ -1850,6 +1874,7 @@ dependencies = [ "serde", "serde_json", "serde_plain", + "settings-extension-oci-defaults", "simplelog", "snafu", "tokio", @@ -2088,11 +2113,12 @@ dependencies = [ [[package]] name = "settings-extension-autoscaling" version = "0.1.0" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" dependencies = [ + "bottlerocket-model-derive", + "bottlerocket-modeled-types", "bottlerocket-settings-sdk", "env_logger", - "model-derive", - "modeled-types", "serde", "serde_json", ] @@ -2100,11 +2126,12 @@ dependencies = [ [[package]] name = "settings-extension-aws" version = "0.1.0" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" dependencies = [ + "bottlerocket-model-derive", + "bottlerocket-modeled-types", "bottlerocket-settings-sdk", "env_logger", - "model-derive", - "modeled-types", "serde", "serde_json", ] @@ -2112,11 +2139,12 @@ dependencies = [ [[package]] name = "settings-extension-bootstrap-containers" version = "0.1.0" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" dependencies = [ + "bottlerocket-model-derive", + "bottlerocket-modeled-types", "bottlerocket-settings-sdk", "env_logger", - "model-derive", - "modeled-types", "serde", "serde_json", ] @@ -2124,11 +2152,12 @@ dependencies = [ [[package]] name = "settings-extension-cloudformation" version = "0.1.0" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" dependencies = [ + "bottlerocket-model-derive", + "bottlerocket-modeled-types", "bottlerocket-settings-sdk", "env_logger", - "model-derive", - "modeled-types", "serde", "serde_json", ] @@ -2136,11 +2165,12 @@ dependencies = [ [[package]] name = "settings-extension-container-registry" version = "0.1.0" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" dependencies = [ + "bottlerocket-model-derive", + "bottlerocket-modeled-types", "bottlerocket-settings-sdk", "env_logger", - "model-derive", - "modeled-types", "serde", "serde_json", ] @@ -2148,11 +2178,12 @@ dependencies = [ [[package]] name = "settings-extension-container-runtime" version = "0.1.0" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" dependencies = [ + "bottlerocket-model-derive", + "bottlerocket-modeled-types", "bottlerocket-settings-sdk", "env_logger", - "model-derive", - "modeled-types", "serde", "serde_json", ] @@ -2160,11 +2191,12 @@ dependencies = [ [[package]] name = "settings-extension-dns" version = "0.1.0" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" dependencies = [ + "bottlerocket-model-derive", + "bottlerocket-modeled-types", "bottlerocket-settings-sdk", "env_logger", - "model-derive", - "modeled-types", "serde", "serde_json", ] @@ -2172,11 +2204,12 @@ dependencies = [ [[package]] name = "settings-extension-ecs" version = "0.1.0" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" dependencies = [ + "bottlerocket-model-derive", + "bottlerocket-modeled-types", "bottlerocket-settings-sdk", "env_logger", - "model-derive", - "modeled-types", "serde", "serde_json", ] @@ -2184,11 +2217,12 @@ dependencies = [ [[package]] name = "settings-extension-host-containers" version = "0.1.0" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" dependencies = [ + "bottlerocket-model-derive", + "bottlerocket-modeled-types", "bottlerocket-settings-sdk", "env_logger", - "model-derive", - "modeled-types", "serde", "serde_json", ] @@ -2196,11 +2230,12 @@ dependencies = [ [[package]] name = "settings-extension-kernel" version = "0.1.0" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" dependencies = [ + "bottlerocket-model-derive", + "bottlerocket-modeled-types", "bottlerocket-settings-sdk", "env_logger", - "model-derive", - "modeled-types", "serde", "serde_json", ] @@ -2208,11 +2243,12 @@ dependencies = [ [[package]] name = "settings-extension-metrics" version = "0.1.0" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" dependencies = [ + "bottlerocket-model-derive", + "bottlerocket-modeled-types", "bottlerocket-settings-sdk", "env_logger", - "model-derive", - "modeled-types", "serde", "serde_json", ] @@ -2220,21 +2256,24 @@ dependencies = [ [[package]] name = "settings-extension-motd" version = "0.1.0" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" dependencies = [ "bottlerocket-settings-sdk", + "bottlerocket-string-impls-for", + "env_logger", "serde", "serde_json", - "string_impls_for", ] [[package]] name = "settings-extension-network" version = "0.1.0" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" dependencies = [ + "bottlerocket-model-derive", + "bottlerocket-modeled-types", "bottlerocket-settings-sdk", "env_logger", - "model-derive", - "modeled-types", "serde", "serde_json", ] @@ -2242,11 +2281,12 @@ dependencies = [ [[package]] name = "settings-extension-ntp" version = "0.1.0" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" dependencies = [ + "bottlerocket-model-derive", + "bottlerocket-modeled-types", "bottlerocket-settings-sdk", "env_logger", - "model-derive", - "modeled-types", "serde", "serde_json", ] @@ -2254,11 +2294,12 @@ dependencies = [ [[package]] name = "settings-extension-oci-defaults" version = "0.1.0" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" dependencies = [ + "bottlerocket-model-derive", + "bottlerocket-modeled-types", "bottlerocket-settings-sdk", "env_logger", - "model-derive", - "modeled-types", "serde", "serde_json", "toml", @@ -2267,11 +2308,12 @@ dependencies = [ [[package]] name = "settings-extension-oci-hooks" version = "0.1.0" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" dependencies = [ + "bottlerocket-model-derive", + "bottlerocket-modeled-types", "bottlerocket-settings-sdk", "env_logger", - "model-derive", - "modeled-types", "serde", "serde_json", ] @@ -2279,11 +2321,12 @@ dependencies = [ [[package]] name = "settings-extension-pki" version = "0.1.0" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" dependencies = [ + "bottlerocket-model-derive", + "bottlerocket-modeled-types", "bottlerocket-settings-sdk", "env_logger", - "model-derive", - "modeled-types", "serde", "serde_json", ] @@ -2291,11 +2334,12 @@ dependencies = [ [[package]] name = "settings-extension-updates" version = "0.1.0" +source = "git+https://github.com/bottlerocket-os/bottlerocket-settings-sdk?tag=bottlerocket-settings-models-v0.1.0#c5dfef43961795c1e7781ffc55e090883ff326d7" dependencies = [ + "bottlerocket-model-derive", + "bottlerocket-modeled-types", "bottlerocket-settings-sdk", "env_logger", - "model-derive", - "modeled-types", "rand", "serde", "serde_json", @@ -2306,26 +2350,10 @@ name = "settings-plugin-aws-dev" version = "0.1.0" dependencies = [ "abi_stable", + "bottlerocket-settings-models", "bottlerocket-settings-plugin", - "model-derive", - "modeled-types", - "models", "serde", "serde_json", - "settings-extension-aws", - "settings-extension-bootstrap-containers", - "settings-extension-cloudformation", - "settings-extension-container-registry", - "settings-extension-dns", - "settings-extension-host-containers", - "settings-extension-kernel", - "settings-extension-metrics", - "settings-extension-motd", - "settings-extension-network", - "settings-extension-ntp", - "settings-extension-oci-hooks", - "settings-extension-pki", - "settings-extension-updates", ] [[package]] @@ -2333,29 +2361,10 @@ name = "settings-plugin-aws-ecs-1" version = "0.1.0" dependencies = [ "abi_stable", + "bottlerocket-settings-models", "bottlerocket-settings-plugin", - "model-derive", - "modeled-types", - "models", "serde", "serde_json", - "settings-extension-autoscaling", - "settings-extension-aws", - "settings-extension-bootstrap-containers", - "settings-extension-cloudformation", - "settings-extension-container-registry", - "settings-extension-dns", - "settings-extension-ecs", - "settings-extension-host-containers", - "settings-extension-kernel", - "settings-extension-metrics", - "settings-extension-motd", - "settings-extension-network", - "settings-extension-ntp", - "settings-extension-oci-defaults", - "settings-extension-oci-hooks", - "settings-extension-pki", - "settings-extension-updates", ] [[package]] @@ -2363,29 +2372,10 @@ name = "settings-plugin-aws-ecs-2" version = "0.1.0" dependencies = [ "abi_stable", + "bottlerocket-settings-models", "bottlerocket-settings-plugin", - "model-derive", - "modeled-types", - "models", "serde", "serde_json", - "settings-extension-autoscaling", - "settings-extension-aws", - "settings-extension-bootstrap-containers", - "settings-extension-cloudformation", - "settings-extension-container-registry", - "settings-extension-dns", - "settings-extension-ecs", - "settings-extension-host-containers", - "settings-extension-kernel", - "settings-extension-metrics", - "settings-extension-motd", - "settings-extension-network", - "settings-extension-ntp", - "settings-extension-oci-defaults", - "settings-extension-oci-hooks", - "settings-extension-pki", - "settings-extension-updates", ] [[package]] @@ -2393,29 +2383,10 @@ name = "settings-plugin-aws-k8s" version = "0.1.0" dependencies = [ "abi_stable", + "bottlerocket-settings-models", "bottlerocket-settings-plugin", - "model-derive", - "modeled-types", - "models", "serde", "serde_json", - "settings-extension-autoscaling", - "settings-extension-aws", - "settings-extension-bootstrap-containers", - "settings-extension-cloudformation", - "settings-extension-container-registry", - "settings-extension-container-runtime", - "settings-extension-dns", - "settings-extension-host-containers", - "settings-extension-kernel", - "settings-extension-metrics", - "settings-extension-motd", - "settings-extension-network", - "settings-extension-ntp", - "settings-extension-oci-defaults", - "settings-extension-oci-hooks", - "settings-extension-pki", - "settings-extension-updates", ] [[package]] @@ -2423,24 +2394,10 @@ name = "settings-plugin-metal-dev" version = "0.1.0" dependencies = [ "abi_stable", + "bottlerocket-settings-models", "bottlerocket-settings-plugin", - "model-derive", - "modeled-types", - "models", "serde", "serde_json", - "settings-extension-bootstrap-containers", - "settings-extension-container-registry", - "settings-extension-dns", - "settings-extension-host-containers", - "settings-extension-kernel", - "settings-extension-metrics", - "settings-extension-motd", - "settings-extension-network", - "settings-extension-ntp", - "settings-extension-oci-hooks", - "settings-extension-pki", - "settings-extension-updates", ] [[package]] @@ -2448,27 +2405,10 @@ name = "settings-plugin-metal-k8s" version = "0.1.0" dependencies = [ "abi_stable", + "bottlerocket-settings-models", "bottlerocket-settings-plugin", - "model-derive", - "modeled-types", - "models", "serde", "serde_json", - "settings-extension-aws", - "settings-extension-bootstrap-containers", - "settings-extension-container-registry", - "settings-extension-container-runtime", - "settings-extension-dns", - "settings-extension-host-containers", - "settings-extension-kernel", - "settings-extension-metrics", - "settings-extension-motd", - "settings-extension-network", - "settings-extension-ntp", - "settings-extension-oci-defaults", - "settings-extension-oci-hooks", - "settings-extension-pki", - "settings-extension-updates", ] [[package]] @@ -2476,24 +2416,10 @@ name = "settings-plugin-vmware-dev" version = "0.1.0" dependencies = [ "abi_stable", + "bottlerocket-settings-models", "bottlerocket-settings-plugin", - "model-derive", - "modeled-types", - "models", "serde", "serde_json", - "settings-extension-bootstrap-containers", - "settings-extension-container-registry", - "settings-extension-dns", - "settings-extension-host-containers", - "settings-extension-kernel", - "settings-extension-metrics", - "settings-extension-motd", - "settings-extension-network", - "settings-extension-ntp", - "settings-extension-oci-hooks", - "settings-extension-pki", - "settings-extension-updates", ] [[package]] @@ -2501,27 +2427,10 @@ name = "settings-plugin-vmware-k8s" version = "0.1.0" dependencies = [ "abi_stable", + "bottlerocket-settings-models", "bottlerocket-settings-plugin", - "model-derive", - "modeled-types", - "models", "serde", "serde_json", - "settings-extension-aws", - "settings-extension-bootstrap-containers", - "settings-extension-container-registry", - "settings-extension-container-runtime", - "settings-extension-dns", - "settings-extension-host-containers", - "settings-extension-kernel", - "settings-extension-metrics", - "settings-extension-motd", - "settings-extension-network", - "settings-extension-ntp", - "settings-extension-oci-defaults", - "settings-extension-oci-hooks", - "settings-extension-pki", - "settings-extension-updates", ] [[package]] @@ -2636,14 +2545,6 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -[[package]] -name = "string_impls_for" -version = "0.1.0" -dependencies = [ - "generate-readme", - "serde", -] - [[package]] name = "strsim" version = "0.10.0" @@ -2686,14 +2587,13 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "synstructure" -version = "0.12.6" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", - "unicode-xid", + "syn 2.0.66", ] [[package]] @@ -3010,12 +2910,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - [[package]] name = "unindent" version = "0.1.11" @@ -3342,9 +3236,9 @@ dependencies = [ [[package]] name = "x509-parser" -version = "0.15.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7069fba5b66b9193bd2c5d3d4ff12b839118f6bcbef5328efafafb5395cf63da" +checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" dependencies = [ "asn1-rs", "data-encoding", diff --git a/sources/Cargo.toml b/sources/Cargo.toml index f9339a8dc19..88712d49f9c 100644 --- a/sources/Cargo.toml +++ b/sources/Cargo.toml @@ -34,25 +34,6 @@ members = [ "settings-defaults/vmware-dev", "settings-defaults/vmware-k8s-1.30", - "settings-extensions/autoscaling", - "settings-extensions/aws", - "settings-extensions/bootstrap-containers", - "settings-extensions/cloudformation", - "settings-extensions/container-registry", - "settings-extensions/container-runtime", - "settings-extensions/dns", - "settings-extensions/ecs", - "settings-extensions/host-containers", - "settings-extensions/kernel", - "settings-extensions/metrics", - "settings-extensions/motd", - "settings-extensions/network", - "settings-extensions/ntp", - "settings-extensions/oci-defaults", - "settings-extensions/oci-hooks", - "settings-extensions/pki", - "settings-extensions/updates", - # (all previous migrations archived; add new ones after this line) "settings-migrations/v1.21.0/pluto-remove-generators-v0-1-0", "settings-migrations/v1.21.0/pod-infra-container-image-affected-services", diff --git a/sources/api/schnauzer/Cargo.toml b/sources/api/schnauzer/Cargo.toml index 3a3e87caeb2..a2e88559127 100644 --- a/sources/api/schnauzer/Cargo.toml +++ b/sources/api/schnauzer/Cargo.toml @@ -42,6 +42,16 @@ tokio = { version = "~1.32", default-features = false, features = ["macros", "rt toml = "0.8" url = "2" +[dependencies.bottlerocket-modeled-types] +git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" +tag = "bottlerocket-settings-models-v0.1.0" +version = "0.1.0" + +[dependencies.settings-extension-oci-defaults] +git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" +tag = "bottlerocket-settings-models-v0.1.0" +version = "0.1.0" + [dev-dependencies] # Workaround to enable a feature during integration tests. schnauzer = { path = ".", version = "0.1.0", features = ["testfakes"] } diff --git a/sources/api/schnauzer/src/helpers.rs b/sources/api/schnauzer/src/helpers.rs index aad4b85aa1b..ca42885ab51 100644 --- a/sources/api/schnauzer/src/helpers.rs +++ b/sources/api/schnauzer/src/helpers.rs @@ -3,17 +3,17 @@ // text at render time. use base64::Engine; +use bottlerocket_modeled_types::{OciDefaultsCapability, OciDefaultsResourceLimitType}; use dns_lookup::lookup_host; use handlebars::{ handlebars_helper, Context, Handlebars, Helper, HelperDef, Output, RenderContext, RenderError, Renderable, }; use lazy_static::lazy_static; -use model::modeled_types::{OciDefaultsCapability, OciDefaultsResourceLimitType}; -use model::OciDefaultsResourceLimit; use serde::Deserialize; use serde_json::value::Value; use serde_plain::derive_fromstr_from_deserialize; +use settings_extension_oci_defaults::OciDefaultsResourceLimitV1; use snafu::{OptionExt, ResultExt}; use std::borrow::Borrow; use std::collections::HashMap; @@ -1263,7 +1263,7 @@ pub fn localhost_aliases( let mut results: Vec = vec![]; - let hosts: Option = (!hosts_value.is_null()) + let hosts: Option = (!hosts_value.is_null()) .then(|| { serde_json::from_value(hosts_value.clone()).context( error::UnparseableTemplateValueSnafu { @@ -1342,12 +1342,14 @@ pub fn etc_hosts_entries( // Otherwise we need to generate /etc/hosts lines, ignoring loopback. let mut result_lines: Vec = Vec::new(); - let hosts: model::modeled_types::EtcHostsEntries = serde_json::from_value(hosts_value.clone()) - .context(error::UnparseableTemplateValueSnafu { - expected: "EtcHostsEntries", - value: hosts_value.to_owned(), - template: template_name.to_owned(), - })?; + let hosts: bottlerocket_modeled_types::EtcHostsEntries = serde_json::from_value( + hosts_value.clone(), + ) + .context(error::UnparseableTemplateValueSnafu { + expected: "EtcHostsEntries", + value: hosts_value.to_owned(), + template: template_name.to_owned(), + })?; trace!("Hosts from template: {:?}", hosts); hosts @@ -1565,7 +1567,7 @@ impl Runtime { fn get_resource_limits( &self, rlimit_type: &OciDefaultsResourceLimitType, - values: &OciDefaultsResourceLimit, + values: &OciDefaultsResourceLimitV1, ) -> String { match self { Self::Docker => Docker::get_resource_limits(rlimit_type, values), @@ -1586,7 +1588,7 @@ impl Docker { /// Formats resource limits for Docker fn get_resource_limits( rlimit_type: &OciDefaultsResourceLimitType, - values: &OciDefaultsResourceLimit, + values: &OciDefaultsResourceLimitV1, ) -> String { format!( r#" "{}":{{ "Name": "{}", "Hard": {}, "Soft": {} }}"#, @@ -1628,7 +1630,7 @@ impl Containerd { /// Formats resource limits for Containerd fn get_resource_limits( rlimit_type: &OciDefaultsResourceLimitType, - values: &OciDefaultsResourceLimit, + values: &OciDefaultsResourceLimitV1, ) -> String { format!( r#"{{ "type": "{}", "hard": {}, "soft": {} }}"#, @@ -1771,7 +1773,7 @@ fn oci_spec_capabilities(value: &Value) -> Result { /// the settings data from the datastore (`settings.oci-defaults.resource-limits`). fn oci_spec_resource_limits( value: &Value, -) -> Result, RenderError> { +) -> Result, RenderError> { Ok(serde_json::from_value(value.clone())?) } @@ -1915,7 +1917,7 @@ fn kube_cpu_helper(num_cores: usize) -> Result { /// If `configured_hosts` is set, the hostname will be considered resolvable if it is listed as an alias for any given IP address. fn hostname_resolveable( hostname: &str, - configured_hosts: Option<&model::modeled_types::EtcHostsEntries>, + configured_hosts: Option<&bottlerocket_modeled_types::EtcHostsEntries>, ) -> bool { // If the hostname is in our configured hosts, then it *will* be resolvable when /etc/hosts is rendered. // Note that DNS search paths in /etc/resolv.conf are not relevant here, as they are not checked when searching /etc/hosts. @@ -2836,7 +2838,7 @@ mod test_etc_hosts_helpers { assert!(hostname_resolveable( "unresolveable.irrelevanthostname.tld", Some( - &serde_json::from_str::( + &serde_json::from_str::( r#"[["10.0.0.1", ["unresolveable.irrelevanthostname.tld"]]]"# ) .unwrap() diff --git a/sources/models/Cargo.toml b/sources/models/Cargo.toml index 75770a7ae03..ab7e9b874d1 100644 --- a/sources/models/Cargo.toml +++ b/sources/models/Cargo.toml @@ -12,38 +12,21 @@ exclude = ["README.md"] [dependencies] bottlerocket-release = { path = "../bottlerocket-release", version = "0.1" } libc = "0.2" -model-derive = { path = "model-derive", version = "0.1" } -modeled-types = { path = "modeled-types", version = "0.1" } serde = { version = "1", features = ["derive"] } serde_json = "1" toml = "0.8" -# settings extensions -settings-extension-autoscaling = { path = "../settings-extensions/autoscaling", version = "0.1" } -settings-extension-aws = { path = "../settings-extensions/aws", version = "0.1" } -settings-extension-bootstrap-containers = { path = "../settings-extensions/bootstrap-containers", version = "0.1" } -settings-extension-cloudformation = { path = "../settings-extensions/cloudformation", version = "0.1" } -settings-extension-container-registry = { path = "../settings-extensions/container-registry", version = "0.1" } -settings-extension-container-runtime = { path = "../settings-extensions/container-runtime", version = "0.1" } -settings-extension-dns = { path = "../settings-extensions/dns", version = "0.1" } -settings-extension-ecs = { path = "../settings-extensions/ecs", version = "0.1" } -settings-extension-host-containers = { path = "../settings-extensions/host-containers", version = "0.1" } -settings-extension-kernel = { path = "../settings-extensions/kernel", version = "0.1" } -settings-extension-metrics = { path = "../settings-extensions/metrics", version = "0.1" } -settings-extension-motd = { path = "../settings-extensions/motd", version = "0.1" } -settings-extension-network = { path = "../settings-extensions/network", version = "0.1" } -settings-extension-ntp = { path = "../settings-extensions/ntp", version = "0.1" } -settings-extension-oci-defaults = { path = "../settings-extensions/oci-defaults", version = "0.1" } -settings-extension-oci-hooks = { path = "../settings-extensions/oci-hooks", version = "0.1" } -settings-extension-pki = { path = "../settings-extensions/pki", version = "0.1" } -settings-extension-updates = { path = "../settings-extensions/updates", version = "0.1" } - # settings plugins [dependencies.bottlerocket-settings-plugin] git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" tag = "bottlerocket-settings-plugin-v0.1.0" version = "0.1.0" +[dependencies.bottlerocket-settings-models] +git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" +tag = "bottlerocket-settings-models-v0.1.0" +version = "0.1.0" + [build-dependencies] generate-readme = { version = "0.1", path = "../generate-readme" } diff --git a/sources/models/model-derive/Cargo.toml b/sources/models/model-derive/Cargo.toml deleted file mode 100644 index 24869fb8a3a..00000000000 --- a/sources/models/model-derive/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "model-derive" -version = "0.1.0" -authors = ["Tom Kirchner "] -license = "Apache-2.0 OR MIT" -edition = "2021" -publish = false -build = "build.rs" -# Don't rebuild crate just because of changes to README. -exclude = ["README.md"] - -[lib] -path = "src/lib.rs" -proc-macro = true - -[dependencies] -darling = "0.20" -quote = "1" -syn = { version = "2", default-features = false, features = ["full", "parsing", "printing", "proc-macro", "visit-mut"] } - -[build-dependencies] -generate-readme = { version = "0.1", path = "../../generate-readme" } diff --git a/sources/models/model-derive/README.md b/sources/models/model-derive/README.md deleted file mode 100644 index 754380acd32..00000000000 --- a/sources/models/model-derive/README.md +++ /dev/null @@ -1,44 +0,0 @@ -# model-derive - -Current version: 0.1.0 - -## Overview - -This module provides a attribute-style procedural macro, `model`, that makes sure a struct is -ready to be used as an API model. - -The goal is to reduce cognitive overhead when reading models. -We do this by automatically specifying required attributes on structs and fields. - -Several arguments are available to override default behavior; see below. - -## Changes it makes - -### Visibility - -All types must be public, so `pub` is added. -Override this (at a per-struct or per-field level) by specifying your own visibility. - -### Derives - -All structs must serde-`Serializable` and -`Deserializable`, and comparable via `PartialEq`. -`Debug` is added for convenience. -`Default` can also be added by specifying the argument `impl_default = true`. - -### Serde - -Structs have a `#[serde(...)]` attribute added to deny unknown fields and rename fields to kebab-case. -The struct can be renamed (for ser/de purposes) by specifying the argument `rename = "bla"`. - -Fields have a `#[serde(...)]` attribute added to skip `Option` fields that are `None`. -This is because we accept updates in the API that are structured the same way as the model, but we don't want to require users to specify fields they aren't changing. -This can be disabled by specifying the argument `add_option = false`. - -### Option - -Fields are all wrapped in `Option<...>`. -Similar to the `serde` attribute added to fields, this is because we don't want users to have to specify fields they aren't changing, and can be disabled the same way, by specifying `add_option = false`. - -## Colophon - -This text was generated from `README.tpl` using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/lib.rs`. diff --git a/sources/models/model-derive/README.tpl b/sources/models/model-derive/README.tpl deleted file mode 100644 index 91fb62910c8..00000000000 --- a/sources/models/model-derive/README.tpl +++ /dev/null @@ -1,9 +0,0 @@ -# {{crate}} - -Current version: {{version}} - -{{readme}} - -## Colophon - -This text was generated from `README.tpl` using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/lib.rs`. diff --git a/sources/models/model-derive/build.rs b/sources/models/model-derive/build.rs deleted file mode 100644 index 42defdba22e..00000000000 --- a/sources/models/model-derive/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - generate_readme::from_lib().unwrap(); -} diff --git a/sources/models/model-derive/src/lib.rs b/sources/models/model-derive/src/lib.rs deleted file mode 100644 index 7fcd3c614d2..00000000000 --- a/sources/models/model-derive/src/lib.rs +++ /dev/null @@ -1,175 +0,0 @@ -/*! -# Overview - -This module provides a attribute-style procedural macro, `model`, that makes sure a struct is -ready to be used as an API model. - -The goal is to reduce cognitive overhead when reading models. -We do this by automatically specifying required attributes on structs and fields. - -Several arguments are available to override default behavior; see below. - -# Changes it makes - -## Visibility - -All types must be public, so `pub` is added. -Override this (at a per-struct or per-field level) by specifying your own visibility. - -## Derives - -All structs must serde-`Serializable` and -`Deserializable`, and comparable via `PartialEq`. -`Debug` is added for convenience. -`Default` can also be added by specifying the argument `impl_default = true`. - -## Serde - -Structs have a `#[serde(...)]` attribute added to deny unknown fields and rename fields to kebab-case. -The struct can be renamed (for ser/de purposes) by specifying the argument `rename = "bla"`. - -Fields have a `#[serde(...)]` attribute added to skip `Option` fields that are `None`. -This is because we accept updates in the API that are structured the same way as the model, but we don't want to require users to specify fields they aren't changing. -This can be disabled by specifying the argument `add_option = false`. - -## Option - -Fields are all wrapped in `Option<...>`. -Similar to the `serde` attribute added to fields, this is because we don't want users to have to specify fields they aren't changing, and can be disabled the same way, by specifying `add_option = false`. -*/ - -extern crate proc_macro; - -use darling::{ast::NestedMeta, FromMeta}; -use proc_macro::TokenStream; -use quote::ToTokens; -use syn::visit_mut::{self, VisitMut}; -use syn::{parse_quote, Attribute, Field, ItemStruct, Visibility}; - -/// Define a `#[model]` attribute that can be placed on structs to be used in an API model. -/// Model requirements are automatically applied to the struct and its fields. -/// (The attribute must be placed on sub-structs; it can't be recursively applied to structs -/// referenced in the given struct.) -#[proc_macro_attribute] -pub fn model(args: TokenStream, input: TokenStream) -> TokenStream { - // Parse args - let args: ParsedArgs = ParsedArgs::from_list( - &NestedMeta::parse_meta_list(args.into()) - .expect("Unable to parse arguments to `model` macro"), - ) - .expect("Unable to parse arguments to `model` macro"); - let mut helper = ModelHelper::from(args); - - // Parse and modify source - let mut ast: ItemStruct = - syn::parse(input).expect("Unable to parse item `model` was placed on - is it a struct?"); - helper.visit_item_struct_mut(&mut ast); - ast.into_token_stream().into() -} - -/// Store any args given by the user inside `#[model(...)]`. -#[derive(Debug, Default, FromMeta)] -#[darling(default)] -struct ParsedArgs { - rename: Option, - impl_default: Option, - add_option: Option, -} - -/// Stores the user's requested options, plus any defaults for unspecified options. -#[derive(Debug)] -struct ModelHelper { - rename: Option, - impl_default: bool, - add_option: bool, -} - -/// Takes the user's requested options and sets default values for anything unspecified. -impl From for ModelHelper { - fn from(args: ParsedArgs) -> Self { - // Add any default values - ModelHelper { - rename: args.rename, - impl_default: args.impl_default.unwrap_or(false), - add_option: args.add_option.unwrap_or(true), - } - } -} - -/// VisitMut helps us modify the node types we want without digging through the huge token trees -/// need to represent them. -impl VisitMut for ModelHelper { - // Visit struct definitions. - fn visit_item_struct_mut(&mut self, node: &mut ItemStruct) { - if let Visibility::Inherited = node.vis { - node.vis = parse_quote!(pub) - } - - // Add our serde attribute, if the user hasn't set one - if !is_attr_set("serde", &node.attrs) { - // Rename the struct, if the user requested - let attr = if let Some(ref rename_to) = self.rename { - parse_quote!( - #[serde(deny_unknown_fields, rename_all = "kebab-case", rename = #rename_to)] - ) - } else { - parse_quote!( - #[serde(deny_unknown_fields, rename_all = "kebab-case")] - ) - }; - node.attrs.push(attr); - } - - // Add our derives, if the user hasn't set any - if !is_attr_set("derive", &node.attrs) { - // Derive Default, if the user requested - let attr = if self.impl_default { - parse_quote!(#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]) - } else { - parse_quote!(#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]) - }; - // Rust 1.52 added a legacy_derive_helpers warning (soon to be an error) that yells if - // you use an attribute macro before the derive macro that introduces it. We should - // always put derive macros at the start of the list to avoid this. - node.attrs.insert(0, attr); - } - - // Let the default implementation do its thing, recursively. - visit_mut::visit_item_struct_mut(self, node); - } - - // Visit field definitions in structs. - fn visit_field_mut(&mut self, node: &mut Field) { - if let Visibility::Inherited = node.vis { - node.vis = parse_quote!(pub) - } - - // Add our serde attribute, if the user hasn't set one - if self.add_option { - if !is_attr_set("serde", &node.attrs) { - node.attrs.push(parse_quote!( - #[serde(skip_serializing_if = "Option::is_none")] - )); - } - - // Wrap each field's type in `Option<...>` - let ty = &node.ty; - node.ty = parse_quote!(Option<#ty>); - } - - // Let the default implementation do its thing, recursively. - visit_mut::visit_field_mut(self, node); - } -} - -/// Checks whether an attribute named `attr_name` (e.g. "serde") is set in the given list of -/// `syn::Attribute`s. -fn is_attr_set(attr_name: &'static str, attrs: &[Attribute]) -> bool { - for attr in attrs { - if let Some(name) = attr.path().get_ident() { - if name == attr_name { - return true; - } - } - } - false -} diff --git a/sources/models/modeled-types/Cargo.toml b/sources/models/modeled-types/Cargo.toml deleted file mode 100644 index 00146d94522..00000000000 --- a/sources/models/modeled-types/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "modeled-types" -version = "0.1.0" -authors = [] -license = "Apache-2.0 OR MIT" -edition = "2021" -publish = false -build = "build.rs" -# Don't rebuild crate just because of changes to README. -exclude = ["README.md"] - -[dependencies] -base64 = "0.21" -indexmap = { version = "2", features = ["serde"] } -lazy_static = "1" -regex = "1" -scalar = { path = "../scalar", version = "0.1" } -scalar-derive = { path = "../scalar-derive", version = "0.1" } -semver = "1" -serde = "1" -serde_json = "1" -serde_plain = "1" -snafu = "0.8" -string_impls_for = { path = "../string_impls_for", version = "0.1" } -url = "2" -x509-parser = "0.15" - -[build-dependencies] -generate-readme = { path = "../../generate-readme", version = "0.1" } diff --git a/sources/models/modeled-types/README.md b/sources/models/modeled-types/README.md deleted file mode 100644 index 861caec580a..00000000000 --- a/sources/models/modeled-types/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# modeled-types - -Current version: 0.1.0 - -This module contains data types that can be used in the model when special input/output -(ser/de) behavior is desired. For example, the ValidBase64 type can be used for a model field -when we don't even want to accept an API call with invalid base64 data. - -## Colophon - -This text was generated from `README.tpl` using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/lib.rs`. diff --git a/sources/models/modeled-types/README.tpl b/sources/models/modeled-types/README.tpl deleted file mode 100644 index 91fb62910c8..00000000000 --- a/sources/models/modeled-types/README.tpl +++ /dev/null @@ -1,9 +0,0 @@ -# {{crate}} - -Current version: {{version}} - -{{readme}} - -## Colophon - -This text was generated from `README.tpl` using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/lib.rs`. diff --git a/sources/models/modeled-types/build.rs b/sources/models/modeled-types/build.rs deleted file mode 100644 index 42defdba22e..00000000000 --- a/sources/models/modeled-types/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - generate_readme::from_lib().unwrap(); -} diff --git a/sources/models/modeled-types/src/ecs.rs b/sources/models/modeled-types/src/ecs.rs deleted file mode 100644 index 678f7217c5e..00000000000 --- a/sources/models/modeled-types/src/ecs.rs +++ /dev/null @@ -1,311 +0,0 @@ -use lazy_static::lazy_static; -use regex::Regex; -use serde::{Deserialize, Serialize}; -// Just need serde's Error in scope to get its trait methods -use super::error::{self, big_pattern_error}; -use scalar::traits::{Scalar, Validate}; -use scalar::ValidationError; -use scalar_derive::Scalar; -use snafu::ensure; -use std::convert::TryFrom; -use string_impls_for::string_impls_for; - -/// ECSAttributeKey represents a string that contains a valid ECS attribute key. It stores -/// the original string and makes it accessible through standard traits. -// https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_Attribute.html -#[allow(clippy::derived_hash_with_manual_eq)] -#[derive(Debug, Clone, Eq, PartialEq, Hash, Scalar)] -pub struct ECSAttributeKey { - inner: String, -} - -// The name of the attribute. The name must contain between 1 and 128 -// characters and name may contain letters (uppercase and lowercase), numbers, -// hyphens, underscores, forward slashes, back slashes, or periods. -lazy_static! { - pub(crate) static ref ECS_ATTRIBUTE_KEY: Regex = Regex::new( - r"(?x)^ - [a-zA-Z0-9._/-]{1,128} - $" - ) - .unwrap(); -} - -impl Validate for ECSAttributeKey { - fn validate>(input: S) -> std::result::Result { - let input = input.into(); - require!( - ECS_ATTRIBUTE_KEY.is_match(&input), - big_pattern_error("ECS attribute key", &input) - ); - Ok(ECSAttributeKey { inner: input }) - } -} - -#[cfg(test)] -mod test_ecs_attribute_key { - use super::ECSAttributeKey; - use std::convert::TryFrom; - - #[test] - fn good_keys() { - for key in &[ - "a", - "alphabetical", - "1234567890", - "with-dash", - "have.period/slash", - "have_underscore_too", - &"a".repeat(128), - ".leadingperiod", - "trailingperiod.", - ] { - ECSAttributeKey::try_from(*key).unwrap(); - } - } - - #[test] - fn bad_keys() { - for key in &[ - "", - &"a".repeat(129), - "@", - "$", - "%", - ":", - "no spaces allowed", - ] { - ECSAttributeKey::try_from(*key).unwrap_err(); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// ECSAttributeValue represents a string that contains a valid ECS attribute value. It stores -/// the original string and makes it accessible through standard traits. -// https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_Attribute.html -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct ECSAttributeValue { - inner: String, -} - -// The value of the attribute. The value must contain between 1 and 128 -// characters and may contain letters (uppercase and lowercase), numbers, -// hyphens, underscores, periods, at signs (@), forward slashes, back slashes, -// colons, or spaces. The value cannot contain any leading or trailing -// whitespace. -lazy_static! { - pub(crate) static ref ECS_ATTRIBUTE_VALUE: Regex = Regex::new( - r"(?x)^ - [a-zA-Z0-9.@:_/\\-] # at least one non-space - ( - ([a-zA-Z0-9.@:\ _/\\-]{0,126})? # spaces allowed - [a-zA-Z0-9.@:_/\\-] # end with non-space - )? - $" - ) - .unwrap(); -} - -impl TryFrom<&str> for ECSAttributeValue { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - ensure!( - ECS_ATTRIBUTE_VALUE.is_match(input), - error::BigPatternSnafu { - thing: "ECS attribute value", - input - } - ); - Ok(ECSAttributeValue { - inner: input.to_string(), - }) - } -} - -string_impls_for!(ECSAttributeValue, "ECSAttributeValue"); - -#[cfg(test)] -mod test_ecs_attribute_value { - use super::ECSAttributeValue; - use std::convert::TryFrom; - - #[test] - fn good_vals() { - for val in &[ - "a", - "alphabetical", - "1234567890", - "with-dash", - "have.period/slash", - "have/slash\\backslash", - "have_underscore_too", - "with spaces in between", - &"a".repeat(128), - ".leadingperiod", - "trailingperiod.", - "@ and : allowed too", - "\\", - "\\ \\", - ] { - ECSAttributeValue::try_from(*val).unwrap(); - } - } - - #[test] - fn bad_vals() { - for val in &[ - "", - &"a".repeat(129), - "$", - "%", - " leading space", - "trailing space ", - ] { - ECSAttributeValue::try_from(*val).unwrap_err(); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// ECSAgentLogLevel represents a string that contains a valid ECS log level for the ECS agent. -#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Scalar)] -#[serde(rename_all = "lowercase")] -pub enum ECSAgentLogLevel { - Debug, - Info, - Warn, - // Rename needed due to #[deny(ambiguous_associated_items)] - // see https://github.com/rust-lang/rust/issues/57644 - #[serde(rename = "error")] - ErrorLevel, - Crit, -} - -#[cfg(test)] -mod test_ecs_agent_log_level { - use super::ECSAgentLogLevel; - use std::convert::TryFrom; - - #[test] - fn good_vals() { - for val in &["debug", "info", "warn"] { - ECSAgentLogLevel::try_from(*val).unwrap(); - } - } - - #[test] - fn bad_vals() { - for val in &["", "warning", "errors", " "] { - ECSAgentLogLevel::try_from(*val).unwrap_err(); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// ECSAgentImagePullBehavior represents a valid ECS Image Pull Behavior for the ECS agent. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Scalar)] -#[serde(rename_all = "kebab-case")] -#[repr(u8)] -pub enum ECSAgentImagePullBehavior { - Default = 0, - Always, - Once, - PreferCached, -} - -impl ECSAgentImagePullBehavior { - pub fn as_u8(&self) -> u8 { - *self as u8 - } -} - -#[cfg(test)] -mod test_ecs_agent_image_pull_behavior { - use super::ECSAgentImagePullBehavior; - use std::convert::TryFrom; - - #[test] - fn good_vals() { - for val in &["default", "always", "once", "prefer-cached"] { - ECSAgentImagePullBehavior::try_from(*val).unwrap(); - } - } - - #[test] - fn bad_vals() { - for val in &["", "tomorrow", "never", " "] { - ECSAgentImagePullBehavior::try_from(*val).unwrap_err(); - } - } -} - -/// ECSDurationValue represents a string that contains a valid ECS duration value -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct ECSDurationValue { - inner: String, -} - -lazy_static! { - pub(crate) static ref ECS_DURATION_VALUE: Regex = - Regex::new(r"^(([0-9]+\.)?[0-9]+h)?(([0-9]+\.)?[0-9]+m)?(([0-9]+\.)?[0-9]+s)?(([0-9]+\.)?[0-9]+ms)?(([0-9]+\.)?[0-9]+(u|µ)s)?(([0-9]+\.)?[0-9]+ns)?$").unwrap(); -} - -impl TryFrom<&str> for ECSDurationValue { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - ensure!( - !input.is_empty() && ECS_DURATION_VALUE.is_match(input), - error::InvalidECSDurationValueSnafu { input } - ); - Ok(ECSDurationValue { - inner: input.to_string(), - }) - } -} - -string_impls_for!(ECSDurationValue, "ECSDurationValue"); - -#[cfg(test)] -mod test_ecs_duration_value { - use super::ECSDurationValue; - use std::convert::TryFrom; - - #[test] - fn valid_values() { - for ok in &[ - "99s", - "20m", - "1h", - "1h2m3s", - "4m5s", - "2h3s", - "1.5h3.5m", - "1ms1us1ns", - "1s1µs1ns", - ] { - ECSDurationValue::try_from(*ok).unwrap(); - } - } - - #[test] - fn invalid_values() { - for err in &[ - "", - "100", - "...3ms", - "1..5s", - "ten second", - "1m2h", - "1y2w", - &"a".repeat(23), - ] { - ECSDurationValue::try_from(*err).unwrap_err(); - } - } -} diff --git a/sources/models/modeled-types/src/kubernetes.rs b/sources/models/modeled-types/src/kubernetes.rs deleted file mode 100644 index 40f37b45e83..00000000000 --- a/sources/models/modeled-types/src/kubernetes.rs +++ /dev/null @@ -1,1415 +0,0 @@ -use super::error; -use lazy_static::lazy_static; -use regex::Regex; -use scalar_derive::Scalar; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -// Just need serde's Error in scope to get its trait methods -use serde::de::Error as _; -use serde_json::Value; -use snafu::{ensure, ResultExt}; -use std::collections::HashMap; -use std::convert::TryFrom; -use std::fmt::{self, Display, Formatter}; -use std::net::IpAddr; -use string_impls_for::string_impls_for; - -use crate::SingleLineString; - -// Declare constant values usable by any type -const IMAGE_GC_THRESHOLD_MAX: i32 = 100; -const IMAGE_GC_THRESHOLD_MIN: i32 = 0; - -/// KubernetesName represents a string that contains a valid Kubernetes resource name. It stores -/// the original string and makes it accessible through standard traits. -// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct KubernetesName { - inner: String, -} - -lazy_static! { - pub(crate) static ref KUBERNETES_NAME: Regex = Regex::new(r"^[0-9a-z.-]{1,253}$").unwrap(); -} - -impl TryFrom<&str> for KubernetesName { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - ensure!( - KUBERNETES_NAME.is_match(input), - error::PatternSnafu { - thing: "Kubernetes name", - pattern: KUBERNETES_NAME.clone(), - input - } - ); - Ok(KubernetesName { - inner: input.to_string(), - }) - } -} - -string_impls_for!(KubernetesName, "KubernetesName"); - -#[cfg(test)] -mod test_kubernetes_name { - use super::KubernetesName; - use std::convert::TryFrom; - - #[test] - fn good_names() { - for ok in &["howdy", "42", "18-eighteen."] { - KubernetesName::try_from(*ok).unwrap(); - } - } - - #[test] - fn bad_names() { - for err in &["", "HOWDY", "@", "hi/there", &"a".repeat(254)] { - KubernetesName::try_from(*err).unwrap_err(); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// KubernetesLabelKey represents a string that contains a valid Kubernetes label key. It stores -/// the original string and makes it accessible through standard traits. -// https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#syntax-and-character-set -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct KubernetesLabelKey { - inner: String, -} - -lazy_static! { - pub(crate) static ref KUBERNETES_LABEL_KEY: Regex = Regex::new( - r"(?x)^ - ( # optional prefix - [[:alnum:].-]{1,253}/ # DNS label characters followed by slash - )? - [[:alnum:]] # at least one alphanumeric - ( - ([[:alnum:]._-]{0,61})? # more characters allowed in middle - [[:alnum:]] # have to end with alphanumeric - )? - $" - ) - .unwrap(); -} - -impl TryFrom<&str> for KubernetesLabelKey { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - ensure!( - KUBERNETES_LABEL_KEY.is_match(input), - error::BigPatternSnafu { - thing: "Kubernetes label key", - input - } - ); - Ok(KubernetesLabelKey { - inner: input.to_string(), - }) - } -} - -string_impls_for!(KubernetesLabelKey, "KubernetesLabelKey"); - -#[cfg(test)] -mod test_kubernetes_label_key { - use super::KubernetesLabelKey; - use std::convert::TryFrom; - - #[test] - fn good_keys() { - for ok in &[ - "no-prefix", - "have.a/prefix", - "more-chars_here.now", - &"a".repeat(63), - &format!("{}/{}", "a".repeat(253), "name"), - ] { - KubernetesLabelKey::try_from(*ok).unwrap(); - } - } - - #[test] - fn bad_keys() { - for err in &[ - ".bad", - "bad.", - &"a".repeat(64), - &format!("{}/{}", "a".repeat(254), "name"), - ] { - KubernetesLabelKey::try_from(*err).unwrap_err(); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// KubernetesLabelValue represents a string that contains a valid Kubernetes label value. It -/// stores the original string and makes it accessible through standard traits. -// https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#syntax-and-character-set -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct KubernetesLabelValue { - inner: String, -} - -lazy_static! { - pub(crate) static ref KUBERNETES_LABEL_VALUE: Regex = Regex::new( - r"(?x) - ^$ | # may be empty, or: - ^ - [[:alnum:]] # at least one alphanumeric - ( - ([[:alnum:]._-]{0,61})? # more characters allowed in middle - [[:alnum:]] # have to end with alphanumeric - )? - $ - " - ) - .unwrap(); -} - -impl TryFrom<&str> for KubernetesLabelValue { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - ensure!( - KUBERNETES_LABEL_VALUE.is_match(input), - error::BigPatternSnafu { - thing: "Kubernetes label value", - input - } - ); - Ok(KubernetesLabelValue { - inner: input.to_string(), - }) - } -} - -string_impls_for!(KubernetesLabelValue, "KubernetesLabelValue"); - -#[cfg(test)] -mod test_kubernetes_label_value { - use super::KubernetesLabelValue; - use std::convert::TryFrom; - - #[test] - fn good_values() { - for ok in &["", "more-chars_here.now", &"a".repeat(63)] { - KubernetesLabelValue::try_from(*ok).unwrap(); - } - } - - #[test] - fn bad_values() { - for err in &[".bad", "bad.", &"a".repeat(64)] { - KubernetesLabelValue::try_from(*err).unwrap_err(); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// KubernetesTaintValue represents a string that contains a valid Kubernetes taint value, which is -/// like a label value, plus a colon, plus an "effect". It stores the original string and makes it -/// accessible through standard traits. -/// -/// Note: Kubelet won't launch if you specify an effect it doesn't know about, but we don't want to -/// gatekeep all possible values, so be careful. -// Note: couldn't find an exact spec for this. Cobbling things together, and guessing a bit as to -// the syntax of the effect. -// https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#syntax-and-character-set -// https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct KubernetesTaintValue { - inner: String, -} - -lazy_static! { - pub(crate) static ref KUBERNETES_TAINT_VALUE: Regex = Regex::new( - r"(?x)^ - ( - [[:alnum:]] # values have to start with alphanumeric if they're specified - ( - ([[:alnum:]._-]{0,61})? # more characters allowed in middle - [[:alnum:]] # values have to end with alphanumeric - )? # only the first alphanumeric is required, further chars optional - )? # the taint value is optional - : # separate the taint value from the effect - [[:alnum:]]{1,253} # effect - $" - ) - .unwrap(); -} - -impl TryFrom<&str> for KubernetesTaintValue { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - ensure!( - KUBERNETES_TAINT_VALUE.is_match(input), - error::BigPatternSnafu { - thing: "Kubernetes taint value", - input - } - ); - Ok(KubernetesTaintValue { - inner: input.to_string(), - }) - } -} - -string_impls_for!(KubernetesTaintValue, "KubernetesTaintValue"); - -#[cfg(test)] -mod test_kubernetes_taint_value { - use super::KubernetesTaintValue; - use std::convert::TryFrom; - - #[test] - fn good_values() { - // All the examples from the docs linked above - for ok in &[ - "value:NoSchedule", - "value:PreferNoSchedule", - "value:NoExecute", - ":NoSchedule", - "a:NoSchedule", - "a-b:NoSchedule", - ] { - KubernetesTaintValue::try_from(*ok).unwrap(); - } - } - - #[test] - fn bad_values() { - for err in &[ - ".bad", - "bad.", - &"a".repeat(254), - "value:", - ":", - "-a:NoSchedule", - "a-:NoSchedule", - ] { - KubernetesTaintValue::try_from(*err).unwrap_err(); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// KubernetesClusterName represents a string that contains a valid Kubernetes cluster name. It -/// stores the original string and makes it accessible through standard traits. -// Note: I was unable to find the rules for cluster naming. We know they have to fit into label -// values, because of the common cluster-name label, but they also can't be empty. This combines -// those two characteristics into a new type, until we find an explicit syntax. -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct KubernetesClusterName { - inner: String, -} - -impl TryFrom<&str> for KubernetesClusterName { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - ensure!( - !input.is_empty(), - error::InvalidClusterNameSnafu { - name: input, - msg: "must not be empty" - } - ); - ensure!( - KubernetesLabelValue::try_from(input).is_ok(), - error::InvalidClusterNameSnafu { - name: input, - msg: "cluster names must be valid Kubernetes label values" - } - ); - - Ok(KubernetesClusterName { - inner: input.to_string(), - }) - } -} - -string_impls_for!(KubernetesClusterName, "KubernetesClusterName"); - -#[cfg(test)] -mod test_kubernetes_cluster_name { - use super::KubernetesClusterName; - use std::convert::TryFrom; - - #[test] - fn good_cluster_names() { - for ok in &["more-chars_here.now", &"a".repeat(63)] { - KubernetesClusterName::try_from(*ok).unwrap(); - } - } - - #[test] - fn bad_values() { - for err in &["", ".bad", "bad.", &"a".repeat(64)] { - KubernetesClusterName::try_from(*err).unwrap_err(); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// KubernetesAuthenticationMode represents a string that is a valid authentication mode for the -/// kubelet. It stores the original string and makes it accessible through standard traits. -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct KubernetesAuthenticationMode { - inner: String, -} - -impl TryFrom<&str> for KubernetesAuthenticationMode { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - ensure!( - matches!(input, "aws" | "tls"), - error::InvalidAuthenticationModeSnafu { input } - ); - Ok(KubernetesAuthenticationMode { - inner: input.to_string(), - }) - } -} - -string_impls_for!(KubernetesAuthenticationMode, "KubernetesAuthenticationMode"); - -#[cfg(test)] -mod test_kubernetes_authentication_mode { - use super::KubernetesAuthenticationMode; - use std::convert::TryFrom; - - #[test] - fn good_modes() { - for ok in &["aws", "tls"] { - KubernetesAuthenticationMode::try_from(*ok).unwrap(); - } - } - - #[test] - fn bad_modes() { - for err in &["", "anonymous"] { - KubernetesAuthenticationMode::try_from(*err).unwrap_err(); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// KubernetesBootstrapToken represents a string that is a valid bootstrap token for Kubernetes. -/// It stores the original string and makes it accessible through standard traits. -// https://kubernetes.io/docs/reference/access-authn-authz/bootstrap-tokens/ -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct KubernetesBootstrapToken { - inner: String, -} - -lazy_static! { - pub(crate) static ref KUBERNETES_BOOTSTRAP_TOKEN: Regex = - Regex::new(r"^[a-z0-9]{6}\.[a-z0-9]{16}$").unwrap(); -} - -impl TryFrom<&str> for KubernetesBootstrapToken { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - ensure!( - KUBERNETES_BOOTSTRAP_TOKEN.is_match(input), - error::PatternSnafu { - thing: "Kubernetes bootstrap token", - pattern: KUBERNETES_BOOTSTRAP_TOKEN.clone(), - input - } - ); - Ok(KubernetesBootstrapToken { - inner: input.to_string(), - }) - } -} - -string_impls_for!(KubernetesBootstrapToken, "KubernetesBootstrapToken"); - -#[cfg(test)] -mod test_kubernetes_bootstrap_token { - use super::KubernetesBootstrapToken; - use std::convert::TryFrom; - - #[test] - fn good_tokens() { - for ok in &["abcdef.0123456789abcdef", "07401b.f395accd246ae52d"] { - KubernetesBootstrapToken::try_from(*ok).unwrap(); - } - } - - #[test] - fn bad_names() { - for err in &["", "ABCDEF.0123456789ABCDEF", "secret", &"a".repeat(23)] { - KubernetesBootstrapToken::try_from(*err).unwrap_err(); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// KubernetesEvictionKey represents a string that contains a valid Kubernetes eviction key. -/// https://kubernetes.io/docs/tasks/administer-cluster/out-of-resource/ - -#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Scalar)] -#[serde(rename_all = "lowercase")] -pub enum KubernetesEvictionKey { - #[serde(rename = "memory.available")] - MemoryAvailable, - #[serde(rename = "nodefs.available")] - NodefsAvailable, - #[serde(rename = "nodefs.inodesFree")] - NodefsInodesFree, - #[serde(rename = "imagefs.available")] - ImagefsAvailable, - #[serde(rename = "imagefs.inodesFree")] - ImagefsInodesFree, - #[serde(rename = "pid.available")] - PidAvailable, -} - -#[cfg(test)] -mod test_kubernetes_eviction_key { - use super::KubernetesEvictionKey; - use std::convert::TryFrom; - - #[test] - fn good_eviction_key() { - for ok in &[ - "memory.available", - "nodefs.available", - "nodefs.inodesFree", - "imagefs.available", - "imagefs.inodesFree", - "pid.available", - ] { - KubernetesEvictionKey::try_from(*ok).unwrap(); - } - } - - #[test] - fn bad_eviction_key() { - for err in &["", "storage.available", ".bad", "bad.", &"a".repeat(64)] { - KubernetesEvictionKey::try_from(*err).unwrap_err(); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// KubernetesThresholdValue represents a string that contains a valid kubernetes threshold value. - -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct KubernetesThresholdValue { - inner: String, -} - -// Regular expression of Kubernetes quantity. i.e. 128974848, 129e6, 129M, 123Mi -lazy_static! { - pub(crate) static ref KUBERNETES_QUANTITY: Regex = Regex::new( - r"(?x) - # format1 for scientific notations (e.g. 123e4) or: - ^([+-]?[0-9.]+)((e)?[0-9]*)$ | - # format2 for values with unit suffixes [EPTGMK] and [EiPiTiGiMiKi] (e.g. 100K or 100Ki), - # or no units (e.g. 100) or: - ^([+-]?[0-9.]+)((E|P|T|G|M|K)i?)?$ | - # format3 for values with unit suffixes [numk] (e.g. 100n 1000k) - ^([+-]?[0-9.]+)(n|u|m|k)?$ - " - ) - .unwrap(); -} - -impl TryFrom<&str> for KubernetesThresholdValue { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - if let Some(stripped) = input.strip_suffix('%') { - let input_f32 = stripped - .parse::() - .context(error::InvalidPercentageSnafu { input })?; - ensure!( - (0.0..100.0).contains(&input_f32), - error::InvalidThresholdPercentageSnafu { input } - ); - } else { - ensure!( - KUBERNETES_QUANTITY.is_match(input), - error::PatternSnafu { - thing: "Kubernetes quantity", - pattern: KUBERNETES_QUANTITY.clone(), - input - } - ); - } - Ok(KubernetesThresholdValue { - inner: input.to_string(), - }) - } -} -string_impls_for!(KubernetesThresholdValue, "KubernetesThresholdValue"); - -#[cfg(test)] -mod test_kubernetes_threshold_value { - use super::KubernetesThresholdValue; - use std::convert::TryFrom; - - #[test] - fn good_kubernetes_threshold_value() { - for ok in &[ - "10%", "129e6", "10Mi", "1024M", "1Gi", "120Ki", "1Ti", "1000n", "100m", - ] { - KubernetesThresholdValue::try_from(*ok).unwrap(); - } - } - - #[test] - fn bad_kubernetes_threshold_value() { - for err in &[ - "", - "anything%", - "12ki", - "100e23m", - "1100KTi", - "100Kiii", - "1000i", - &"a".repeat(64), - ] { - KubernetesThresholdValue::try_from(*err).unwrap_err(); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// KubernetesReservedResourceKey represents a string that contains a valid Kubernetes kubeReserved -/// and systemReserved resources i.e. cpu, memory. -/// https://kubernetes.io/docs/tasks/administer-cluster/reserve-compute-resources/ - -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct KubernetesReservedResourceKey { - inner: String, -} - -#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize)] -#[serde(rename_all = "lowercase")] -enum ReservedResources { - Cpu, - Memory, - #[serde(rename = "ephemeral-storage")] - EphemeralStorage, -} - -impl TryFrom<&str> for KubernetesReservedResourceKey { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - serde_plain::from_str::(input).context( - error::InvalidPlainValueSnafu { - field: "Reserved sources key", - }, - )?; - Ok(KubernetesReservedResourceKey { - inner: input.to_string(), - }) - } -} -string_impls_for!( - KubernetesReservedResourceKey, - "KubernetesReservedResourceKey" -); - -#[cfg(test)] -mod test_reserved_resources_key { - use super::KubernetesReservedResourceKey; - use std::convert::TryFrom; - - #[test] - fn good_reserved_resources_key() { - for ok in &["cpu", "memory", "ephemeral-storage"] { - KubernetesReservedResourceKey::try_from(*ok).unwrap(); - } - } - - #[test] - fn bad_reserved_resources_key() { - for err in &["", "cpa", ".bad", "bad.", &"a".repeat(64)] { - KubernetesReservedResourceKey::try_from(*err).unwrap_err(); - } - } -} - -/// // =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// KubernetesQuantityValue represents a string that contains a valid kubernetes quantity value. -/// https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct KubernetesQuantityValue { - inner: String, -} - -impl TryFrom<&str> for KubernetesQuantityValue { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - ensure!( - KUBERNETES_QUANTITY.is_match(input), - error::PatternSnafu { - thing: "Kubernetes quantity", - pattern: KUBERNETES_QUANTITY.clone(), - input - } - ); - - Ok(KubernetesQuantityValue { - inner: input.to_string(), - }) - } -} -string_impls_for!(KubernetesQuantityValue, "KubernetesQuantityValue"); - -#[cfg(test)] -mod test_kubernetes_quantity_value { - use super::KubernetesQuantityValue; - use std::convert::TryFrom; - - #[test] - fn good_kubernetes_quantity_value() { - for ok in &[ - "129e6", "10Mi", "1024M", "1Gi", "120Ki", "1Ti", "1000n", "100m", - ] { - KubernetesQuantityValue::try_from(*ok).unwrap(); - } - } - - #[test] - fn bad_kubernetes_quantity_value() { - for err in &[ - "", - "12%", - "anything%", - "12ki", - "100e23m", - "1100KTi", - "100Kiii", - "1000i", - &"a".repeat(64), - ] { - KubernetesQuantityValue::try_from(*err).unwrap_err(); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// KubernetesCloudProvider represents a string that is a valid cloud provider for the -/// kubelet. It stores the original string and makes it accessible through standard traits. -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct KubernetesCloudProvider { - inner: String, -} - -impl TryFrom<&str> for KubernetesCloudProvider { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - // Kubelet expects the empty string to be double-quoted when be passed to `--cloud-provider` - let cloud_provider = if input.is_empty() { "\"\"" } else { input }; - ensure!( - matches!(cloud_provider, "aws" | "external" | "\"\""), - error::InvalidCloudProviderSnafu { - input: cloud_provider - } - ); - Ok(KubernetesCloudProvider { - inner: cloud_provider.to_string(), - }) - } -} - -string_impls_for!(KubernetesCloudProvider, "KubernetesCloudProvider"); - -#[cfg(test)] -mod test_kubernetes_cloud_provider { - use super::KubernetesCloudProvider; - use std::convert::TryFrom; - - #[test] - fn allowed_providers() { - for ok in &["aws", "external", "\"\"", ""] { - KubernetesCloudProvider::try_from(*ok).unwrap(); - } - } - - #[test] - fn disallowed_providers() { - { - let err = &"internal"; - KubernetesCloudProvider::try_from(*err).unwrap_err(); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// CpuManagerPolicy represents a string that contains a valid cpu management policy. Default: none -/// https://kubernetes.io/docs/tasks/administer-cluster/cpu-management-policies/ - -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct CpuManagerPolicy { - inner: String, -} -#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize)] -#[serde(rename_all = "lowercase")] -enum ValidCpuManagerPolicy { - #[serde(alias = "Static")] - Static, - #[serde(alias = "None")] - None, -} - -impl TryFrom<&str> for CpuManagerPolicy { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - serde_plain::from_str::(input) - .context(error::InvalidCpuManagerPolicySnafu { input })?; - Ok(CpuManagerPolicy { - inner: input.to_string(), - }) - } -} -string_impls_for!(CpuManagerPolicy, "CpuManagerPolicy"); - -#[cfg(test)] -mod test_cpu_manager_policy { - use super::CpuManagerPolicy; - use std::convert::TryFrom; - - #[test] - fn good_cpu_manager_policy() { - for ok in &["Static", "static", "None", "none"] { - CpuManagerPolicy::try_from(*ok).unwrap(); - } - } - - #[test] - fn bad_cpu_manager_policy() { - for err in &["", "bad", "100", &"a".repeat(64)] { - CpuManagerPolicy::try_from(*err).unwrap_err(); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// KubernetesDurationValue represents a string that contains a valid Kubernetes duration value. -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct KubernetesDurationValue { - inner: String, -} - -lazy_static! { - pub(crate) static ref KUBERNETES_DURATION_VALUE: Regex = Regex::new( - r"^(([0-9]+\.)?[0-9]+h)?(([0-9]+\.)?[0-9]+m)?(([0-9]+\.)?[0-9]+s)?(([0-9]+\.)?[0-9]+ms)?$" - ) - .unwrap(); -} - -impl TryFrom<&str> for KubernetesDurationValue { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - ensure!( - !input.is_empty(), - error::InvalidKubernetesDurationValueSnafu { input } - ); - ensure!( - KUBERNETES_DURATION_VALUE.is_match(input), - error::InvalidKubernetesDurationValueSnafu { input } - ); - Ok(KubernetesDurationValue { - inner: input.to_string(), - }) - } -} - -string_impls_for!(KubernetesDurationValue, "KubernetesDurationValue"); - -#[cfg(test)] -mod test_kubernetes_duration_value { - use super::KubernetesDurationValue; - use std::convert::TryFrom; - - #[test] - fn good_tokens() { - for ok in &[ - "9ms", - "99s", - "20m", - "1h", - "1h2m3s10ms", - "4m5s10ms", - "2h3s10ms", - "1.5h3.5m", - ] { - KubernetesDurationValue::try_from(*ok).unwrap(); - } - } - - #[test] - fn bad_names() { - for err in &[ - "", - "100", - "...3ms", - "1..5s", - "ten second", - "1m2h", - "9ns", - &"a".repeat(23), - ] { - KubernetesDurationValue::try_from(*err).unwrap_err(); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// TopologyManagerScope represents a string that contains a valid topology management scope. Default: container -/// https://kubernetes.io/docs/tasks/administer-cluster/topology-manager/ - -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct TopologyManagerScope { - inner: String, -} -#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize)] -#[serde(rename_all = "lowercase")] -enum ValidTopologyManagerScope { - Container, - Pod, -} - -impl TryFrom<&str> for TopologyManagerScope { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - serde_plain::from_str::(input) - .context(error::InvalidTopologyManagerScopeSnafu { input })?; - Ok(TopologyManagerScope { - inner: input.to_string(), - }) - } -} -string_impls_for!(TopologyManagerScope, "TopologyManagerScope"); - -#[cfg(test)] -mod test_topology_manager_scope { - use super::TopologyManagerScope; - use std::convert::TryFrom; - - #[test] - fn good_topology_manager_scope() { - for ok in &["container", "pod"] { - TopologyManagerScope::try_from(*ok).unwrap(); - } - } - - #[test] - fn bad_topology_manager_scope() { - for err in &["", "bad", "100", &"a".repeat(64)] { - TopologyManagerScope::try_from(*err).unwrap_err(); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// TopologyManagerPolicy represents a string that contains a valid topology management policy. Default: none -/// https://kubernetes.io/docs/tasks/administer-cluster/topology-manager/ - -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct TopologyManagerPolicy { - inner: String, -} -#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize)] -#[serde(rename_all = "lowercase")] -enum ValidTopologyManagerPolicy { - None, - Restricted, - #[serde(rename = "best-effort")] - BestEffort, - #[serde(rename = "single-numa-node")] - SingleNumaNode, -} - -impl TryFrom<&str> for TopologyManagerPolicy { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - serde_plain::from_str::(input) - .context(error::InvalidTopologyManagerPolicySnafu { input })?; - Ok(TopologyManagerPolicy { - inner: input.to_string(), - }) - } -} -string_impls_for!(TopologyManagerPolicy, "TopologyManagerPolicy"); - -#[cfg(test)] -mod test_topology_manager_policy { - use super::TopologyManagerPolicy; - use std::convert::TryFrom; - - #[test] - fn good_topology_manager_policy() { - for ok in &["none", "restricted", "best-effort", "single-numa-node"] { - TopologyManagerPolicy::try_from(*ok).unwrap(); - } - } - - #[test] - fn bad_topology_manager_policy() { - for err in &["", "bad", "100", &"a".repeat(64)] { - TopologyManagerPolicy::try_from(*err).unwrap_err(); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// This enum is used by `IntegerPercent` to "remember" how the number was deserialized. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] -enum IntegerPercentMode { - Number, - String, -} - -/// This type allows for the representation of `imageGCHighThresholdPercent` and -/// `imageGCHighThresholdPercent` as numbers in Bottlerocket userdata and API interactions. -/// See https://github.com/bottlerocket-os/bottlerocket/issues/2883 -/// -/// The type "remembers" whether it was deserialized from a string or a number and reserializes the -/// same way. This allows for backward compatibility where users may expect these to be strings, but -/// allows for new userdata/API-interactions to represent these as numbers. -/// -/// ## About Kubernetes GC Threshold Percent -/// -/// `imageGCHighThresholdPercent` and `imageGCHighThresholdPercent` are percentages of disk usage -/// after which image garbage collection is always run. The percent is calculated by dividing by -/// 100, so this field must be between 0 and 100, inclusive. When specified, the value of -/// `imageGCHighThresholdPercent` must be greater than `imageGCHighThresholdPercent`, however this -/// is not enforced by the Bottlerocket API. -/// Default: 85 -/// https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/ -/// -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] -pub struct IntegerPercent { - value: i32, - mode: IntegerPercentMode, -} - -impl IntegerPercent { - fn new(value: i32, mode: IntegerPercentMode) -> Result { - ensure!( - (IMAGE_GC_THRESHOLD_MIN..=IMAGE_GC_THRESHOLD_MAX).contains(&value), - error::InvalidImageGCLowThresholdPercentSnafu { - input: value.to_string(), - msg: "must be between 0 and 100 (inclusive)" - } - ); - Ok(Self { value, mode }) - } -} - -impl Display for IntegerPercent { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - Display::fmt(&self.value, f) - } -} - -impl Serialize for IntegerPercent { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self.mode { - IntegerPercentMode::Number => self.value.serialize(serializer), - IntegerPercentMode::String => { - let s = self.value.to_string(); - s.serialize(serializer) - } - } - } -} - -impl<'de> Deserialize<'de> for IntegerPercent { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - // We need to deserialize it first into a type that can handle both numbers and strings. - let json_value = Value::deserialize(deserializer)?; - - // We expect the json_value to be either a string or a number, but either way we need to - // convert it to a string and parse it because we cannot cast a json number to i32. - let (s, mode) = match &json_value { - Value::Number(n) => (n.to_string(), IntegerPercentMode::Number), - Value::String(s) => (s.clone(), IntegerPercentMode::String), - _ => { - return Err(D::Error::custom(format!( - "Unable to deserialize value, it is not a number or a string: {:?}", - json_value, - ))) - } - }; - - let value = s - .parse::() - .map_err(|e| D::Error::custom(format!("Unable to parse {} as an integer: {}", s, e)))?; - - // This new function will clamp the range to 0..100 with a nice error message. - Self::new(value, mode).map_err(|e| D::Error::custom(e.to_string())) - } -} - -#[cfg(test)] -mod test_integer_percent { - use super::{IntegerPercent, IntegerPercentMode}; - use serde::{Deserialize, Serialize}; - use serde_json::json; - use serde_plain::derive_fromstr_from_deserialize; - use std::fmt::Debug; - use std::str::FromStr; - - #[derive(Debug, Serialize, Deserialize)] - struct Object { - number: IntegerPercent, - } - - #[test] - fn valid_string_42() { - let json_value = json!({"number":"42"}); - let json = serde_json::to_string_pretty(&json_value).unwrap(); - let object: Object = serde_json::from_value(json_value).unwrap(); - assert_eq!(object.number.value, 42); - assert!(matches!(object.number.mode, IntegerPercentMode::String)); - let serialized = serde_json::to_string_pretty(&object).unwrap(); - assert_eq!(json, serialized); - } - - #[test] - fn valid_number_42() { - let json_value = json!({"number":42}); - let json = serde_json::to_string_pretty(&json_value).unwrap(); - let object: Object = serde_json::from_value(json_value).unwrap(); - assert_eq!(object.number.value, 42); - assert!(matches!(object.number.mode, IntegerPercentMode::Number)); - let serialized = serde_json::to_string_pretty(&object).unwrap(); - assert_eq!(json, serialized); - } - - #[test] - fn invalid_string_not_a_number() { - let json_value = json!({"number":"foo"}); - assert!(serde_json::from_value::(json_value).is_err()); - } - - #[test] - fn invalid_string_out_of_range() { - let json_value = json!({"number":"99999999"}); - assert!(serde_json::from_value::(json_value).is_err()); - } - - #[test] - fn invalid_number_out_of_range() { - let json_value = json!({"number":99999999}); - assert!(serde_json::from_value::(json_value).is_err()); - } - - // Adding these impls to preserve legacy tests as they were written. - derive_fromstr_from_deserialize!(IntegerPercent); - impl TryFrom<&str> for IntegerPercent { - type Error = serde_plain::Error; - fn try_from(value: &str) -> Result { - Self::from_str(value) - } - } - - // legacy test 1: good values should succeed - #[test] - fn image_gc_threshold_percent_between_0_and_100_inclusive() { - for ok in &["0", "1", "99", "100"] { - IntegerPercent::try_from(*ok).unwrap(); - } - } - - // legacy test 2: values too low should return Errors - #[test] - fn image_gc_threshold_percent_less_than_0_fails() { - IntegerPercent::try_from("-1").unwrap_err(); - } - - // legacy test 3: values too high should return Errors - #[test] - fn image_gc_threshold_percent_greater_than_100_fails() { - IntegerPercent::try_from("101").unwrap_err(); - } - - // pseudo-legacy test 4: empty values should return Errors - #[test] - fn image_gc_threshold_percent_empty() { - IntegerPercent::try_from("").unwrap_err(); - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// KubernetesClusterDnsIp represents the --cluster-dns settings for kubelet. -/// -/// This model allows the value to be either a list of IPs, or a single IP string -/// for backwards compatibility. -#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] -#[serde(untagged)] -pub enum KubernetesClusterDnsIp { - Scalar(IpAddr), - Vector(Vec), -} - -impl KubernetesClusterDnsIp { - pub fn iter<'a>(&'a self) -> Box + 'a> { - match self { - Self::Scalar(inner) => Box::new(std::iter::once(inner)), - Self::Vector(inner) => Box::new(inner.iter()), - } - } -} - -impl IntoIterator for KubernetesClusterDnsIp { - type Item = IpAddr; - type IntoIter = std::vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - match self { - Self::Scalar(inner) => vec![inner], - Self::Vector(inner) => inner, - } - .into_iter() - } -} - -#[cfg(test)] -mod test_cluster_dns_ip { - use super::KubernetesClusterDnsIp; - use std::net::IpAddr; - use std::str::FromStr; - - #[test] - fn test_parse_cluster_dns_ip_from_str() { - assert_eq!( - serde_json::from_str::(r#""127.0.0.1""#).unwrap(), - KubernetesClusterDnsIp::Scalar(IpAddr::from_str("127.0.0.1").unwrap()) - ); - assert_eq!( - serde_json::from_str::(r#""::1""#).unwrap(), - KubernetesClusterDnsIp::Scalar(IpAddr::from_str("::1").unwrap()) - ); - } - - #[test] - fn test_parse_cluster_dns_ip_from_list() { - assert_eq!( - serde_json::from_str::(r#"[]"#).unwrap(), - KubernetesClusterDnsIp::Vector(vec![]) - ); - assert_eq!( - serde_json::from_str::(r#"["127.0.0.1", "::1"]"#).unwrap(), - KubernetesClusterDnsIp::Vector(vec![ - IpAddr::from_str("127.0.0.1").unwrap(), - IpAddr::from_str("::1").unwrap() - ]) - ); - } - - #[test] - fn test_iter_cluster_dns_ips() { - assert_eq!( - KubernetesClusterDnsIp::Vector(vec![]) - .iter() - .collect::>(), - Vec::<&IpAddr>::new(), - ); - - assert_eq!( - KubernetesClusterDnsIp::Vector(vec![ - IpAddr::from_str("127.0.0.1").unwrap(), - IpAddr::from_str("::1").unwrap() - ]) - .iter() - .collect::>(), - vec![ - &IpAddr::from_str("127.0.0.1").unwrap(), - &IpAddr::from_str("::1").unwrap() - ] - ); - - assert_eq!( - KubernetesClusterDnsIp::Scalar(IpAddr::from_str("127.0.0.1").unwrap()) - .iter() - .collect::>(), - vec![&IpAddr::from_str("127.0.0.1").unwrap()], - ); - } - - #[test] - fn test_first_cluster_dns_ips() { - assert_eq!(KubernetesClusterDnsIp::Vector(vec![]).iter().next(), None); - - assert_eq!( - KubernetesClusterDnsIp::Vector(vec![ - IpAddr::from_str("127.0.0.1").unwrap(), - IpAddr::from_str("::1").unwrap() - ]) - .iter() - .next(), - Some(&IpAddr::from_str("127.0.0.1").unwrap()) - ); - - assert_eq!( - KubernetesClusterDnsIp::Scalar(IpAddr::from_str("127.0.0.1").unwrap()) - .iter() - .next(), - Some(&IpAddr::from_str("127.0.0.1").unwrap()) - ); - } -} - -type EnvVarMap = HashMap; - -/// CredentialProvider contains the settings for a credential provider for use -/// in CredentialProviderConfig. -#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub struct CredentialProvider { - enabled: bool, - image_patterns: Vec, - cache_duration: Option, - environment: Option, -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// KubernetesCPUManagerPolicyOption values are the possible option names for the cpuManagerPolicyOptions. -#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Scalar)] -pub enum KubernetesCPUManagerPolicyOption { - #[serde(rename = "full-pcpus-only")] - FullPCPUsOnly, -} - -#[cfg(test)] -mod test_kubernetes_cpu_manager_policy_option { - use super::KubernetesCPUManagerPolicyOption; - use std::convert::TryFrom; - - #[test] - fn good_cpu_manager_policy_option() { - { - let ok = &"full-pcpus-only"; - KubernetesCPUManagerPolicyOption::try_from(*ok).unwrap(); - } - } - - #[test] - fn bad_cpu_manager_policy_option() { - for err in &["fullPCPUSOnly", "", "align-by-socket"] { - KubernetesCPUManagerPolicyOption::try_from(*err).unwrap_err(); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// KubernetesMemoryReservationKey represents a string that contains a valid Kubernetes memory -/// resource reservation key. -#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Scalar)] -pub enum KubernetesMemoryReservationKey { - #[serde(rename = "memory")] - Memory, - #[serde(rename = "hugepages-2Mi")] - HugePages2Mi, - #[serde(rename = "hugepages-1Gi")] - HugePages1Gi, -} - -#[cfg(test)] -mod test_memory_reservation_key { - use super::KubernetesMemoryReservationKey; - use std::convert::TryFrom; - - #[test] - fn good_memory_reservation_key() { - for ok in &["memory", "hugepages-2Mi", "hugepages-1Gi"] { - KubernetesMemoryReservationKey::try_from(*ok).unwrap(); - } - } - - #[test] - fn bad_memory_reservation_key() { - for err in &["", "cpu", "hugepages-1Mi", "HugePages_1Gi", &"a".repeat(64)] { - KubernetesMemoryReservationKey::try_from(*err).unwrap_err(); - } - } -} - -/// KubernetesMemoryReservation enables setting kubelet reserved memory values. -#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub struct KubernetesMemoryReservation { - enabled: bool, - #[serde(flatten)] - limits: HashMap, -} - -/// KubernetesMemoryManagerPolicy represents the valid options for the memory manager policy. -#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Scalar)] -pub enum KubernetesMemoryManagerPolicy { - #[serde(alias = "static")] - Static, - #[serde(alias = "none")] - None, -} - -#[cfg(test)] -mod test_kubernetes_memory_manager_policy { - use super::KubernetesMemoryManagerPolicy; - use std::convert::TryFrom; - - #[test] - fn good_policy_key() { - for ok in &["Static", "static", "None", "none"] { - KubernetesMemoryManagerPolicy::try_from(*ok).unwrap(); - } - } - - #[test] - fn bad_policy_key() { - for err in &["", "dynamic", &"a".repeat(64)] { - KubernetesMemoryManagerPolicy::try_from(*err).unwrap_err(); - } - } -} diff --git a/sources/models/modeled-types/src/lib.rs b/sources/models/modeled-types/src/lib.rs deleted file mode 100644 index 9ee46c04715..00000000000 --- a/sources/models/modeled-types/src/lib.rs +++ /dev/null @@ -1,192 +0,0 @@ -//! This module contains data types that can be used in the model when special input/output -//! (ser/de) behavior is desired. For example, the ValidBase64 type can be used for a model field -//! when we don't even want to accept an API call with invalid base64 data. - -// The pattern in this module is to make a struct and implement TryFrom<&str> with code that does -// necessary checks and returns the struct. Other traits that treat the struct like a string can -// be implemented for you with the string_impls_for macro. - -pub mod error { - use regex::Regex; - use scalar::ValidationError; - use snafu::Snafu; - - // x509_parser::pem::Pem::parse_x509 returns an Err, which is a bit - // verbose. Declaring a type to simplify it. - type PEMToX509ParseError = x509_parser::nom::Err; - - #[derive(Debug, Snafu)] - #[snafu(visibility(pub(super)))] - pub enum Error { - #[snafu(display("Can't create SingleLineString containing line terminator"))] - StringContainsLineTerminator, - - #[snafu(display("Invalid base64 input: {}", source))] - InvalidBase64 { source: base64::DecodeError }, - - #[snafu(display( - "Identifiers may only contain ASCII alphanumerics plus hyphens, received '{}'", - input - ))] - InvalidIdentifier { input: String }, - - #[snafu(display( - "Kernel boot config keywords may only contain ASCII alphanumerics plus hyphens and underscores, received '{}'", - input - ))] - InvalidBootconfigKey { input: String }, - - #[snafu(display( - "Kernel boot config values may only contain ASCII printable characters, received '{}'", - input - ))] - InvalidBootconfigValue { input: String }, - - #[snafu(display( - "Kernel module keys may only contain ASCII alphanumerics plus hyphens and underscores, received '{}'", - input - ))] - InvalidKmodKey { input: String }, - - #[snafu(display("Given invalid URL '{}'", input))] - InvalidUrl { input: String }, - - #[snafu(display("Invalid version string '{}'", input))] - InvalidVersion { input: String }, - - #[snafu(display("{} must match '{}', given: {}", thing, pattern, input))] - Pattern { - thing: String, - pattern: Regex, - input: String, - }, - - // Some regexes are too big to usefully display in an error. - #[snafu(display("{} given invalid input: {}", thing, input))] - BigPattern { thing: String, input: String }, - - #[snafu(display("Invalid Kubernetes cloud provider '{}'", input))] - InvalidCloudProvider { input: String }, - - #[snafu(display("Invalid Kubernetes authentication mode '{}'", input))] - InvalidAuthenticationMode { input: String }, - - #[snafu(display("Invalid bootstrap container mode '{}'", input))] - InvalidBootstrapContainerMode { input: String }, - - #[snafu(display("Given invalid cluster name '{}': {}", name, msg))] - InvalidClusterName { name: String, msg: String }, - - #[snafu(display("Invalid domain name '{}': {}", input, msg))] - InvalidDomainName { input: String, msg: String }, - - #[snafu(display("Invalid hostname '{}': {}", input, msg))] - InvalidLinuxHostname { input: String, msg: String }, - - #[snafu(display("Invalid Linux lockdown mode '{}'", input))] - InvalidLockdown { input: String }, - - #[snafu(display("Invalid sysctl key '{}': {}", input, msg))] - InvalidSysctlKey { input: String, msg: String }, - - #[snafu(display("Invalid input for field {}: {}", field, source))] - InvalidPlainValue { - field: String, - source: serde_plain::Error, - }, - - #[snafu(display("Invalid Kubernetes threshold percentage value '{}'", input))] - InvalidThresholdPercentage { input: String }, - - #[snafu(display("Invalid percentage value '{}'", input))] - InvalidPercentage { - input: String, - source: std::num::ParseFloatError, - }, - - #[snafu(display("Invalid Cpu Manager policy '{}'", input))] - InvalidCpuManagerPolicy { - input: String, - source: serde_plain::Error, - }, - - #[snafu(display("Invalid Kubernetes duration value '{}'", input))] - InvalidKubernetesDurationValue { input: String }, - - #[snafu(display("Invalid x509 certificate: {}", source))] - InvalidX509Certificate { source: PEMToX509ParseError }, - - #[snafu(display("Invalid PEM object: {}", source))] - InvalidPEM { - source: x509_parser::error::PEMError, - }, - - #[snafu(display("No valid certificate found in bundle"))] - NoCertificatesFound {}, - - #[snafu(display("Invalid topology manager scope '{}'", input))] - InvalidTopologyManagerScope { - input: String, - source: serde_plain::Error, - }, - - #[snafu(display("Invalid topology manager policy '{}'", input))] - InvalidTopologyManagerPolicy { - input: String, - source: serde_plain::Error, - }, - - #[snafu(display("Invalid imageGCHighThresholdPercent '{}': {}", input, msg))] - InvalidImageGCHighThresholdPercent { input: String, msg: String }, - - #[snafu(display("Invalid imageGCLowThresholdPercent '{}': {}", input, msg))] - InvalidImageGCLowThresholdPercent { input: String, msg: String }, - - #[snafu(display("Invalid ECS duration value '{}'", input))] - InvalidECSDurationValue { input: String }, - - #[snafu(display("Could not parse '{}' as an integer", input))] - ParseInt { - input: String, - source: std::num::ParseIntError, - }, - - #[snafu(display("Invalid Kernel CpuSet value '{}'", input))] - InvalidKernelCpuSetValue { input: String }, - } - - /// Creates a `ValidationError` with a consistent message for strings with regex validations - /// where the regex is too big to display to the user. - pub(crate) fn big_pattern_error(thing: S1, input: S2) -> ValidationError - where - S1: AsRef, - S2: AsRef, - { - ValidationError::new(format!( - "{} given invalid input: {}", - thing.as_ref(), - input.as_ref() - )) - } -} - -/// This is similar to the `Snafu` `ensure` macro that we are familiar with, but it works with our -/// own `ValidationError` instead of a `Snafu` error enum. -macro_rules! require { - ($condition:expr, $err:expr) => { - if !($condition) { - return Err($err); - } - }; -} - -// Must be after macro definition -mod ecs; -mod kubernetes; -mod oci_defaults; -mod shared; - -pub use ecs::*; -pub use kubernetes::*; -pub use oci_defaults::*; -pub use shared::*; diff --git a/sources/models/modeled-types/src/oci_defaults.rs b/sources/models/modeled-types/src/oci_defaults.rs deleted file mode 100644 index b32702b7fcc..00000000000 --- a/sources/models/modeled-types/src/oci_defaults.rs +++ /dev/null @@ -1,188 +0,0 @@ -use scalar_derive::Scalar; -use serde::{Deserialize, Serialize}; - -/// OciDefaultsCapability specifies which process capabilities are -/// allowed to be set in the default OCI spec. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Scalar, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum OciDefaultsCapability { - AuditControl, - AuditRead, - AuditWrite, - BlockSuspend, - Bpf, - CheckpointRestore, - Chown, - DacOverride, - DacReadSearch, - Fowner, - Fsetid, - IpcLock, - IpcOwner, - Kill, - Lease, - LinuxImmutable, - MacAdmin, - MacOverride, - Mknod, - NetAdmin, - NetBindService, - NetBroadcast, - NetRaw, - Perfmon, - Setgid, - Setfcap, - Setpcap, - Setuid, - SysAdmin, - SysBoot, - SysChroot, - SysModule, - SysNice, - SysPacct, - SysPtrace, - SysRawio, - SysResource, - SysTime, - SysTtyConfig, - Syslog, - WakeAlarm, -} - -impl OciDefaultsCapability { - /// Converts from Bottlerocket's kabob-case name into the Linux capability name, e.g. turns - /// `wake-alarm` into `CAP_WAKE_ALARM`. - pub fn to_linux_string(&self) -> String { - format!("CAP_{}", self.to_string().to_uppercase().replace('-', "_")) - } -} - -#[cfg(test)] -mod oci_defaults_capabilities { - use super::*; - - fn check_capability_strings(cap: OciDefaultsCapability, bottlerocket: &str, linux: &str) { - let actual_bottlerocket = cap.to_string(); - let actual_linux = cap.to_linux_string(); - assert_eq!(bottlerocket, actual_bottlerocket); - assert_eq!(linux, actual_linux); - } - - #[test] - fn linux_capability_strings() { - check_capability_strings( - OciDefaultsCapability::AuditControl, - "audit-control", - "CAP_AUDIT_CONTROL", - ); - - check_capability_strings( - OciDefaultsCapability::SysPacct, - "sys-pacct", - "CAP_SYS_PACCT", - ); - - check_capability_strings(OciDefaultsCapability::Mknod, "mknod", "CAP_MKNOD"); - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// OciDefaultsResourceLimitType specifies which resource limits are -/// allowed to be set in the default OCI spec. - -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Scalar, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum OciDefaultsResourceLimitType { - MaxAddressSpace, - MaxCoreFileSize, - MaxCpuTime, - MaxDataSize, - MaxFileLocks, - MaxFileSize, - MaxLockedMemory, - MaxMsgqueueSize, - MaxNicePriority, - MaxOpenFiles, - MaxPendingSignals, - MaxProcesses, - MaxRealtimePriority, - MaxRealtimeTimeout, - MaxResidentSet, - MaxStackSize, -} - -// We are leaving this implementation open for the easy addition of -// future resource limits. -impl OciDefaultsResourceLimitType { - pub fn to_linux_string(&self) -> &'static str { - use OciDefaultsResourceLimitType::*; - match self { - MaxAddressSpace => "RLIMIT_AS", - MaxCoreFileSize => "RLIMIT_CORE", - MaxCpuTime => "RLIMIT_CPU", - MaxDataSize => "RLIMIT_DATA", - MaxFileLocks => "RLIMIT_LOCKS", - MaxFileSize => "RLIMIT_FSIZE", - MaxLockedMemory => "RLIMIT_MEMLOCK", - MaxMsgqueueSize => "RLIMIT_MSGQUEUE", - MaxNicePriority => "RLIMIT_NICE", - MaxOpenFiles => "RLIMIT_NOFILE", - MaxPendingSignals => "RLIMIT_SIGPENDING", - MaxProcesses => "RLIMIT_NPROC", - MaxRealtimePriority => "RLIMIT_RTPRIO", - MaxRealtimeTimeout => "RLIMIT_RTTIME", - MaxResidentSet => "RLIMIT_RSS", - MaxStackSize => "RLIMIT_STACK", - } - } -} - -#[cfg(test)] -mod oci_defaults_rlimits { - use super::*; - use OciDefaultsResourceLimitType::*; - - fn check_rlimit_strings( - (cap, bottlerocket, linux): (OciDefaultsResourceLimitType, &str, &str), - ) { - let actual_bottlerocket = cap.to_string(); - let actual_linux = cap.to_linux_string(); - assert_eq!(bottlerocket, actual_bottlerocket); - assert_eq!(linux, actual_linux); - } - - #[test] - fn linux_rlimit_strings() { - let rlimits = [ - (MaxAddressSpace, "max-address-space", "RLIMIT_AS"), - (MaxCoreFileSize, "max-core-file-size", "RLIMIT_CORE"), - (MaxCpuTime, "max-cpu-time", "RLIMIT_CPU"), - (MaxDataSize, "max-data-size", "RLIMIT_DATA"), - (MaxFileLocks, "max-file-locks", "RLIMIT_LOCKS"), - (MaxFileSize, "max-file-size", "RLIMIT_FSIZE"), - (MaxLockedMemory, "max-locked-memory", "RLIMIT_MEMLOCK"), - (MaxMsgqueueSize, "max-msgqueue-size", "RLIMIT_MSGQUEUE"), - (MaxNicePriority, "max-nice-priority", "RLIMIT_NICE"), - (MaxOpenFiles, "max-open-files", "RLIMIT_NOFILE"), - ( - MaxPendingSignals, - "max-pending-signals", - "RLIMIT_SIGPENDING", - ), - (MaxProcesses, "max-processes", "RLIMIT_NPROC"), - ( - MaxRealtimePriority, - "max-realtime-priority", - "RLIMIT_RTPRIO", - ), - (MaxRealtimeTimeout, "max-realtime-timeout", "RLIMIT_RTTIME"), - (MaxResidentSet, "max-resident-set", "RLIMIT_RSS"), - (MaxStackSize, "max-stack-size", "RLIMIT_STACK"), - ]; - - for rlimit in rlimits { - check_rlimit_strings(rlimit); - } - } -} diff --git a/sources/models/modeled-types/src/shared.rs b/sources/models/modeled-types/src/shared.rs deleted file mode 100644 index 829c382c22f..00000000000 --- a/sources/models/modeled-types/src/shared.rs +++ /dev/null @@ -1,1255 +0,0 @@ -use super::error; -use base64::Engine; -use lazy_static::lazy_static; -use regex::Regex; -use scalar::traits::{Scalar, Validate}; -use scalar::ValidationError; -use scalar_derive::Scalar; -use semver::Version; -use serde::{Deserialize, Serialize}; -use snafu::{ensure, ResultExt}; -use std::convert::TryFrom; -use std::net::IpAddr; -use std::str::FromStr; -use string_impls_for::string_impls_for; -use url::Host; - -/// ValidBase64 can only be created by deserializing from valid base64 text. It stores the -/// original text, not the decoded form. Its purpose is input validation, namely being used as a -/// field in a model structure so that you don't even accept a request with a field that has -/// invalid base64. -// Note: we use the default base64::STANDARD config which uses/allows "=" padding. -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct ValidBase64 { - inner: String, -} - -/// Validate base64 format before we accept the input. -impl TryFrom<&str> for ValidBase64 { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - base64::engine::general_purpose::STANDARD - .decode(input) - .context(error::InvalidBase64Snafu)?; - Ok(ValidBase64 { - inner: input.to_string(), - }) - } -} - -string_impls_for!(ValidBase64, "ValidBase64"); - -#[cfg(test)] -mod test_valid_base64 { - use super::ValidBase64; - use base64::Engine; - use std::convert::TryFrom; - - #[test] - fn valid_base64() { - let v = ValidBase64::try_from("aGk=").unwrap(); - let decoded_bytes = base64::engine::general_purpose::STANDARD - .decode(v.as_ref()) - .unwrap(); - let decoded = std::str::from_utf8(&decoded_bytes).unwrap(); - assert_eq!(decoded, "hi"); - } - - #[test] - fn invalid_base64() { - assert!(ValidBase64::try_from("invalid base64").is_err()); - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// SingleLineString can only be created by deserializing from a string that contains at most one -/// line. It stores the original form and makes it accessible through standard traits. Its -/// purpose is input validation, for example in cases where you want to accept input for a -/// configuration file and want to ensure a user can't create a new line with extra configuration. -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct SingleLineString { - inner: String, -} - -impl TryFrom<&str> for SingleLineString { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - // Rust does not treat all Unicode line terminators as starting a new line, so we check for - // specific characters here, rather than just counting from lines(). - // https://en.wikipedia.org/wiki/Newline#Unicode - let line_terminators = [ - '\n', // newline (0A) - '\r', // carriage return (0D) - '\u{000B}', // vertical tab - '\u{000C}', // form feed - '\u{0085}', // next line - '\u{2028}', // line separator - '\u{2029}', // paragraph separator - ]; - - ensure!( - !input.contains(&line_terminators[..]), - error::StringContainsLineTerminatorSnafu - ); - - Ok(Self { - inner: input.to_string(), - }) - } -} - -string_impls_for!(SingleLineString, "SingleLineString"); - -#[cfg(test)] -mod test_single_line_string { - use super::SingleLineString; - use std::convert::TryFrom; - - #[test] - fn valid_single_line_string() { - assert!(SingleLineString::try_from("").is_ok()); - assert!(SingleLineString::try_from("hi").is_ok()); - let long_string = " ".repeat(9999); - assert!(SingleLineString::try_from(long_string).is_ok()); - } - - #[test] - fn invalid_single_line_string() { - assert!(SingleLineString::try_from("Hello\nWorld").is_err()); - - assert!(SingleLineString::try_from("\n").is_err()); - assert!(SingleLineString::try_from("\r").is_err()); - assert!(SingleLineString::try_from("\r\n").is_err()); - - assert!(SingleLineString::try_from("\u{000B}").is_err()); // vertical tab - assert!(SingleLineString::try_from("\u{000C}").is_err()); // form feed - assert!(SingleLineString::try_from("\u{0085}").is_err()); // next line - assert!(SingleLineString::try_from("\u{2028}").is_err()); // line separator - assert!(SingleLineString::try_from("\u{2029}").is_err()); - // paragraph separator - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// ValidLinuxHostname represents a string that contains a valid Linux hostname as defined by -/// https://man7.org/linux/man-pages/man7/hostname.7.html. It stores the original form and makes -/// it accessible through standard traits. -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct ValidLinuxHostname { - inner: String, -} - -lazy_static! { - // According to the man page above, hostnames must be between 1-253 characters long consisting - // of characters [0-9a-z.-]. - pub(crate) static ref VALID_LINUX_HOSTNAME: Regex = Regex::new(r"^[0-9a-z.-]{1,253}$").unwrap(); -} - -impl TryFrom<&str> for ValidLinuxHostname { - type Error = error::Error; - - #[allow(clippy::len_zero)] - fn try_from(input: &str) -> Result { - ensure!( - VALID_LINUX_HOSTNAME.is_match(input), - error::InvalidLinuxHostnameSnafu { - input, - msg: "must only be [0-9a-z.-], and 1-253 chars long" - } - ); - - // Though the man page doesn't explicitly disallow hostnames that start with dots, dots are - // used as separators so starting with a separator would imply an empty domain, which isn't - // allowed (must be at least one character). - ensure!( - !input.starts_with('-') && !input.starts_with('.'), - error::InvalidLinuxHostnameSnafu { - input, - msg: "must not start with '-' or '.'" - } - ); - - // Each segment must be from 1-63 chars long and shouldn't start with "-" - - ensure!( - input - .split('.') - .all(|x| x.len() >= 1 && x.len() <= 63 && !x.starts_with('-')), - error::InvalidLinuxHostnameSnafu { - input, - msg: "segment is less than 1 or greater than 63 chars" - } - ); - - Ok(Self { - inner: input.to_string(), - }) - } -} - -string_impls_for!(ValidLinuxHostname, "ValidLinuxHostname"); - -#[cfg(test)] -mod test_valid_linux_hostname { - use super::ValidLinuxHostname; - use std::convert::TryFrom; - - #[test] - fn valid_linux_hostname() { - assert!(ValidLinuxHostname::try_from("hello").is_ok()); - assert!(ValidLinuxHostname::try_from("hello1234567890").is_ok()); - - let segment_limit = "a".repeat(63); - assert!(ValidLinuxHostname::try_from(segment_limit.clone()).is_ok()); - - let segment = "a".repeat(61); - let long_name = format!( - "{}.{}.{}.{}", - &segment_limit, &segment_limit, &segment_limit, &segment - ); - assert!(ValidLinuxHostname::try_from(long_name).is_ok()); - } - - #[test] - fn invalid_linux_hostname() { - assert!(ValidLinuxHostname::try_from(" ").is_err()); - assert!(ValidLinuxHostname::try_from("-a").is_err()); - assert!(ValidLinuxHostname::try_from(".a").is_err()); - assert!(ValidLinuxHostname::try_from("@a").is_err()); - assert!(ValidLinuxHostname::try_from("a..a").is_err()); - assert!(ValidLinuxHostname::try_from("a.a.-a.a1234").is_err()); - - let long_segment = "a".repeat(64); - assert!(ValidLinuxHostname::try_from(long_segment.clone()).is_err()); - - let long_name = format!( - "{}.{}.{}.{}", - &long_segment, &long_segment, &long_segment, &long_segment - ); - assert!(ValidLinuxHostname::try_from(long_name).is_err()); - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// EtcHostsEntries represents a mapping of IP Address to hostname aliases that can apply to those -/// addresses. -#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] -#[serde(transparent)] -pub struct EtcHostsEntries( - // Ordering matters in /etc/hosts, and this setting directly maps to that file and its behavior in glibc. - // Repeated IP Addresses have their host aliases merged to a single line, respecting the order as they appear in this list. - Vec<(IpAddr, Vec)>, -); - -impl EtcHostsEntries { - pub fn iter_merged(&self) -> impl Iterator)> { - let mut merged: indexmap::IndexMap> = - indexmap::IndexMap::with_capacity(self.0.len()); - - for (ip_address, aliases) in &self.0 { - merged - .entry(*ip_address) - .or_default() - .append(&mut (aliases.clone())); - } - - merged.into_iter() - } -} - -#[cfg(test)] -mod test_etc_hosts_entries { - use super::{EtcHostsEntries, ValidLinuxHostname}; - use std::net::IpAddr; - - #[test] - fn test_valid_etc_hosts_entries() { - assert!(serde_json::from_str::( - r#"[ - ["127.0.0.1", ["localhost", "localhost4"]], - ["::1", ["localhost", "localhost6"]] - ]"# - ) - .is_ok()); - assert!(serde_json::from_str::( - r#"[ - ["127.0.0.1", ["localhost", "localhost4"]], - ["::1", ["localhost", "localhost6"]], - ["127.0.0.1", ["test.example.com"]] - ]"# - ) - .is_ok()); - assert!(serde_json::from_str::( - r#"[ - ["::1", ["localhost", "localhost6"]], - ["0000:0000:0000:0000:0000:0000:0000:0001", ["test6.example.com"]] - ]"# - ) - .is_ok()); - assert!(serde_json::from_str::(r#"[]"#).is_ok()); - } - - #[test] - fn test_invalid_etc_hosts_entries() { - assert!( - serde_json::from_str::(r#"[["127.0.0.0/24", ["localhost"]]"#).is_err() - ); - assert!( - serde_json::from_str::(r#"[["not_an_ip", ["localhost"]]"#).is_err() - ); - assert!(serde_json::from_str::( - r#"[["127.0.0.1", ["not_a_valid_hostname!"]]"# - ) - .is_err()); - } - - #[test] - fn test_iter_merged() { - assert_eq!( - serde_json::from_str::( - r#"[ - ["127.0.0.1", ["localhost", "localhost4"]], - ["127.0.0.1", ["test.example.com"]] - ]"#, - ) - .unwrap() - .iter_merged() - .collect::)>>(), - serde_json::from_str::( - r#"[ - ["127.0.0.1", ["localhost", "localhost4", "test.example.com"]] - ]"#, - ) - .unwrap() - .0 - ); - - assert_eq!( - serde_json::from_str::( - r#"[ - ["127.0.0.1", ["localhost", "localhost4"]], - ["127.0.0.3", ["test.example.com"]], - ["127.0.0.2", ["test.example.com"]], - ["127.0.0.1", ["test.example.com"]] - ]"#, - ) - .unwrap() - .iter_merged() - .collect::)>>(), - serde_json::from_str::( - r#"[ - ["127.0.0.1", ["localhost", "localhost4", "test.example.com"]], - ["127.0.0.3", ["test.example.com"]], - ["127.0.0.2", ["test.example.com"]] - ]"#, - ) - .unwrap() - .0 - ); - - assert_eq!( - serde_json::from_str::( - r#"[ - ["127.0.0.1", ["localhost", "localhost4"]], - ["::1", ["localhost", "localhost6"]], - ["127.0.0.1", ["test.example.com"]], - ["0000:0000:0000:0000:0000:0000:0000:0001", ["test6.example.com"]], - ["10.0.0.1", ["example.bottlerocket.aws"]] - ]"#, - ) - .unwrap() - .iter_merged() - .collect::)>>(), - serde_json::from_str::( - r#"[ - ["127.0.0.1", ["localhost", "localhost4", "test.example.com"]], - ["::1", ["localhost", "localhost6", "test6.example.com"]], - ["10.0.0.1", ["example.bottlerocket.aws"]] - ]"#, - ) - .unwrap() - .0 - ); - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// Identifier can only be created by deserializing from a string that contains -/// ASCII alphanumeric characters, plus hyphens, which we use as our standard word separator -/// character in user-facing identifiers. It stores the original form and makes it accessible -/// through standard traits. Its purpose is to validate input for identifiers like container names -/// that might be used to create files/directories. -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct Identifier { - inner: String, -} - -const CONTAINERD_ID_LENGTH: usize = 76; - -impl TryFrom<&str> for Identifier { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - let valid_identifier = input - .chars() - .all(|c| (c.is_ascii() && c.is_alphanumeric()) || c == '-') - && input.len() <= CONTAINERD_ID_LENGTH; - ensure!(valid_identifier, error::InvalidIdentifierSnafu { input }); - Ok(Identifier { - inner: input.to_string(), - }) - } -} - -string_impls_for!(Identifier, "Identifier"); - -#[cfg(test)] -mod test_valid_identifier { - use super::{Identifier, CONTAINERD_ID_LENGTH}; - use std::convert::TryFrom; - - #[test] - fn valid_identifier() { - assert!(Identifier::try_from("hello-world").is_ok()); - assert!(Identifier::try_from("helloworld").is_ok()); - assert!(Identifier::try_from("123321hello").is_ok()); - assert!(Identifier::try_from("hello-1234").is_ok()); - assert!(Identifier::try_from("--------").is_ok()); - assert!(Identifier::try_from("11111111").is_ok()); - assert!(Identifier::try_from(vec!["X"; CONTAINERD_ID_LENGTH].join("")).is_ok()); - } - - #[test] - fn invalid_identifier() { - assert!(Identifier::try_from("../").is_err()); - assert!(Identifier::try_from("{}").is_err()); - assert!(Identifier::try_from("hello|World").is_err()); - assert!(Identifier::try_from("hello\nWorld").is_err()); - assert!(Identifier::try_from("hello_world").is_err()); - assert!(Identifier::try_from("タール").is_err()); - assert!(Identifier::try_from("💝").is_err()); - assert!(Identifier::try_from(vec!["X"; CONTAINERD_ID_LENGTH + 1].join("")).is_err()); - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// Url represents a string that contains a valid URL, according to url::Url, though it also -/// allows URLs without a scheme (e.g. without "http://") because it's common. It stores the -/// original string and makes it accessible through standard traits. Its purpose is to validate -/// input for any field containing a network address. -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct Url { - inner: String, -} - -impl TryFrom<&str> for Url { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - if input.parse::().is_ok() { - return Ok(Url { - inner: input.to_string(), - }); - } else { - // It's very common to specify URLs without a scheme, so we add one and see if that - // fixes parsing. - let prefixed = format!("http://{}", input); - if prefixed.parse::().is_ok() { - return Ok(Url { - inner: input.to_string(), - }); - } - } - error::InvalidUrlSnafu { input }.fail() - } -} - -string_impls_for!(Url, "Url"); - -#[cfg(test)] -mod test_url { - use super::Url; - use std::convert::TryFrom; - - #[test] - fn good_urls() { - for ok in &[ - "https://example.com/path", - "https://example.com", - "example.com/path", - "example.com", - "ntp://127.0.0.1/path", - "ntp://127.0.0.1", - "127.0.0.1/path", - "127.0.0.1", - "http://localhost/path", - "http://localhost", - "localhost/path", - "localhost", - "localhost:8080", - ".internal", - ".cluster.local", - ] { - Url::try_from(*ok).unwrap(); - } - } - - #[test] - fn bad_urls() { - for err in &["how are you", "weird@"] { - Url::try_from(*err).unwrap_err(); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// FriendlyVersion represents a version string that can optionally be prefixed with 'v'. -/// It can also be set to 'latest' to represent the latest version. It stores the original string -/// and makes it accessible through standard traits. -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct FriendlyVersion { - inner: String, -} - -impl TryFrom<&str> for FriendlyVersion { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - if input == "latest" { - return Ok(FriendlyVersion { - inner: input.to_string(), - }); - } - // If the string begins with a 'v', skip it before checking if it is valid semver. - let version = if let Some(stripped) = input.strip_prefix('v') { - stripped - } else { - input - }; - - if version.parse::().is_ok() { - return Ok(FriendlyVersion { - inner: input.to_string(), - }); - } - error::InvalidVersionSnafu { input }.fail() - } -} - -impl TryFrom for semver::Version { - type Error = semver::Error; - - fn try_from(input: FriendlyVersion) -> Result { - // If the string begins with a 'v', skip it before conversion - let version = if input.inner.starts_with('v') { - &input.inner[1..] - } else { - &input.inner - }; - Version::from_str(version) - } -} - -string_impls_for!(FriendlyVersion, "FriendlyVersion"); - -#[cfg(test)] -mod test_version { - use super::FriendlyVersion; - use semver::Version; - use std::convert::TryFrom; - use std::convert::TryInto; - - #[test] - fn good_version_strings() { - for ok in &[ - "1.0.0", - "v1.0.0", - "1.0.1-alpha", - "v1.0.1-alpha", - "1.0.2-alpha+1.0", - "v1.0.2-alpha+1.0", - "1.1.0-rc.1.1", - "v1.1.0-rc.1.1", - "latest", - ] { - FriendlyVersion::try_from(*ok).unwrap(); - // Test conversion to semver::Version - if *ok != "latest" { - let _: Version = FriendlyVersion { - inner: ok.to_string(), - } - .try_into() - .unwrap(); - } - } - } - - #[test] - fn bad_version_string() { - for err in &[ - "hi", - "1.0", - "1", - "v", - "v1", - "v1.0", - "vv1.1.0", - "1.0.3-beta.1.01", - "v1.0.3-beta.1.01", - ] { - FriendlyVersion::try_from(*err).unwrap_err(); - let res: Result = Version::try_from(FriendlyVersion { - inner: err.to_string(), - }); - res.unwrap_err(); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// DNSDomain represents a string that is a valid DNS domain. It stores the -/// original string and makes it accessible through standard traits. Its purpose -/// is input validation, for example validating the kubelet's "clusterDomain" -/// config value. -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct DNSDomain { - inner: String, -} - -impl TryFrom<&str> for DNSDomain { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - ensure!( - !input.starts_with('.'), - error::InvalidDomainNameSnafu { - input, - msg: "must not start with '.'", - } - ); - - let host = Host::parse(input).or_else(|e| { - error::InvalidDomainNameSnafu { - input, - msg: e.to_string(), - } - .fail() - })?; - match host { - Host::Ipv4(_) | Host::Ipv6(_) => error::InvalidDomainNameSnafu { - input, - msg: "IP address is not a valid domain name", - } - .fail(), - Host::Domain(_) => Ok(Self { - inner: input.to_string(), - }), - } - } -} - -string_impls_for!(DNSDomain, "DNSDomain"); - -#[cfg(test)] -mod test_dns_domain { - use super::DNSDomain; - use std::convert::TryFrom; - - #[test] - fn valid_dns_domain() { - for ok in &["cluster.local", "dev.eks", "stage.eks", "prod.eks"] { - assert!(DNSDomain::try_from(*ok).is_ok()); - } - } - - #[test] - fn invalid_dns_domain() { - for err in &[ - "foo/com", - ".a", - "123.123.123.123", - "[2001:db8::ff00:42:8329]", - ] { - assert!(DNSDomain::try_from(*err).is_err()); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// SysctlKey represents a string that is a valid Linux sysctl key; keys must be representable as -/// filesystem paths, and are generally kept to lowercase_underscored_names separated with '.' or -/// '/'. SysctlKey stores the original string and makes it accessible through standard traits. -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct SysctlKey { - inner: String, -} - -lazy_static! { - /// Pattern matching the name of a sysctl key. Must be representable as a path; we'll go a bit - /// further and enforce a basic pattern that would match all known keys, plus some leeway. - pub(crate) static ref SYSCTL_KEY: Regex = Regex::new(r"^[a-zA-Z0-9./_-]{1,128}$").unwrap(); -} - -impl TryFrom<&str> for SysctlKey { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - // Basic directory traversal checks; corndog also checks - ensure!( - !input.contains(".."), - error::InvalidSysctlKeySnafu { - input, - msg: "must not contain '..'".to_string(), - } - ); - ensure!( - !input.starts_with('.') && !input.starts_with('/'), - error::InvalidSysctlKeySnafu { - input, - msg: "must not start with '.' or '/'".to_string(), - } - ); - ensure!( - SYSCTL_KEY.is_match(input), - error::InvalidSysctlKeySnafu { - input, - msg: format!("must match pattern {}", *SYSCTL_KEY), - } - ); - Ok(SysctlKey { - inner: input.to_string(), - }) - } -} - -string_impls_for!(SysctlKey, "SysctlKey"); - -#[cfg(test)] -mod test_sysctl_key { - use super::SysctlKey; - use std::convert::TryFrom; - - #[test] - fn valid_sysctl_key() { - for ok in &[ - // Longest real one - "net/ipv4/conf/enp0s42f3/igmpv3_unsolicited_report_interval", - // Dots or slashes OK - "net.ipv4.conf.enp0s42f3.igmpv3_unsolicited_report_interval", - // Mixed dots/slashes isn't supported by sysctl(8), but it's unambiguous - "net/ipv4.conf.enp0s42f3/igmpv3_unsolicited_report_interval", - // Shortest real one - "fs/aio-nr", - // Shortest allowed - "a", - // Longest allowed - &"a".repeat(128), - // All allowed characters - "-./0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", - ] { - SysctlKey::try_from(*ok).unwrap(); - } - } - - #[test] - fn invalid_sysctl_key() { - for err in &[ - // Too long - &"a".repeat(129), - // Too short, - "", - // Sneaky sneaky - "hi/../../there", - "../hi", - "/../hi", - // Invalid characters - "!", - "@", - "#", - "$", - "%", - "^", - "&", - "*", - "(", - ")", - "\"", - "'", - "\\", - "|", - "~", - "`", - ] { - SysctlKey::try_from(*err).unwrap_err(); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// BootConfigKey represents a string that is a valid Kernel boot config key; each key word must -/// contain only alphabets, numbers, dash (-) or underscore (_). -/// BootConfigKey stores the original string and makes it accessible through standard traits. -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct BootConfigKey { - inner: String, -} - -impl TryFrom<&str> for BootConfigKey { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - // Each individual keyword must be valid - let valid_key = input.split('.').all(|keyword| { - !keyword.is_empty() - && keyword - .chars() - .all(|c| (c.is_ascii() && c.is_alphanumeric()) || c == '-' || c == '_') - }); - ensure!(valid_key, error::InvalidBootconfigKeySnafu { input }); - Ok(BootConfigKey { - inner: input.to_string(), - }) - } -} - -string_impls_for!(BootConfigKey, "BootConfigKey"); - -#[cfg(test)] -mod test_bootconfig_key { - use super::BootConfigKey; - use std::convert::TryFrom; - - #[test] - fn valid_bootconfig_key() { - for ok in &[ - "keyword1.keyword2", - "-keyword1.keyword2", - "_keyword.1.2.3", - "key_word", - "key-word", - "keyword1", - "keyword1-", - "keyword2_", - ] { - BootConfigKey::try_from(*ok).unwrap(); - } - } - - #[test] - fn invalid_bootconfig_key() { - for err in &[ - "", "①", ".", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "\"", "'", "\\", "|", - "~", "`", - ] { - BootConfigKey::try_from(*err).unwrap_err(); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// BootConfigValue represents a string that is a valid Kernel boot config value; each value only -/// contains printable characters or spaces except for delimiters such as semicolon, newline, comma, -/// hash, and closing brace. These delimiters are only usable if the value itself is quoted with -/// single-quotes or double-quotes. Here we treat the value as if they're always quoted in the context -/// of Bottlerocket settings. This means the value just has to be printable ASCII. -/// BootConfigValue stores the original string and makes it accessible through standard traits. -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct BootConfigValue { - inner: String, -} - -impl TryFrom<&str> for BootConfigValue { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - ensure!( - input.chars().all(|c| c.is_ascii() && !c.is_ascii_control()) - // Values containing both single quotes and double quotes are inherently invalid since quotes - // cannot be escaped. - && !(input.contains('"') && input.contains('\'')), - error::InvalidBootconfigValueSnafu { input } - ); - Ok(BootConfigValue { - inner: input.to_string(), - }) - } -} - -string_impls_for!(BootConfigValue, "BootConfigValue"); - -#[cfg(test)] -mod test_bootconfig_value { - use super::BootConfigValue; - use std::convert::TryFrom; - - #[test] - fn valid_bootconfig_value() { - for ok in &[ - "plain", - "@yogurt@", - "\"abc", - " !#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}", - "1", - "value1", - "hello.goodbye", - "", - ] { - BootConfigValue::try_from(*ok).unwrap(); - } - } - - #[test] - fn invalid_bootconfig_value() { - for err in &["'\"", "bottlerocket①", "💝", "Ï", "—"] { - BootConfigValue::try_from(*err).unwrap_err(); - } - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// Lockdown represents a string that is a valid Linux kernel lockdown mode name. It stores the -/// original string and makes it accessible through standard traits. -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct Lockdown { - inner: String, -} - -impl TryFrom<&str> for Lockdown { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - ensure!( - matches!(input, "none" | "integrity" | "confidentiality"), - error::InvalidLockdownSnafu { input } - ); - Ok(Lockdown { - inner: input.to_string(), - }) - } -} - -string_impls_for!(Lockdown, "Lockdown"); - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct BootstrapContainerMode { - inner: String, -} - -impl TryFrom<&str> for BootstrapContainerMode { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - ensure!( - matches!(input, "off" | "once" | "always"), - error::InvalidBootstrapContainerModeSnafu { input } - ); - Ok(BootstrapContainerMode { - inner: input.to_string(), - }) - } -} - -impl Default for BootstrapContainerMode { - fn default() -> Self { - BootstrapContainerMode { - inner: "off".to_string(), - } - } -} - -string_impls_for!(BootstrapContainerMode, "BootstrapContainerMode"); - -#[cfg(test)] -mod test_valid_container_mode { - use super::BootstrapContainerMode; - use std::convert::TryFrom; - - #[test] - fn valid_container_mode() { - for ok in &["off", "once", "always"] { - assert!(BootstrapContainerMode::try_from(*ok).is_ok()); - } - } - - #[test] - fn invalid_container_mode() { - assert!(BootstrapContainerMode::try_from("invalid").is_err()); - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct PemCertificateString { - inner: String, -} - -impl TryFrom<&str> for PemCertificateString { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - // Empty strings are valid to allow deleting bundles - if input.trim().is_empty() { - return Ok(PemCertificateString { - inner: input.to_string(), - }); - } - let decoded_bytes = base64::engine::general_purpose::STANDARD - .decode(input) - .context(error::InvalidBase64Snafu)?; - // Flag to check if the bundle doesn't contain any valid certificate - let mut certs_found = false; - // Validate each certificate in the bundle - for pem in x509_parser::pem::Pem::iter_from_buffer(&decoded_bytes) { - // Parse buffer into a PEM object, then to a x509 certificate - let pem = pem.context(error::InvalidPEMSnafu)?; - pem.parse_x509() - .context(error::InvalidX509CertificateSnafu)?; - certs_found = true; - } - - // No valid certificate found - if !certs_found { - return error::NoCertificatesFoundSnafu {}.fail(); - } - - Ok(PemCertificateString { - inner: input.to_string(), - }) - } -} - -impl Default for PemCertificateString { - fn default() -> Self { - PemCertificateString { - inner: "".to_string(), - } - } -} - -string_impls_for!(PemCertificateString, "PemCertificateString"); - -#[cfg(test)] -mod test_valid_pem_certificate_string { - use super::PemCertificateString; - use std::convert::TryFrom; - - static TEST_PEM: &str = include_str!("../../tests/data/test-pem"); - static TEST_INCOMPLETE_PEM: &str = include_str!("../../tests/data/test-incomplete-pem"); - - #[test] - fn valid_pem_certificate() { - assert!(PemCertificateString::try_from(TEST_PEM).is_ok()); - assert!(PemCertificateString::try_from("").is_ok()); - } - - #[test] - fn invalid_pem_certificate() { - // PEM with valid markers but with invalid content - assert!(PemCertificateString::try_from( - "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tIGJhZCAtLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==" - ) - .is_err()); - // PEM with valid content but without footer marker - assert!(PemCertificateString::try_from(TEST_INCOMPLETE_PEM).is_err()); - - // PEM without any valid certificate - assert!(PemCertificateString::try_from( - "77yc44Kz77ya44OfIOOBj+OCszrlvaEg77yc44Kz77ya44OfIOOBj+OCszrlvaEg77yc44Kz77ya44OfCg==" - ) - .is_err()) - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// KmodKey can only be created by deserializing from a string that contains ASCII -/// alphanumeric characters, plus hyphens, plus underscores. It stores the original -/// form and makes it accessible through standard traits. Its purpose is to validate -/// input that will be treated as a potential kernel module name. -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct KmodKey { - inner: String, -} - -// This limit is based on the kernel definition, and assumes a 64-bit host. -// include/linux/module.h -// #define MODULE_NAME_LEN MAX_PARAM_PREFIX_LEN -// include/linux/moduleparam.h -// #define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long)) -const KMOD_KEY_LENGTH: usize = 56; - -impl TryFrom<&str> for KmodKey { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - // The kernel allows modules to have any name that's a valid filename, - // but real module names seem to be limited to this character set. - let valid_key = input - .chars() - .all(|c| (c.is_ascii() && c.is_alphanumeric()) || c == '-' || c == '_') - && input.len() <= KMOD_KEY_LENGTH; - ensure!(valid_key, error::InvalidKmodKeySnafu { input }); - Ok(KmodKey { - inner: input.to_string(), - }) - } -} - -string_impls_for!(KmodKey, "KmodKey"); - -#[cfg(test)] -mod test_valid_kmod_key { - use super::{KmodKey, KMOD_KEY_LENGTH}; - use std::convert::TryFrom; - - #[test] - fn valid_kmod_key() { - assert!(KmodKey::try_from("kmod").is_ok()); - assert!(KmodKey::try_from("i8042").is_ok()); - assert!(KmodKey::try_from("xt_XT").is_ok()); - assert!(KmodKey::try_from("dm-block").is_ok()); - assert!(KmodKey::try_from("blowfish-x86_64").is_ok()); - assert!(KmodKey::try_from(vec!["a"; KMOD_KEY_LENGTH].join("")).is_ok()); - } - - #[test] - fn invalid_kmod_key() { - assert!(KmodKey::try_from("../").is_err()); - assert!(KmodKey::try_from("{}").is_err()); - assert!(KmodKey::try_from("kernel|Module").is_err()); - assert!(KmodKey::try_from("kernel\nModule").is_err()); - assert!(KmodKey::try_from("🐡").is_err()); - assert!(KmodKey::try_from(vec!["z"; KMOD_KEY_LENGTH + 1].join("")).is_err()); - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// Input value that needs to be a positive value, but should not be greater -/// than an i32::MAX. -#[derive(Clone, Debug, PartialEq, Scalar)] -pub struct NonNegativeInteger { - inner: i32, -} - -impl Validate for NonNegativeInteger { - fn validate>(input: I) -> Result { - let inner: i32 = input.into(); - if inner < 0 { - Err(ValidationError::new( - "number must be great than or equal to 0", - )) - } else { - Ok(Self { inner }) - } - } -} - -#[cfg(test)] -mod test_positive_integer { - use super::NonNegativeInteger; - use std::convert::TryFrom; - - #[test] - fn valid_positive_integer() { - assert!(NonNegativeInteger::try_from(0).is_ok()); - assert!(NonNegativeInteger::try_from(i32::MAX).is_ok()); - assert!(NonNegativeInteger::try_from(42).is_ok()); - } - - #[test] - fn invalid_positive_integer() { - assert!(NonNegativeInteger::try_from(i32::MIN).is_err()); - assert!(NonNegativeInteger::try_from(-1).is_err()); - } -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -/// KernelCpuSetValue represents a string that contains a valid Kernel CpuSet Value from -/// here: https://man7.org/linux/man-pages/man7/cpuset.7.html#FORMATS. This matches the -/// logic from https://github.com/kubernetes/utils/blob/d93618cff8a22d3aea7bf78d9d528fd859720c2d/cpuset/cpuset.go#L203 -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct KernelCpuSetValue { - inner: String, -} - -lazy_static! { - pub(crate) static ref KERNAL_CPU_SET_VALUE: Regex = - Regex::new(r"^([0-9]+(-[0-9]+)?,?)*([0-9]+(-[0-9]+)?)+$").unwrap(); -} - -impl TryFrom<&str> for KernelCpuSetValue { - type Error = error::Error; - - fn try_from(input: &str) -> Result { - ensure!( - !input.is_empty(), - error::InvalidKernelCpuSetValueSnafu { input } - ); - ensure!( - KERNAL_CPU_SET_VALUE.is_match(input), - error::InvalidKernelCpuSetValueSnafu { input } - ); - Ok(KernelCpuSetValue { - inner: input.to_string(), - }) - } -} - -string_impls_for!(KernelCpuSetValue, "KernelCpuSetValue"); - -#[cfg(test)] -mod test_kernel_cpu_set_value { - use super::KernelCpuSetValue; - use std::convert::TryFrom; - - #[test] - fn good_tokens() { - for ok in &[ - "1", - "0,1,2,3", - "1-4", - "1,6-9", - "1-4,6", - "1-3,6-9,10-15", - "100,101", - "1,2,3,4,5,6,7,8,9,10", - ] { - KernelCpuSetValue::try_from(*ok).unwrap(); - } - } - - #[test] - fn bad_names() { - for err in &[ - "", - "100.0", - "0...4", - "1..5", - "ten", - "1-", - "-3", - "9,-10", - "1,2,3,4,5,6,7,8,9,10,", - &"a".repeat(23), - ] { - KernelCpuSetValue::try_from(*err).unwrap_err(); - } - } -} diff --git a/sources/models/scalar-derive/Cargo.toml b/sources/models/scalar-derive/Cargo.toml deleted file mode 100644 index 0008df5a772..00000000000 --- a/sources/models/scalar-derive/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "scalar-derive" -version = "0.1.0" -authors = ["Matt Briggs "] -license = "Apache-2.0 OR MIT" -edition = "2021" -publish = false -build = "build.rs" -# Don't rebuild crate just because of changes to README. -exclude = ["README.md"] - -[lib] -path = "src/lib.rs" -proc-macro = true - -[dependencies] -darling = "0.20" -proc-macro2 = "1" -quote = "1" -scalar = { path = "../scalar", version = "0.1" } -serde = { version = "1", features = ["derive"] } -serde_plain = "1" -syn = { version = "2", default-features = false, features = ["full", "parsing", "printing", "proc-macro", "visit-mut"] } - -[build-dependencies] -generate-readme = { path = "../../generate-readme", version = "0.1" } diff --git a/sources/models/scalar-derive/README.md b/sources/models/scalar-derive/README.md deleted file mode 100644 index 69ba54d3d9a..00000000000 --- a/sources/models/scalar-derive/README.md +++ /dev/null @@ -1,216 +0,0 @@ -# scalar-derive - -Current version: 0.1.0 - - -A convenience macro for Bottlerocket model types. - -### Description - -The `Scalar` macro can be used for strings or numbers that need to be validated in the Bottlerocket -model. It uses a trait, also named `Scalar`, to treat a `struct` as a thin wrapper around an -internal scalar type, or to treat an `enum` as "string-like". - -For structs, the macro expects your inner scalar type to implement `Display`, `PartialEq`, -`Serialize` and `Deserialize`. It then implements these traits on the wrapper type by passing them -through to the inner type. - -You are also expected to implement the `Validate` trait on your `Scalar` struct types (the wrapper, -not the inner type). This macro will call `::validate(some_value)` when -implementing `YourType::new`. - -Enums do not require a wrapping struct since it is assumed that the deserializtion of the enum -serves as validation. When using the `Scalar` macro on an enum it expects the enum to implement -`Serialize` and `Deserialize`. It also expects that your enum doesn't not contain any structures. -That is, your enum should be representable with a simple string and compatible with `serde_plain`. -The `Scalar` uses `serde_plain`, to implement `Display`, `FromStr` and `String` conversions for your -enum. - -### Parameters - -The macro can take the following input parameters when used with wrapper structs (in most cases you -will not need to use these; the defaults will "just work"): -- `as_ref_str: bool`: Set to `true` if need the macro to treat your inner type as a `String`. - This will happen automatically if your inner type is named `String`. -- `inner`: The name of the field that holds your `inner` type. Defaults to `inner`. - -## Examples - -### Simple Usage - -This is an example of a very common use-case in Bottlerocket. We have a string, but we want to -validate it. In this example we want to return an error if the string is "pineapple". - -```rust -use scalar::traits::{Scalar, Validate}; -use scalar::ValidationError; -use scalar_derive::Scalar; - -// We create a struct with an inner type in a field named `inner`. We derive `Scalar`. -#[derive(Debug, PartialEq, Scalar)] -struct Pizza { - inner: String -} - -// We must implement the `Validate` trait for our type. -impl Validate for Pizza { - fn validate>(input: S) -> Result { - let input: String = input.into(); - if input == "pineapple" { - Err(ValidationError::new("pineapple is gross on pizza")) - } else { - Ok(Self{ inner: input }) - } - } -} - -// The `Scalar` derive macro has made it so that we can use `Pizza` as if it were a `String`, -// but we know that the value has been validated. - -let pizza = Pizza::new("pepperoni").unwrap(); -// `pizza` behaves like a string! -assert!("pepperoni" == pizza); - -let err = Pizza::new("pineapple"); -// no that's gross! -assert!(err.is_err()); -``` - -### Validating a Number - -Here we use the Scalar macro with a numeric inner type. The inner value is constrained to be less -than 4. - -```rust -use scalar::traits::{Scalar, Validate}; -use scalar::ValidationError; -use scalar_derive::Scalar; - -#[derive(Debug, PartialEq, Scalar)] -struct CatQuantity { - inner: i32 -} - -impl Validate for CatQuantity { - fn validate>(input: I) -> Result { - let input: i32 = input.into(); - if input > 4 { - Err(ValidationError::new("that's too many cats")) - } else { - Ok(Self{ inner: input }) - } - } -} - -let cat_quantity = CatQuantity::new(2).unwrap(); -// `cat_quantity` can be compared to a i32 -assert!(2 == cat_quantity); - -let err = CatQuantity::new(23); -// no that's too many! -assert!(err.is_err()); -``` - -### Using Macro Parameters - -In this example we will show how to use the parameters `as_ref_str` and `inner`. This example is -contrived, but demonstrates how to pass parameters to the derive macro. - -```rust -use scalar::traits::{Scalar, Validate}; -use scalar::ValidationError; -use scalar_derive::Scalar; -use serde::{Serialize, Deserialize}; - -#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] -struct WeirdType; - -// We need `AsRef` to treat it like a string with `as_ref_str`. -impl AsRef for WeirdType { - fn as_ref(&self) -> &str { - "i'm a weird type" - } -} - -// We also need `From<&str>` to treat it like a string with `as_ref_str`. -impl From<&str> for WeirdType { - fn from(_: &str) -> WeirdType { - WeirdType - } -} - -// We also need `Deref` to treat it like a string with `as_ref_str`. -impl std::ops::Deref for WeirdType { - type Target = str; - fn deref(&self) -> &str { - self.as_ref() - } -} - -// We also need `Borrow` to treat it like a string with `as_ref_str`. -impl core::borrow::Borrow for WeirdType { - fn borrow(&self) -> &str { - self.as_ref() - } -} - -// We also need `Display` to work. -impl std::fmt::Display for WeirdType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.as_ref()) - } -} - -// Here we create a struct that doesn't use the default name for the inner field. We also tell -// the `Scalar` macro to treat the inner type like a string. -#[derive(Debug, PartialEq, Scalar)] -#[scalar(as_ref_str = true, inner = "some_field")] -struct MyWrapper { - some_field: WeirdType, -} - -impl Validate for MyWrapper { - fn validate>(input: T) -> Result { - Ok(Self{ some_field: input.into() }) - } -} - -let value = MyWrapper::new(WeirdType).unwrap(); -// This type can be compared with &str because we specified `as_ref_str = true`. -assert!("i'm a weird type" == value); -``` - -### Enums - -When used with an enum, `Scalar` implements a few `String` conversions such as `Display` and -`FromStr`. - -```rust -use scalar_derive::Scalar; -use serde::{Serialize, Deserialize}; -use std::convert::TryInto; - -#[derive(Debug, PartialEq, Serialize, Deserialize, Scalar)] -#[serde(rename_all = "snake_case")] -enum Color { - Red, - Green, - Blue, -} - - -let value = Color::Blue; -let to_string_val = value.to_string(); -assert_eq!(to_string_val, "blue"); -let from_str_val: Color = "blue".parse().unwrap(); -assert_eq!(value, from_str_val); -let into_string_val: String = value.into(); -assert_eq!(into_string_val, "blue"); -let try_from_value: Color = "blue".try_into().unwrap(); -assert_eq!(Color::Blue, try_from_value); -``` - - -## Colophon - -This text was generated from `README.tpl` using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/lib.rs`. diff --git a/sources/models/scalar-derive/README.tpl b/sources/models/scalar-derive/README.tpl deleted file mode 100644 index 91fb62910c8..00000000000 --- a/sources/models/scalar-derive/README.tpl +++ /dev/null @@ -1,9 +0,0 @@ -# {{crate}} - -Current version: {{version}} - -{{readme}} - -## Colophon - -This text was generated from `README.tpl` using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/lib.rs`. diff --git a/sources/models/scalar-derive/build.rs b/sources/models/scalar-derive/build.rs deleted file mode 100644 index 42defdba22e..00000000000 --- a/sources/models/scalar-derive/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - generate_readme::from_lib().unwrap(); -} diff --git a/sources/models/scalar-derive/src/lib.rs b/sources/models/scalar-derive/src/lib.rs deleted file mode 100644 index cbfbef37c10..00000000000 --- a/sources/models/scalar-derive/src/lib.rs +++ /dev/null @@ -1,612 +0,0 @@ -/*! - -A convenience macro for Bottlerocket model types. - -## Description - -The `Scalar` macro can be used for strings or numbers that need to be validated in the Bottlerocket -model. It uses a trait, also named `Scalar`, to treat a `struct` as a thin wrapper around an -internal scalar type, or to treat an `enum` as "string-like". - -For structs, the macro expects your inner scalar type to implement `Display`, `PartialEq`, -`Serialize` and `Deserialize`. It then implements these traits on the wrapper type by passing them -through to the inner type. - -You are also expected to implement the `Validate` trait on your `Scalar` struct types (the wrapper, -not the inner type). This macro will call `::validate(some_value)` when -implementing `YourType::new`. - -Enums do not require a wrapping struct since it is assumed that the deserializtion of the enum -serves as validation. When using the `Scalar` macro on an enum it expects the enum to implement -`Serialize` and `Deserialize`. It also expects that your enum doesn't not contain any structures. -That is, your enum should be representable with a simple string and compatible with `serde_plain`. -The `Scalar` uses `serde_plain`, to implement `Display`, `FromStr` and `String` conversions for your -enum. - -## Parameters - -The macro can take the following input parameters when used with wrapper structs (in most cases you -will not need to use these; the defaults will "just work"): -- `as_ref_str: bool`: Set to `true` if need the macro to treat your inner type as a `String`. - This will happen automatically if your inner type is named `String`. -- `inner`: The name of the field that holds your `inner` type. Defaults to `inner`. - -# Examples - -## Simple Usage - -This is an example of a very common use-case in Bottlerocket. We have a string, but we want to -validate it. In this example we want to return an error if the string is "pineapple". - -``` -use scalar::traits::{Scalar, Validate}; -use scalar::ValidationError; -use scalar_derive::Scalar; - -// We create a struct with an inner type in a field named `inner`. We derive `Scalar`. -#[derive(Debug, PartialEq, Scalar)] -struct Pizza { - inner: String -} - -// We must implement the `Validate` trait for our type. -impl Validate for Pizza { - fn validate>(input: S) -> Result { - let input: String = input.into(); - if input == "pineapple" { - Err(ValidationError::new("pineapple is gross on pizza")) - } else { - Ok(Self{ inner: input }) - } - } -} - -// The `Scalar` derive macro has made it so that we can use `Pizza` as if it were a `String`, -// but we know that the value has been validated. - -let pizza = Pizza::new("pepperoni").unwrap(); -// `pizza` behaves like a string! -assert!("pepperoni" == pizza); - -let err = Pizza::new("pineapple"); -// no that's gross! -assert!(err.is_err()); -``` - -## Validating a Number - -Here we use the Scalar macro with a numeric inner type. The inner value is constrained to be less -than 4. - -``` -use scalar::traits::{Scalar, Validate}; -use scalar::ValidationError; -use scalar_derive::Scalar; - -#[derive(Debug, PartialEq, Scalar)] -struct CatQuantity { - inner: i32 -} - -impl Validate for CatQuantity { - fn validate>(input: I) -> Result { - let input: i32 = input.into(); - if input > 4 { - Err(ValidationError::new("that's too many cats")) - } else { - Ok(Self{ inner: input }) - } - } -} - -let cat_quantity = CatQuantity::new(2).unwrap(); -// `cat_quantity` can be compared to a i32 -assert!(2 == cat_quantity); - -let err = CatQuantity::new(23); -// no that's too many! -assert!(err.is_err()); -``` - -## Using Macro Parameters - -In this example we will show how to use the parameters `as_ref_str` and `inner`. This example is -contrived, but demonstrates how to pass parameters to the derive macro. - -``` -use scalar::traits::{Scalar, Validate}; -use scalar::ValidationError; -use scalar_derive::Scalar; -use serde::{Serialize, Deserialize}; - -#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] -struct WeirdType; - -// We need `AsRef` to treat it like a string with `as_ref_str`. -impl AsRef for WeirdType { - fn as_ref(&self) -> &str { - "i'm a weird type" - } -} - -// We also need `From<&str>` to treat it like a string with `as_ref_str`. -impl From<&str> for WeirdType { - fn from(_: &str) -> WeirdType { - WeirdType - } -} - -// We also need `Deref` to treat it like a string with `as_ref_str`. -impl std::ops::Deref for WeirdType { - type Target = str; - fn deref(&self) -> &str { - self.as_ref() - } -} - -// We also need `Borrow` to treat it like a string with `as_ref_str`. -impl core::borrow::Borrow for WeirdType { - fn borrow(&self) -> &str { - self.as_ref() - } -} - -// We also need `Display` to work. -impl std::fmt::Display for WeirdType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.as_ref()) - } -} - -// Here we create a struct that doesn't use the default name for the inner field. We also tell -// the `Scalar` macro to treat the inner type like a string. -#[derive(Debug, PartialEq, Scalar)] -#[scalar(as_ref_str = true, inner = "some_field")] -struct MyWrapper { - some_field: WeirdType, -} - -impl Validate for MyWrapper { - fn validate>(input: T) -> Result { - Ok(Self{ some_field: input.into() }) - } -} - -let value = MyWrapper::new(WeirdType).unwrap(); -// This type can be compared with &str because we specified `as_ref_str = true`. -assert!("i'm a weird type" == value); -``` - -## Enums - -When used with an enum, `Scalar` implements a few `String` conversions such as `Display` and -`FromStr`. - -``` -use scalar_derive::Scalar; -use serde::{Serialize, Deserialize}; -use std::convert::TryInto; - -#[derive(Debug, PartialEq, Serialize, Deserialize, Scalar)] -#[serde(rename_all = "snake_case")] -enum Color { - Red, - Green, - Blue, -} - - -let value = Color::Blue; -let to_string_val = value.to_string(); -assert_eq!(to_string_val, "blue"); -let from_str_val: Color = "blue".parse().unwrap(); -assert_eq!(value, from_str_val); -let into_string_val: String = value.into(); -assert_eq!(into_string_val, "blue"); -let try_from_value: Color = "blue".try_into().unwrap(); -assert_eq!(Color::Blue, try_from_value); -``` - -*/ - -use darling::FromAttributes; -use proc_macro::TokenStream; -use quote::{format_ident, ToTokens}; -use quote::{quote, TokenStreamExt}; -use syn::__private::TokenStream2; -use syn::{parse_macro_input, Data, DataEnum, DataStruct, DeriveInput, Fields}; - -/// A convenience macro for implementing Bottlerocket model types. See description in the lib -/// documentation or README. -#[proc_macro_derive(Scalar, attributes(scalar))] -pub fn scalar(input: TokenStream) -> TokenStream { - // Parse the input tokens. - let derive_input = parse_macro_input!(input as DeriveInput); - let name = derive_input.ident.to_string(); - let settings = RawSettings::from_attributes(derive_input.attrs.as_slice()) - .expect("Unable to parse `scalar` macro arguments"); - - // We will write syntax as tokens to this token stream. - let mut ast2 = TokenStream2::new(); - - match &derive_input.data { - Data::Struct(s) => { - // Further parse the input. - let struct_info = StructInfo::new(&name, s, settings); - struct_info.write_impls(&mut ast2); - } - Data::Enum(data_enum) => { - require_simple_enum(&name, data_enum); - write_string_impls_for_enum(&name, &mut ast2) - } - Data::Union(_) => panic!("A Scalar cannot be an union, it must be a struct or enum"), - } - - // Convert - ast2.into_token_stream().into() -} - -/// Store args given by the user inside `#[scalar(as_ref_str=false, ...)]` using `darling` (it's -/// kind of like `clap` for derive macro arguments). -#[derive(Debug, Clone, Default, FromAttributes)] -#[darling(attributes(scalar))] -#[darling(default)] -struct RawSettings { - /// Whether or not `AsRef` (and similar impls) should be created. If the inner type is - /// `String` (or implements `AsRef`) then it is more convenient when using the `Scalar` if - /// it treats references to its inner type as `&str` instead of `&String`. This defaults to - /// `true` when the inner type is `String` and `false` otherwise. - as_ref_str: Option, - /// The name of the field that holds the inner value in the struct. Defaults to "inner". - inner: Option, -} - -/// Once we parse the incoming AST and see what our struct is named, see what its inner type is, -/// and introspect the macro arguments, we save the resultant information in this structure for -/// use during code generation. -#[derive(Debug, Clone)] -struct StructInfo { - /// The typename of the struct or enum, that the `Scalar` derive macro was called on. - scalar: String, - /// The name of the field, inside the `scalar` struct, that holds the "inner" value. - inner_field: String, - /// The type of the `inner_field`. - inner_type: String, - /// Whether or not we should treat the inner reference type as `&str`. - as_ref_str: bool, -} - -impl StructInfo { - fn new(name: &str, data: &DataStruct, settings: RawSettings) -> Self { - let (inner_field, inner_type) = find_inner_field(data.clone(), settings.inner.as_deref()); - - // Automatically impl AsRef when unspecified by the user but the inner type is String. - // Note, this might not work if String is not what we think it is. We assume that anything - // named `String`, `string::String`, or `std::string::String` is, in fact, a - // `std::string::String`. - let as_ref_str = settings - .as_ref_str - .unwrap_or_else(|| is_string(&inner_type)); - - Self { - scalar: name.to_owned(), - inner_field, - inner_type, - as_ref_str, - } - } - - /// Returns an `Ident` named `str` when we want to treat the inner type as a `String` (i.e. we - /// want to impl `AsRef` and such). Otherwise returns the inner typename as an `Ident`. - fn inner_ref_type(&self) -> proc_macro2::Ident { - format_ident!( - "{}", - if self.as_ref_str { - String::from("str") - } else { - self.inner_type.to_string() - } - ) - } - - fn write_impls(&self, stream: &mut TokenStream2) { - // We need to store our information in local variables for the quote macro. - let scalar = format_ident!("{}", &self.scalar); - let inner_type = format_ident!("{}", &self.inner_type); - let inner_ref_type = self.inner_ref_type(); - - // Create the Scalar trait implementation, which is different based on whether the inner - // field is named or unnamed (i.e. in a tuple struct like this `MyStruct(String)` - let trait_impl = if let Ok(index) = self.inner_field.parse::() { - // If the inner field is unnamed, i.e. `0` or `1`, etc., we need to cast it as an index - // so that quote will do the right thing with it. - let index = syn::Index::from(index); - quote!( - impl scalar::traits::Scalar for #scalar { - type Inner = #inner_type; - - fn new>(inner: T) -> Result - where - Self: Sized, - { - <#scalar as scalar::traits::Validate>::validate(inner.into()) - } - - fn inner(&self) -> &Self::Inner { &self.#index } - - fn unwrap(self) -> Self::Inner { self.#index } - } - ) - } else { - // If the inner field is named, we cast it as an identifier. - let inner_field = format_ident!("{}", &self.inner_field); - quote!( - impl scalar::traits::Scalar for #scalar { - type Inner = #inner_type; - - fn new>(inner: T) -> Result - where - Self: Sized, - { - <#scalar as scalar::traits::Validate>::validate(inner.into()) - } - - fn inner(&self) -> &Self::Inner { &self.#inner_field } - - fn unwrap(self) -> Self::Inner { self.#inner_field } - } - ) - }; - - // Generate code. - let impls = quote!( - #trait_impl - - impl std::convert::TryFrom<<#scalar as scalar::traits::Scalar>::Inner> for #scalar { - type Error = ValidationError; - fn try_from(input: <#scalar as scalar::traits::Scalar>::Inner) -> Result { - Self::new(input) - } - } - - impl<'de> serde::de::Deserialize<'de> for #scalar { - fn deserialize(deserializer: D) -> Result - where - D: serde::de::Deserializer<'de>, - { - let original = <#scalar as scalar::traits::Scalar>::Inner::deserialize(deserializer)?; - // We need to make sure the serde Error trait is in scope. - use serde::de::Error as _; - let scalar = #scalar::new(original).map_err(|e| { - D::Error::custom(format!("Unable to deserialize into {}: {}", stringify!(#scalar), e)) - })?; - Ok(scalar) - } - } - - impl serde::ser::Serialize for #scalar { - fn serialize(&self, serializer: S) -> Result - where - S: serde::ser::Serializer, - { - self.inner().serialize(serializer) - } - } - - impl std::fmt::Display for #scalar { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.inner()) - } - } - - impl std::ops::Deref for #scalar { - type Target = #inner_ref_type; - fn deref(&self) -> &Self::Target { - self.inner() - } - } - - impl core::borrow::Borrow<#inner_ref_type> for #scalar { - fn borrow(&self) -> &#inner_ref_type { - self.inner() - } - } - - impl AsRef<#inner_ref_type> for #scalar { - fn as_ref(&self) -> &#inner_ref_type { - self.inner() - } - } - - impl PartialEq<<#scalar as scalar::traits::Scalar>::Inner> for #scalar { - fn eq(&self, other: &<#scalar as scalar::traits::Scalar>::Inner) -> bool { - (*(&self.inner())).eq(other) - } - } - - impl PartialEq<#scalar> for <#scalar as scalar::traits::Scalar>::Inner { - fn eq(&self, other: &#scalar) -> bool { - self.eq(*(&other.inner())) - } - } - - impl From<#scalar> for <#scalar as scalar::traits::Scalar>::Inner { - fn from(scalar: #scalar) -> Self { - scalar.unwrap() - } - } - ); - - stream.append_all(impls); - - // Generate code that is only applicable if the inner type can be treated like a String. - if self.as_ref_str { - let code = quote!( - impl std::convert::TryFrom<&#inner_ref_type> for #scalar { - type Error = ValidationError; - fn try_from(input: &#inner_ref_type) -> Result { - Self::new(input) - } - } - - impl PartialEq<#inner_ref_type> for #scalar { - fn eq(&self, other: &#inner_ref_type) -> bool { - let self_as_str: &str = self.as_ref(); - let other_as_str: &str = other.as_ref(); - self_as_str.eq(other_as_str) - } - } - - impl PartialEq<#scalar> for #inner_ref_type { - fn eq(&self, other: &#scalar) -> bool { - let self_as_str: &str = self.as_ref(); - let other_as_str: &str = other.as_ref(); - self_as_str.eq(other_as_str) - } - } - - impl PartialEq<#scalar> for &#inner_ref_type { - fn eq(&self, other: &#scalar) -> bool { - let other_as_str: &str = other.inner().as_ref(); - let self_as_str: &str = self.as_ref(); - self_as_str.eq(other_as_str) - } - } - - impl PartialEq<&#inner_ref_type> for #scalar { - fn eq(&self, other: &&#inner_ref_type) -> bool { - let other_as_str: &str = (*other); - let self_as_str: &str = self.as_ref(); - self_as_str.eq(other_as_str) - } - } - ); - stream.append_all(code); - } - - // If the inner type is String, then we already have this implemented. If not, we can add - // this as a convenience since we know the inner type implements `Display`. - if !is_string(&self.inner_type) { - let code = quote!( - impl From<#scalar> for String { - fn from(scalar: #scalar) -> Self { - scalar.unwrap().to_string() - } - } - ); - stream.append_all(code); - } - } -} - -/// Given a type `t`, what is its `typename`? -fn typename(t: &syn::Type) -> String { - let mut stream = proc_macro2::TokenStream::new(); - t.to_tokens(&mut stream); - stream.to_string() -} - -/// Whether or not the type assumed to be `std::string::String` -fn is_string(t: &str) -> bool { - t == "String" || t == "string::String" || t == "std::string::String" -} - -/// This function finds the "inner" field of the struct. The most common example is: -/// -/// ```no_run -/// struct SomeStruct { -/// inner: String -/// } -/// ``` -/// -/// In the above example, this function would return the field ("inner", "String") -fn find_inner_field(data_struct: DataStruct, field_name: Option<&str>) -> (String, String) { - match &data_struct.fields { - Fields::Named(named_fields) => { - let field_name = field_name.unwrap_or("inner"); - for field in &named_fields.named { - if let Some(field_ident) = &field.ident { - let field_ident: &syn::Ident = field_ident; - if field_ident == field_name { - return (field_name.to_string(), typename(&field.ty)); - } - } - } - panic!( - "The Scalar derive macro could not find a field named '{}', in this struct", - field_name - ); - } - Fields::Unnamed(unnamed_field) => { - let field_name = field_name.unwrap_or("0"); - return ( - field_name.to_string(), - typename( - &unnamed_field - .unnamed - .iter() - .next() - .expect( - "The Scalar macro could not parse the unnamed fields of this struct", - ) - .ty, - ), - ); - } - Fields::Unit => { - panic!( - "The Scalar derive macro does not work on 'unit' types, it should have one or more \ - fields" - ) - } - } -} - -/// For enums we assume `Serialize` and `Deserialize` are implemented, and that the enum is "simple" -/// (i.e. it de/serializes from/to a string). We use this to implement `Display` and conversions -/// from strings. -fn write_string_impls_for_enum(name: &str, ast: &mut TokenStream2) { - let scalar = format_ident!("{}", name); - let impls = quote!( - serde_plain::derive_display_from_serialize!(#scalar); - serde_plain::derive_fromstr_from_deserialize!(#scalar, scalar::ValidationError); - - impl ::std::convert::From<#scalar> for String { - fn from(s: #scalar) -> Self { - s.to_string() - } - } - - impl ::std::convert::TryFrom<&str> for #scalar { - type Error = scalar::ValidationError; - - fn try_from(value: &str) -> Result { - value.parse() - } - } - - impl ::std::convert::TryFrom for #scalar { - type Error = scalar::ValidationError; - - fn try_from(value: String) -> Result { - value.as_str().parse() - } - } - ); - - ast.append_all(impls); -} - -/// Make sure all variants of the enum are empty of data. Otherwise we can't represent this enum -/// as a simple string in the datastore. -fn require_simple_enum(name: &str, e: &DataEnum) { - for variant in e.variants.iter() { - if !variant.fields.is_empty() { - panic!( - "The enum '{}' cannot be used with the Scalar derive macro because it has non unit \ - variants. No variants in the enum should carry any data. The '{}' variant was \ - found to have one or more fields.", name, variant.ident - ) - } - } -} diff --git a/sources/models/scalar-derive/tests/tests.rs b/sources/models/scalar-derive/tests/tests.rs deleted file mode 100644 index d75b138dc06..00000000000 --- a/sources/models/scalar-derive/tests/tests.rs +++ /dev/null @@ -1,87 +0,0 @@ -use scalar::traits::{Scalar, Validate}; -use scalar::ValidationError; -use scalar_derive::Scalar; - -// By default the `0` field will be our `inner` field. -#[derive(Debug, PartialEq, Scalar)] -struct SimpleString(String); - -impl Validate for SimpleString { - fn validate(input: T) -> Result - where - T: Into<::Inner>, - { - // No validation - Ok(Self(input.into())) - } -} - -#[test] -fn simple_string() { - let s = SimpleString::new("foo").unwrap(); - // Check that a few dereferencing conveniences compile - let eq1 = "foo" == s; - let eq2 = *"foo" == s; - let eq3 = "foo" == &s; - // Assert these in a way that doesn't use assert_eq and doesn't make my IDE mad - assert!(eq1); - assert!(eq2); - assert!(eq3); -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -// By default the `0` field will be our `inner` field. -#[derive(Debug, PartialEq, Scalar)] -struct UnnamedFields(u16, String); - -impl Validate for UnnamedFields { - fn validate(input: T) -> Result - where - T: Into<::Inner>, - { - let input = input.into(); - // Contrived weirdness - if input == 0 { - Err(ValidationError::new("never zero")) - } else if input == 1 { - Ok(Self(2, "it was 1 but I changed it to 2".to_string())) - } else { - Ok(Self(input, "".to_string())) - } - } -} - -#[test] -fn unnamed_fields() { - let i = UnnamedFields::new(1u16).unwrap(); - let eq1 = 2u16 == i; - let eq2 = &2u16 == &i; - assert!(eq1); - assert!(eq2); -} - -// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= - -// We will make `1` the inner field -#[derive(Debug, PartialEq, Scalar)] -#[scalar(inner = "1")] -struct SecondField(u16, u16); - -impl Validate for SecondField { - fn validate(input: T) -> Result - where - T: Into<::Inner>, - { - Ok(Self(100u16, input.into())) - } -} - -#[test] -fn second_field() { - let i = SecondField::new(3u16).unwrap(); - let eq1 = 3u16 == i; - let eq2 = &3u16 == &i; - assert!(eq1); - assert!(eq2); -} diff --git a/sources/models/scalar/Cargo.toml b/sources/models/scalar/Cargo.toml deleted file mode 100644 index 6de04044410..00000000000 --- a/sources/models/scalar/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "scalar" -version = "0.1.0" -authors = ["Matt Briggs "] -license = "Apache-2.0 OR MIT" -edition = "2021" -publish = false -build = "build.rs" -# Don't rebuild crate just because of changes to README. -exclude = ["README.md"] - -[dependencies] -serde = "1" -serde_plain = "1" - -[build-dependencies] -generate-readme = { path = "../../generate-readme", version = "0.1" } diff --git a/sources/models/scalar/README.md b/sources/models/scalar/README.md deleted file mode 100644 index 76a2c12046e..00000000000 --- a/sources/models/scalar/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# scalar - -Current version: 0.1.0 - - -This library provides traits and an error type to be used in Bottlerocket models. It is intended -to be combined with the `scalar-derive` crate so that we can use the `Scalar` macro on simple -types. - - -## Colophon - -This text was generated from `README.tpl` using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/lib.rs`. diff --git a/sources/models/scalar/README.tpl b/sources/models/scalar/README.tpl deleted file mode 100644 index 91fb62910c8..00000000000 --- a/sources/models/scalar/README.tpl +++ /dev/null @@ -1,9 +0,0 @@ -# {{crate}} - -Current version: {{version}} - -{{readme}} - -## Colophon - -This text was generated from `README.tpl` using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/lib.rs`. diff --git a/sources/models/scalar/build.rs b/sources/models/scalar/build.rs deleted file mode 100644 index 42defdba22e..00000000000 --- a/sources/models/scalar/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - generate_readme::from_lib().unwrap(); -} diff --git a/sources/models/scalar/src/lib.rs b/sources/models/scalar/src/lib.rs deleted file mode 100644 index 3393c8382d4..00000000000 --- a/sources/models/scalar/src/lib.rs +++ /dev/null @@ -1,196 +0,0 @@ -/*! - -This library provides traits and an error type to be used in Bottlerocket models. It is intended -to be combined with the `scalar-derive` crate so that we can use the `Scalar` macro on simple -types. - -*/ - -use serde::Serialize; -use std::error::Error; -use std::fmt::{Display, Formatter}; - -/// Because the `Scalar` trait has the same name as the `Scalar` derive macro, we place it and the -/// `Validate` traits into a module named `traits`. -pub mod traits { - use super::*; - - /// The `Scalar` trait is used to wrap some inner, validated, value. It is intended for use in - /// the Bottlerocket model for values like strings or numbers that need some additional - /// validation. The `Inner` value is the string or number that has been validated. Validation - /// of the `Inner` value takes place during the `new` function. Thus a constructed `Scalar` - /// object can be expected to hold a valid value. - /// - /// # Example - /// - /// ``` - /// use scalar::traits::Scalar; - /// use scalar::ValidationError; - /// - /// pub struct Pizza { - /// inner: String, - /// } - /// - /// impl Scalar for Pizza { - /// type Inner = String; - /// - /// fn new>(input: T) -> Result where Self: Sized { - /// let input: String = input.into(); - /// if input == "pineapple" { - /// Err(ValidationError::new("pineapple is gross on pizza")) - /// } else { - /// Ok(Self{ inner: input }) - /// } - /// } - /// - /// fn inner(&self) -> &Self::Inner { - /// &self.inner - /// } - /// - /// fn unwrap(self) -> Self::Inner { - /// self.inner - /// }} - /// ``` - /// - pub trait Scalar { - /// The inner type who's value is being wrapped by the `Scalar` object. For example, - /// `String`, `u32`, etc. - /// - /// The traits bounds on the `Inner` type exist because the `Scalar` derive macro expects - /// them to be there. Placing the trait bounds here makes error messages easier to interpret - /// when using the `Scalar` derive macro. The macro also requires `Deserialize<'de>`, but it - /// is unhelpful to add it to the trait bounds here because of the lifetime parameter. - type Inner: PartialEq + Display + Serialize; - - /// Creates a new instance of the `Scalar` object. Validates `input` and returns a - /// `ValidationError` if the `input` is invalid. - fn new>(input: T) -> Result - where - Self: Sized; - - /// Return a reference to the inner value. - fn inner(&self) -> &Self::Inner; - - /// Destroys the `Scalar` object and gives ownership of its inner value. - fn unwrap(self) -> Self::Inner; - } - - /// `Validate` provides a function that you can implement to construct your `Scalar` type from - /// its `Inner` type. The `Scalar` derive macro expects your `Scalar` type to implement - /// `Validate`. - /// - /// # Example - /// - /// If we rewrite the `Scalar` example to incorporate the `Validate` trait, it looks like this. - /// Notice that the validation has moved to the `Validate` trait and that the `Scalar::new` - /// function calls it. This is what the `new` function looks like when generated by the `Scalar` - /// derive macro. - /// - /// ``` - /// use scalar::traits::{Scalar, Validate}; - /// use scalar::ValidationError; - /// - /// pub struct Pizza { - /// inner: String, - /// } - /// - /// impl Validate for Pizza { - /// fn validate(input: T) -> Result - /// where T: Into<::Inner> { - /// let input: String = input.into(); - /// if input == "pineapple" { - /// Err(ValidationError::new("pineapple is gross on pizza")) - /// } else { - /// Ok(Self{ inner: input }) - /// } - /// } - /// - /// } - /// - /// impl Scalar for Pizza { - /// type Inner = String; - /// - /// fn new>(input: T) -> Result - /// where Self: Sized { - /// ::validate(input) - /// } - /// - /// fn inner(&self) -> &Self::Inner { - /// &self.inner - /// } - /// - /// fn unwrap(self) -> Self::Inner { - /// self.inner - /// }} - /// ``` - /// - pub trait Validate - where - Self: Scalar + Sized, - { - /// Constructs a validated `Wrapper` object. - fn validate(input: T) -> Result - where - T: Into<::Inner>; - } -} - -/// The error type that [`Validate::validate`] returns. -#[derive(Debug)] -pub struct ValidationError { - /// A message about what occurred during validation. - message: String, - /// The underlying error that occurred (if any). - source: Option>, -} - -impl ValidationError { - /// Creates a new [`ValidationError`] with a message. Use this when there is no underlying error - /// to include. - pub fn new(message: S) -> Self - where - S: AsRef, - { - Self { - message: message.as_ref().into(), - source: None, - } - } - - /// Creates a new [`ValidationError`] with a message and an error. Use this when you have an - /// underlying error that you want to preserve as the `source`. - pub fn new_with_cause(message: S, source: E) -> Self - where - E: Into>, - S: AsRef, - { - Self { - message: message.as_ref().into(), - source: Some(source.into()), - } - } -} - -impl Display for ValidationError { - /// Display the message if there is no underlying error, or display both if there is one. - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - if let Some(e) = self.source.as_ref() { - write!(f, "{}: {}", self.message, e) - } else { - write!(f, "{}", self.message) - } - } -} - -impl Error for ValidationError { - /// Return the underlying error if there is one. - fn source(&self) -> Option<&(dyn Error + 'static)> { - self.source.as_ref().map(|e| e.as_ref() as &(dyn Error)) - } -} - -impl From for ValidationError { - fn from(e: serde_plain::Error) -> Self { - ValidationError::new_with_cause("Unable to convert from string", e) - } -} diff --git a/sources/models/src/de.rs b/sources/models/src/de.rs deleted file mode 100644 index c1a0f11444b..00000000000 --- a/sources/models/src/de.rs +++ /dev/null @@ -1,333 +0,0 @@ -use crate::{KubernetesLabelKey, KubernetesTaintValue, RegistryMirror}; -use serde::de::value::SeqAccessDeserializer; -use serde::de::{Error, MapAccess, SeqAccess, Visitor}; -use serde::{Deserialize, Deserializer}; -use std::collections::HashMap; -use std::convert::TryFrom; -use std::fmt::Formatter; -use toml::Value; - -// Our standard representation of node-taints is a `HashMap` of label keys to a list of taint values and effects; -// for backward compatibility, we also allow a `HashMap` of label keys to a singular taint value/effect. -pub(crate) fn deserialize_node_taints<'de, D>( - deserializer: D, -) -> Result>>, D::Error> -where - D: Deserializer<'de>, -{ - struct NodeTaints; - - impl<'de> Visitor<'de> for NodeTaints { - type Value = Option>>; - fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { - formatter.write_str("TOML table") - } - - fn visit_map(self, mut map: M) -> Result - where - M: MapAccess<'de>, - { - let mut node_taints: HashMap> = - HashMap::new(); - while let Some((k, v)) = map.next_entry()? { - match v { - // If we encounter a singular mapped value, convert it into a list of one - Value::String(taint_val) => { - node_taints.insert( - k, - vec![KubernetesTaintValue::try_from(taint_val) - .map_err(M::Error::custom)?], - ); - } - // If we encounter a list of values, just insert it as is - Value::Array(taint_values) => { - let taint_values = taint_values - .iter() - .map(|v| v.to_owned().try_into().map_err(M::Error::custom)) - .collect::, _>>()?; - if taint_values.is_empty() { - return Err(M::Error::custom("empty taint value")); - } - node_taints.insert(k, taint_values); - } - _ => { - return Err(M::Error::custom("unsupported taint value type")); - } - } - } - Ok(Some(node_taints)) - } - } - - deserializer.deserialize_map(NodeTaints) -} - -#[cfg(test)] -mod node_taint_tests { - use crate::{KubernetesSettings, KubernetesTaintValue}; - use std::convert::TryFrom; - static TEST_NODE_TAINT_LIST: &str = include_str!("../tests/data/node-taint-list-val"); - static TEST_NODE_TAINT_SINGLE: &str = include_str!("../tests/data/node-taint-single-val"); - static TEST_NODE_TAINT_EMPTY_LIST: &str = include_str!("../tests/data/node-taint-empty-list"); - - #[test] - fn node_taints_list_representation() { - let k8s_settings = toml::from_str::(TEST_NODE_TAINT_LIST).unwrap(); - assert_eq!( - k8s_settings - .node_taints - .as_ref() - .unwrap() - .get("key1") - .unwrap() - .to_owned(), - vec![ - KubernetesTaintValue::try_from("value1:NoSchedule").unwrap(), - KubernetesTaintValue::try_from("value1:NoExecute").unwrap() - ] - ); - assert_eq!( - k8s_settings - .node_taints - .as_ref() - .unwrap() - .get("key2") - .unwrap() - .to_owned(), - vec![KubernetesTaintValue::try_from("value2:NoSchedule").unwrap()] - ); - } - - #[test] - fn node_taint_single_representation() { - let k8s_settings = toml::from_str::(TEST_NODE_TAINT_SINGLE).unwrap(); - assert_eq!( - k8s_settings - .node_taints - .as_ref() - .unwrap() - .get("key1") - .unwrap() - .to_owned(), - vec![KubernetesTaintValue::try_from("value1:NoSchedule").unwrap()] - ); - assert_eq!( - k8s_settings - .node_taints - .as_ref() - .unwrap() - .get("key2") - .unwrap() - .to_owned(), - vec![KubernetesTaintValue::try_from("value2:NoExecute").unwrap()] - ); - } - - #[test] - fn node_taint_none_representation() { - let k8s_settings = toml::from_str::("").unwrap(); - assert!(k8s_settings.node_taints.is_none()); - } - - #[test] - fn node_taint_empty_list() { - assert!(toml::from_str::(TEST_NODE_TAINT_EMPTY_LIST).is_err()); - } -} - -// Our standard representation of registry mirrors is a `Vec` of `RegistryMirror`; for backward compatibility, we also allow a `HashMap` of registry to endpoints. -pub(crate) fn deserialize_mirrors<'de, D>( - deserializer: D, -) -> Result>, D::Error> -where - D: Deserializer<'de>, -{ - struct TableOrArray; - - impl<'de> Visitor<'de> for TableOrArray { - type Value = Option>; - - fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { - formatter.write_str("TOML array or TOML table") - } - - fn visit_seq(self, seq: A) -> Result - where - A: SeqAccess<'de>, - { - Ok(Some(Deserialize::deserialize(SeqAccessDeserializer::new( - seq, - ))?)) - } - - fn visit_map(self, mut map: M) -> Result - where - M: MapAccess<'de>, - { - let mut vec = Vec::new(); - while let Some((k, v)) = map.next_entry()? { - vec.push(RegistryMirror { - registry: Some(k), - endpoint: Some(v), - }); - } - Ok(Some(vec)) - } - } - deserializer.deserialize_any(TableOrArray) -} - -#[cfg(test)] -mod mirrors_tests { - use crate::RegistrySettings; - static TEST_MIRRORS_ARRAY: &str = include_str!("../tests/data/mirrors-array"); - static TEST_MIRRORS_TABLE: &str = include_str!("../tests/data/mirrors-table"); - - #[test] - fn registry_mirrors_array_representation() { - assert!(toml::from_str::(TEST_MIRRORS_ARRAY).is_ok()); - } - - #[test] - fn registry_mirrors_table_representation() { - assert!(toml::from_str::(TEST_MIRRORS_TABLE).is_ok()); - } - - #[test] - fn registry_mirrors_none_representation() { - let registry_settings = toml::from_str::("").unwrap(); - assert!(registry_settings.mirrors.is_none()); - } - - #[test] - fn representation_equal() { - assert_eq!( - toml::from_str::(TEST_MIRRORS_TABLE).unwrap(), - toml::from_str::(TEST_MIRRORS_ARRAY).unwrap() - ); - } -} - -// This specifies that any non negative i64 integer, -1, and "unlimited" -/// are the valid resource-limits. The hard-limit set to "unlimited" or -1 -/// and soft-limit set to "unlimited" or -1 are converted to u64::MAX in -/// the spec file for the container runtime which ultimately represents -/// unlimited for that resource -pub(crate) fn deserialize_limit<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - #[derive(Deserialize)] - #[serde(untagged)] - enum StringOrInt64 { - String(String), - Int(i64), - } - - match StringOrInt64::deserialize(deserializer)? { - StringOrInt64::String(s) => { - if s == "unlimited" { - Ok(-1) - } else { - Err(Error::custom(format!( - "Invalid rlimit {}, expected -1 to {} or \"unlimited\"", - s, - i64::MAX - ))) - } - } - StringOrInt64::Int(i) => { - if (-1..=i64::MAX).contains(&i) { - Ok(i) - } else { - Err(Error::custom(format!( - "Invalid rlimit {}, expected -1 to {} or \"unlimited\"", - i, - i64::MAX - ))) - } - } - } -} - -#[cfg(test)] -mod oci_default_resource_limit_tests { - use crate::OciDefaultsResourceLimit; - - #[test] - fn valid_any_integer_i_64() { - assert!(toml::from_str::( - r#" - hard-limit = 200000 - soft-limit = 10000 - "# - ) - .is_ok()); - } - - #[test] - fn valid_string_unlimited() { - assert!(toml::from_str::( - r#" - hard-limit = 'unlimited' - soft-limit = 10000 - "# - ) - .is_ok()); - } - - #[test] - fn valid_integer_i_64_max() { - assert!(toml::from_str::( - r#" - hard-limit = 9223372036854775807 - soft-limit = 10000 - "# - ) - .is_ok()); - } - - #[test] - fn valid_integer_minus_one() { - assert!(toml::from_str::( - r#" - hard-limit = -1 - soft-limit = 10000 - "# - ) - .is_ok()); - } - - #[test] - fn invalid_integer_greater_than_i_64_max() { - assert!(toml::from_str::( - r#" - hard-limit = 9223372036854775808 - soft-limit = 10000 - "# - ) - .is_err()); - } - - #[test] - fn invalid_minus_2() { - assert!(toml::from_str::( - r#" - hard-limit = -2 - soft-limit = 10000 - "# - ) - .is_err()); - } - - #[test] - fn invalid_string_abc() { - assert!(toml::from_str::( - r#" - hard-limit = 'abc' - soft-limit = 10000 - "# - ) - .is_err()); - } -} diff --git a/sources/models/src/lib.rs b/sources/models/src/lib.rs index a827636539b..e3015d3f9d1 100644 --- a/sources/models/src/lib.rs +++ b/sources/models/src/lib.rs @@ -18,44 +18,16 @@ At the field level, standard Rust types can be used, or ["modeled types"](src/mo The `#[model]` attribute on Settings and its sub-structs reduces duplication and adds some required metadata; see [its docs](model-derive/) for details. */ -// Clippy has a false positive in the presence of the Scalar macro. -#![allow(clippy::derived_hash_with_manual_eq)] - -// The "de" module contains custom deserialization trait implementation for models. -mod de; - -pub use modeled_types; -use modeled_types::KubernetesCPUManagerPolicyOption; -use modeled_types::KubernetesEvictionKey; -use modeled_types::KubernetesMemoryManagerPolicy; -use modeled_types::KubernetesMemoryReservation; -use modeled_types::NonNegativeInteger; - // Types used to communicate between client and server for 'apiclient exec'. pub mod exec; -// Below, we define common structures used in the API surface; specific variants build a Settings -// structure based on these, and that's what gets exposed via the API. (Specific variants' models -// are in subdirectories and linked into place by build.rs at variant/current.) - use bottlerocket_release::BottlerocketRelease; +use bottlerocket_settings_models::model_derive::model; use bottlerocket_settings_plugin::BottlerocketSettings; -use model_derive::model; use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use std::net::IpAddr; -use crate::de::{deserialize_limit, deserialize_mirrors, deserialize_node_taints}; -use modeled_types::{ - BootConfigKey, BootConfigValue, BootstrapContainerMode, CpuManagerPolicy, CredentialProvider, - DNSDomain, EtcHostsEntries, Identifier, IntegerPercent, KernelCpuSetValue, - KubernetesAuthenticationMode, KubernetesBootstrapToken, KubernetesCloudProvider, - KubernetesClusterDnsIp, KubernetesClusterName, KubernetesDurationValue, KubernetesLabelKey, - KubernetesLabelValue, KubernetesQuantityValue, KubernetesReservedResourceKey, - KubernetesTaintValue, KubernetesThresholdValue, OciDefaultsCapability, - OciDefaultsResourceLimitType, PemCertificateString, SingleLineString, TopologyManagerPolicy, - TopologyManagerScope, Url, ValidBase64, ValidLinuxHostname, -}; +use bottlerocket_settings_models::modeled_types::SingleLineString; #[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)] #[serde(transparent)] @@ -74,173 +46,6 @@ pub struct Model { os: BottlerocketRelease, } -// Kubernetes static pod manifest settings -#[model] -struct StaticPod { - enabled: bool, - manifest: ValidBase64, -} - -// Kubernetes related settings. The dynamic settings are retrieved from -// IMDS via Sundog's child "Pluto". -#[model] -struct KubernetesSettings { - // Settings that must be specified via user data or through API requests. Not all settings are - // useful for all modes. For example, in standalone mode the user does not need to specify any - // cluster information, and the bootstrap token is only needed for TLS authentication mode. - cluster_name: KubernetesClusterName, - cluster_certificate: ValidBase64, - api_server: Url, - node_labels: HashMap, - #[serde( - default, - skip_serializing_if = "Option::is_none", - deserialize_with = "deserialize_node_taints" - )] - node_taints: HashMap>, - static_pods: HashMap, - authentication_mode: KubernetesAuthenticationMode, - bootstrap_token: KubernetesBootstrapToken, - standalone_mode: bool, - eviction_hard: HashMap, - eviction_soft: HashMap, - eviction_soft_grace_period: HashMap, - eviction_max_pod_grace_period: NonNegativeInteger, - kube_reserved: HashMap, - system_reserved: HashMap, - allowed_unsafe_sysctls: Vec, - server_tls_bootstrap: bool, - cloud_provider: KubernetesCloudProvider, - registry_qps: i32, - registry_burst: i32, - event_qps: i32, - event_burst: i32, - kube_api_qps: i32, - kube_api_burst: i32, - container_log_max_size: KubernetesQuantityValue, - container_log_max_files: i32, - cpu_cfs_quota_enforced: bool, - cpu_manager_policy: CpuManagerPolicy, - cpu_manager_reconcile_period: KubernetesDurationValue, - cpu_manager_policy_options: Vec, - topology_manager_scope: TopologyManagerScope, - topology_manager_policy: TopologyManagerPolicy, - pod_pids_limit: i64, - image_gc_high_threshold_percent: IntegerPercent, - image_gc_low_threshold_percent: IntegerPercent, - provider_id: Url, - log_level: u8, - credential_providers: HashMap, - server_certificate: ValidBase64, - server_key: ValidBase64, - shutdown_grace_period: KubernetesDurationValue, - shutdown_grace_period_for_critical_pods: KubernetesDurationValue, - memory_manager_reserved_memory: HashMap, - memory_manager_policy: KubernetesMemoryManagerPolicy, - reserved_cpus: KernelCpuSetValue, - - // Settings where we generate a value based on the runtime environment. The user can specify a - // value to override the generated one, but typically would not. - max_pods: u32, - cluster_dns_ip: KubernetesClusterDnsIp, - cluster_domain: DNSDomain, - node_ip: IpAddr, - pod_infra_container_image: SingleLineString, - // Generated in `aws-k8s-1.26*` variants only - hostname_override: ValidLinuxHostname, - // Generated in `k8s-1.25+` variants only - seccomp_default: bool, -} - -#[model] -struct RegistryMirror { - registry: SingleLineString, - endpoint: Vec, -} - -#[model] -struct RegistryCredential { - registry: SingleLineString, - username: SingleLineString, - password: SingleLineString, - // This is the base64 encoding of "username:password" - auth: ValidBase64, - identitytoken: SingleLineString, -} - -// Image registry settings for the container runtimes. -#[model] -struct RegistrySettings { - #[serde( - default, - skip_serializing_if = "Option::is_none", - deserialize_with = "deserialize_mirrors" - )] - mirrors: Vec, - #[serde(alias = "creds", default, skip_serializing_if = "Option::is_none")] - credentials: Vec, -} - -#[model] -struct HostContainer { - source: Url, - enabled: bool, - superpowered: bool, - user_data: ValidBase64, -} - -// Network settings. These settings will affect host service components' network behavior -#[model(impl_default = true)] -struct NetworkSettings { - hostname: ValidLinuxHostname, - hosts: EtcHostsEntries, - https_proxy: Url, - // We allow some flexibility in NO_PROXY values because different services support different formats. - no_proxy: Vec, -} - -// Kernel module settings -#[model] -struct KmodSetting { - allowed: bool, - autoload: bool, -} - -// Kernel boot settings -#[model(impl_default = true)] -struct BootSettings { - reboot_to_reconcile: bool, - #[serde( - alias = "kernel", - rename(serialize = "kernel"), - default, - skip_serializing_if = "Option::is_none" - )] - kernel_parameters: HashMap>, - #[serde( - alias = "init", - rename(serialize = "init"), - default, - skip_serializing_if = "Option::is_none" - )] - init_parameters: HashMap>, -} - -// AutoScaling settings -#[model] -struct AutoScalingSettings { - should_wait: bool, -} - -// Container runtime settings -#[model] -struct ContainerRuntimeSettings { - max_container_log_line_size: i32, - max_concurrent_downloads: i32, - enable_unprivileged_ports: bool, - enable_unprivileged_icmp: bool, -} - ///// Internal services // Note: Top-level objects that get returned from the API should have a "rename" attribute @@ -277,40 +82,6 @@ struct Metadata { val: toml::Value, } -///// Bootstrap Containers - -#[model] -struct BootstrapContainer { - source: Url, - mode: BootstrapContainerMode, - user_data: ValidBase64, - essential: bool, -} - -///// PEM Certificates -#[model] -struct PemCertificate { - data: PemCertificateString, - trusted: bool, -} - -///// OCI defaults specifies the default values that will be used in cri-base-json. -#[model] -struct OciDefaults { - capabilities: HashMap, - resource_limits: HashMap, -} - -///// The hard and soft limit values for an OCI defaults resource limit. -#[model(add_option = false)] -#[derive(Copy, Clone, Debug, Deserialize, Serialize, Eq, Ord, PartialOrd, PartialEq)] -struct OciDefaultsResourceLimit { - #[serde(deserialize_with = "deserialize_limit")] - hard_limit: i64, - #[serde(deserialize_with = "deserialize_limit")] - soft_limit: i64, -} - #[model(add_option = false)] struct Report { name: String, diff --git a/sources/models/string_impls_for/Cargo.toml b/sources/models/string_impls_for/Cargo.toml deleted file mode 100644 index 7bffc49bba1..00000000000 --- a/sources/models/string_impls_for/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "string_impls_for" -version = "0.1.0" -authors = ["Tom Kirchner ", "Sean P. Kelly "] -license = "Apache-2.0 OR MIT" -edition = "2021" -publish = false -build = "build.rs" -# Don't rebuild crate just because of changes to README. -exclude = ["README.md"] - -[dependencies] -serde = "1" - -[build-dependencies] -generate-readme = { path = "../../generate-readme", version = "0.1" } diff --git a/sources/models/string_impls_for/README.md b/sources/models/string_impls_for/README.md deleted file mode 100644 index 824713740c8..00000000000 --- a/sources/models/string_impls_for/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# string_impls_for - -Current version: 0.1.0 - - -A convenience macro for Bottlerocket model types. - -### Description - -The `string_impls_for` is meant to assist in representing string-like types that require additional -validation when deserialized. These types should be modeled as a struct with a single string field -called `inner`. - -The user of the macro implements `TryFrom<&str>`, and the macro will derive implementations for -`TryFrom`, `serde::Deserialize`, `serde::Serialize`, `Deref`, `Borrow`, -`Borrow`, `AsRef`, `Display`, `Into`, `PartialEq`, `PartialEq<&str>`, and -`PartialEq`. - -### Example - -Consider a model which we want to contain a string name for a vegetable, you could implement -something like so: - -```rust -use string_impls_for::string_impls_for; - -#[derive(Debug, PartialEq, Eq)] -struct Vegetable { - inner: String, -} - -impl TryFrom<&str> for Vegetable { - type Error = &'static str; - - fn try_from(input: &str) -> std::result::Result { - if !["cucumber", "radish", "leek"].contains(&input) { - return Err("Vegetable name must be one of cucumber, radish, or leek"); - } - Ok(Vegetable { inner: input.to_string() }) - } -} - -string_impls_for!(Vegetable, "Vegetable"); - - -let cucumber = Vegetable::try_from("cucumber").unwrap(); -assert_eq!(cucumber.to_string(), "cucumber"); -``` -! - -## Colophon - -This text was generated from `README.tpl` using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/lib.rs`. diff --git a/sources/models/string_impls_for/README.tpl b/sources/models/string_impls_for/README.tpl deleted file mode 100644 index 91fb62910c8..00000000000 --- a/sources/models/string_impls_for/README.tpl +++ /dev/null @@ -1,9 +0,0 @@ -# {{crate}} - -Current version: {{version}} - -{{readme}} - -## Colophon - -This text was generated from `README.tpl` using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/lib.rs`. diff --git a/sources/models/string_impls_for/build.rs b/sources/models/string_impls_for/build.rs deleted file mode 100644 index 42defdba22e..00000000000 --- a/sources/models/string_impls_for/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - generate_readme::from_lib().unwrap(); -} diff --git a/sources/models/string_impls_for/src/lib.rs b/sources/models/string_impls_for/src/lib.rs deleted file mode 100644 index 33c27103661..00000000000 --- a/sources/models/string_impls_for/src/lib.rs +++ /dev/null @@ -1,142 +0,0 @@ -/*! - -A convenience macro for Bottlerocket model types. - -## Description - -The `string_impls_for` is meant to assist in representing string-like types that require additional -validation when deserialized. These types should be modeled as a struct with a single string field -called `inner`. - -The user of the macro implements `TryFrom<&str>`, and the macro will derive implementations for -`TryFrom`, `serde::Deserialize`, `serde::Serialize`, `Deref`, `Borrow`, -`Borrow`, `AsRef`, `Display`, `Into`, `PartialEq`, `PartialEq<&str>`, and -`PartialEq`. - -## Example - -Consider a model which we want to contain a string name for a vegetable, you could implement -something like so: - -``` -use string_impls_for::string_impls_for; - -#[derive(Debug, PartialEq, Eq)] -struct Vegetable { - inner: String, -} - -impl TryFrom<&str> for Vegetable { - type Error = &'static str; - - fn try_from(input: &str) -> std::result::Result { - if !["cucumber", "radish", "leek"].contains(&input) { - return Err("Vegetable name must be one of cucumber, radish, or leek"); - } - Ok(Vegetable { inner: input.to_string() }) - } -} - -string_impls_for!(Vegetable, "Vegetable"); - - -let cucumber = Vegetable::try_from("cucumber").unwrap(); -assert_eq!(cucumber.to_string(), "cucumber"); -``` -!*/ -#[macro_export] -/// Helper macro for implementing the common string-like traits for a modeled type. -/// Pass the name of the type, and the name of the type in quotes (to be used in string error -/// messages, etc.). -macro_rules! string_impls_for { - ($for:ident, $for_str:expr) => { - impl TryFrom for $for { - type Error = >::Error; - - fn try_from(input: String) -> std::result::Result { - Self::try_from(input.as_ref()) - } - } - - impl<'de> serde::Deserialize<'de> for $for { - fn deserialize(deserializer: D) -> std::result::Result - where - D: serde::Deserializer<'de>, - { - let original = String::deserialize(deserializer)?; - Self::try_from(original).map_err(|e| { - ::custom(format!( - "Unable to deserialize into {}: {}", - $for_str, e - )) - }) - } - } - - /// We want to serialize the original string back out, not our structure, which is just there to - /// force validation. - impl serde::Serialize for $for { - fn serialize(&self, serializer: S) -> std::result::Result - where - S: serde::Serializer, - { - serializer.serialize_str(&self.inner) - } - } - - impl std::ops::Deref for $for { - type Target = str; - fn deref(&self) -> &Self::Target { - &self.inner - } - } - - impl std::borrow::Borrow for $for { - fn borrow(&self) -> &String { - &self.inner - } - } - - impl std::borrow::Borrow for $for { - fn borrow(&self) -> &str { - &self.inner - } - } - - impl AsRef for $for { - fn as_ref(&self) -> &str { - &self.inner - } - } - - impl std::fmt::Display for $for { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.inner) - } - } - - impl From<$for> for String { - fn from(x: $for) -> Self { - x.inner - } - } - - impl PartialEq for $for { - fn eq(&self, other: &str) -> bool { - &self.inner == other - } - } - - impl PartialEq for $for { - fn eq(&self, other: &String) -> bool { - &self.inner == other - } - } - - impl PartialEq<&str> for $for { - fn eq(&self, other: &&str) -> bool { - &self.inner == other - } - } - }; -} diff --git a/sources/models/tests/data/mirrors-array b/sources/models/tests/data/mirrors-array deleted file mode 100644 index 030cfe7fc84..00000000000 --- a/sources/models/tests/data/mirrors-array +++ /dev/null @@ -1,7 +0,0 @@ -[[mirrors]] -registry = "*" -endpoint = ["hello"] - -[[mirrors]] -registry = "example" -endpoint = [ "hello", "hellohello"] diff --git a/sources/models/tests/data/mirrors-table b/sources/models/tests/data/mirrors-table deleted file mode 100644 index f922a3c36b3..00000000000 --- a/sources/models/tests/data/mirrors-table +++ /dev/null @@ -1,3 +0,0 @@ -[mirrors] -"*" = ["hello"] -"example" = ["hello", "hellohello"] diff --git a/sources/models/tests/data/node-taint-empty-list b/sources/models/tests/data/node-taint-empty-list deleted file mode 100644 index 592b2131d8a..00000000000 --- a/sources/models/tests/data/node-taint-empty-list +++ /dev/null @@ -1,2 +0,0 @@ -[node-taints] -"key1" = [] diff --git a/sources/models/tests/data/node-taint-list-val b/sources/models/tests/data/node-taint-list-val deleted file mode 100644 index 9f401a0e729..00000000000 --- a/sources/models/tests/data/node-taint-list-val +++ /dev/null @@ -1,3 +0,0 @@ -[node-taints] -"key1" = ["value1:NoSchedule","value1:NoExecute"] -"key2" = "value2:NoSchedule" diff --git a/sources/models/tests/data/node-taint-single-val b/sources/models/tests/data/node-taint-single-val deleted file mode 100644 index 21cbf8a66ce..00000000000 --- a/sources/models/tests/data/node-taint-single-val +++ /dev/null @@ -1,3 +0,0 @@ -[node-taints] -"key1" = "value1:NoSchedule" -"key2" = "value2:NoExecute" diff --git a/sources/models/tests/data/test-incomplete-pem b/sources/models/tests/data/test-incomplete-pem deleted file mode 100644 index 654f8b97757..00000000000 --- a/sources/models/tests/data/test-incomplete-pem +++ /dev/null @@ -1 +0,0 @@ -LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURVekNDQWp1Z0F3SUJBZ0lVQWE3RTNJYTVzOXFaYnJhMmdtM005OTk0K1JNd0RRWUpLb1pJaHZjTkFRRUwKQlFBd09URVZNQk1HQTFVRUF3d01ZbTkwZEd4bGNtOWphMlYwTVFzd0NRWURWUVFHRXdKVlV6RVRNQkVHQTFVRQpCd3dLVjBGVFNFbE9SMVJQVGpBZUZ3MHlNVEEzTVRRd01UTTFNemRhRncweU5qQTNNVE13TVRNMU16ZGFNRGt4CkZUQVRCZ05WQkFNTURHSnZkSFJzWlhKdlkydGxkREVMTUFrR0ExVUVCaE1DVlZNeEV6QVJCZ05WQkFjTUNsZEIKVTBoSlRrZFVUMDR3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRRGgrV01OaWRxYQpYbE1ZZ1dxUVpnKzV1RTlCL21qYS9JSXpHclk1c0RQbDNLRm1qR0srUlpYS2FuZ2FIY3lWcTUvMkdlcEthcThOCmlSYTNsejRUY1JWRzJkUkxkR2RJVlBCVlg4Z1h3NngvcFg3TDkyN0dsam5naGR5VGYyWnBUYjNScU1odTdEZTUKaGVsdkRyVnU3TVFER0d3VnVBWU03cnBrM09hNitpeEJGTHN2MmwwK01xRkZwKzF6TGo4VFVmNXhoa0pjTnQ0NgpBeCt6S1FIeWxoQ2tkQmt5VTNVUzJhRXllSndMRURZcUt4SWcvdERFdDNpUWRVV3M4dmJFRkJBU2JOZWtxYjJ5ClNLSFNpNWEzMWhlYWNheWpRSnZ5dUt5YnNEWkdBdnVRVVdOTXY0N1FRcXA2UUU2bklkQ0lpQkVaQkM4OUdpaHYKUWg0ditYR3d0dDhOQWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJSUDJleHJmRHg2M083cHh5NVZwaTBFRTNjMgpMREFmQmdOVkhTTUVHREFXZ0JSUDJleHJmRHg2M083cHh5NVZwaTBFRTNjMkxEQVBCZ05WSFJNQkFmOEVCVEFECkFRSC9NQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUE5akhsUW4xZ0dnUmtRejJ5VkNYdGRNbDYzRzBYQUxFcncKNXp3VFcyMjZnbzBBYSs4TTdBQ2Y5c05rRE5uZ1cxYjFKbnJuWWs2QTY5WEsyaEtiMm13QVgzaDdpaHh2alZJcgoxZGtrbkxpYStpODQ5ODVQeGpEZW5kUXBqZS9JUWhkZXMyTy9uVDJFQ2VVb200MzF1OXpreHdYSFd2L0pjL0xlCmhvYklEZ3BySW1PQjhoR3ZOaUh1WmZwZjVJdXV3Um9MMHJXdjBDOWZlYTNlRUtBajVNYUN3dGJyYlViSGd1dTIKNVhhQjMrL284V3NwZ3hvTHE0VEwxa2JTRTJlSHFDb2ZvUmw4RURTdjhKR2FvR20rMTIvVDArWjdxL1RhNG8rLwp3VldzTkY3aUdwbUt1SnFLWnZKVy9QZTM0SzZ0U1YzdlpRNkdzTHhKUFFiQlBsN1hEZXdLCg== \ No newline at end of file diff --git a/sources/models/tests/data/test-pem b/sources/models/tests/data/test-pem deleted file mode 100644 index 2e2d530e5cc..00000000000 --- a/sources/models/tests/data/test-pem +++ /dev/null @@ -1 +0,0 @@ -LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURVekNDQWp1Z0F3SUJBZ0lVVUNBbXU1MWU1NDZIakpGVEd6Z1BpS2ZxZXVVd0RRWUpLb1pJaHZjTkFRRUwKQlFBd09URVZNQk1HQTFVRUF3d01ZbTkwZEd4bGNtOWphMlYwTVFzd0NRWURWUVFHRXdKVlV6RVRNQkVHQTFVRQpCd3dLVjBGVFNFbE9SMVJQVGpBZUZ3MHlNVEEzTURjeU1UQXhNekJhRncweU5qQTNNRFl5TVRBeE16QmFNRGt4CkZUQVRCZ05WQkFNTURHSnZkSFJzWlhKdlkydGxkREVMTUFrR0ExVUVCaE1DVlZNeEV6QVJCZ05WQkFjTUNsZEIKVTBoSlRrZFVUMDR3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQzErSk5MbllIeApyeGowOTJsQUpwOGRwRlRYbTVpR25jZFRubjBwem1OLzByMWhXUWNLSU9JY1UwcUdlN1h0UkVMcUFPQW5Gb3ZqCktaREV5SjB4eU9TZ1k4NFF6MVdXbUtqSHVsMGZXRHJ0RWlFNU03UklwVXBlVjZwejhOclRoOUFiSEZ1UWFMMkoKWk1COHVRWnFWRUhFZFl0THpFaHhnTU9NMUtjaXVqcjczWVE5TElLYVA3aW5sMU14YWd4c1Y4cjYyZG9WR3g2UwpsT2l3WXVQdmdkNnZWamQ5Wjl1UU5KNHFUdzBVVjBMbGJ1bXZwN2NITHg3U0EzWU55elZBWG0xb2FKYmhKeWpNClJmZEFwZDB3dkc0T1RXd2d5d240N2JPc0pBK3BJMDY0ZlNEeEpIaWxtdGVCSVRmV3hpQ1k2dkFvc01kVHJtRWwKUEFxYzVuem1WRkI3QWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJRZlFJYWh1cFRFMUdaeFBicnhYS3RoVitzTwovekFmQmdOVkhTTUVHREFXZ0JRZlFJYWh1cFRFMUdaeFBicnhYS3RoVitzTy96QVBCZ05WSFJNQkFmOEVCVEFECkFRSC9NQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUFrc1BrNlhMTG5CdVRYK0xtYWJyK0VzcnNOQ2RBYitkOXkKc3Rpc2RDanBrbUtDc2VzSjk2UWdpMDYvMU04OHUvcCtHZHAreEhMUElKVUxyR2owMWoxdXJtRWJxd2lmeFVtawpmSkZ6bW00ZU56UVpqV1gyQm5HOVA4eHlHT1NWaWVHb1RFZW13MlBNT1hodUVFc0o5ckNQSXdzdlhMRzhOQW8yCnNjOGxaNXlOVnZkaHdwemdZL3lvM2pNKzJWeXZ4K2FnTXNhRGs3YmhjOTJGc3ZieTZ2a3ZweC82THZLSGFvSmgKbmxGcUwxcWZEZGZjOU81d1ZqeURyK3Q2NVBlVy9JN2ZCeXpZTEtyMDhIM3JCTzRQRXh0aVJrUHBJcGtEVWNnUAo3eTB6SGd6eVc5dHZNVlBXdXRDTDJ3UE1jb0hpdXJrRnNoOERtQzdzUytMMlNKTG1wbDJoCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KYmFkCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlEVXpDQ0FqdWdBd0lCQWdJVVVDQW11NTFlNTQ2SGpKRlRHemdQaUtmcWV1VXdEUVlKS29aSWh2Y05BUUVMCkJRQXdPVEVWTUJNR0ExVUVBd3dNWW05MGRHeGxjbTlqYTJWME1Rc3dDUVlEVlFRR0V3SlZVekVUTUJFR0ExVUUKQnd3S1YwRlRTRWxPUjFSUFRqQWVGdzB5TVRBM01EY3lNVEF4TXpCYUZ3MHlOakEzTURZeU1UQXhNekJhTURreApGVEFUQmdOVkJBTU1ER0p2ZEhSc1pYSnZZMnRsZERFTE1Ba0dBMVVFQmhNQ1ZWTXhFekFSQmdOVkJBY01DbGRCClUwaEpUa2RVVDA0d2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUUMxK0pOTG5ZSHgKcnhqMDkybEFKcDhkcEZUWG01aUduY2RUbm4wcHptTi8wcjFoV1FjS0lPSWNVMHFHZTdYdFJFTHFBT0FuRm92agpLWkRFeUoweHlPU2dZODRRejFXV21Lakh1bDBmV0RydEVpRTVNN1JJcFVwZVY2cHo4TnJUaDlBYkhGdVFhTDJKClpNQjh1UVpxVkVIRWRZdEx6RWh4Z01PTTFLY2l1anI3M1lROUxJS2FQN2lubDFNeGFneHNWOHI2MmRvVkd4NlMKbE9pd1l1UHZnZDZ2VmpkOVo5dVFOSjRxVHcwVVYwTGxidW12cDdjSEx4N1NBM1lOeXpWQVhtMW9hSmJoSnlqTQpSZmRBcGQwd3ZHNE9UV3dneXduNDdiT3NKQStwSTA2NGZTRHhKSGlsbXRlQklUZld4aUNZNnZBb3NNZFRybUVsClBBcWM1bnptVkZCN0FnTUJBQUdqVXpCUk1CMEdBMVVkRGdRV0JCUWZRSWFodXBURTFHWnhQYnJ4WEt0aFYrc08KL3pBZkJnTlZIU01FR0RBV2dCUWZRSWFodXBURTFHWnhQYnJ4WEt0aFYrc08vekFQQmdOVkhSTUJBZjhFQlRBRApBUUgvTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFBa3NQazZYTExuQnVUWCtMbWFicitFc3JzTkNkQWIrZDl5CnN0aXNkQ2pwa21LQ3Nlc0o5NlFnaTA2LzFNODh1L3ArR2RwK3hITFBJSlVMckdqMDFqMXVybUVicXdpZnhVbWsKZkpGem1tNGVOelFaaldYMkJuRzlQOHh5R09TVmllR29URWVtdzJQTU9YaHVFRXNKOXJDUEl3c3ZYTEc4TkFvMgpzYzhsWjV5TlZ2ZGh3cHpnWS95bzNqTSsyVnl2eCthZ01zYURrN2JoYzkyRnN2Ynk2dmt2cHgvNkx2S0hhb0poCm5sRnFMMXFmRGRmYzlPNXdWanlEcit0NjVQZVcvSTdmQnl6WUxLcjA4SDNyQk80UEV4dGlSa1BwSXBrRFVjZ1AKN3kwekhnenlXOXR2TVZQV3V0Q0wyd1BNY29IaXVya0ZzaDhEbUM3c1MrTDJTSkxtcGwyaAotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== \ No newline at end of file diff --git a/sources/settings-extensions/autoscaling/Cargo.toml b/sources/settings-extensions/autoscaling/Cargo.toml deleted file mode 100644 index 242d048795a..00000000000 --- a/sources/settings-extensions/autoscaling/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "settings-extension-autoscaling" -version = "0.1.0" -authors = ["Gaurav Sharma "] -license = "Apache-2.0 OR MIT" -edition = "2021" -publish = false - -[dependencies] -env_logger = "0.10" -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -model-derive = { path = "../../models/model-derive", version = "0.1" } -serde = { version = "1", features = ["derive"] } -serde_json = "1" - -[dependencies.bottlerocket-settings-sdk] -git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" -tag = "bottlerocket-settings-sdk-v0.1.0" -version = "0.1.0" diff --git a/sources/settings-extensions/autoscaling/autoscaling.toml b/sources/settings-extensions/autoscaling/autoscaling.toml deleted file mode 100644 index 727dfb274cd..00000000000 --- a/sources/settings-extensions/autoscaling/autoscaling.toml +++ /dev/null @@ -1,13 +0,0 @@ -[extension] -supported-versions = [ - "v1" -] -default-version = "v1" - -[v1] -[v1.validation.cross-validates] - -[v1.templating] -helpers = [] - -[v1.generation.requires] diff --git a/sources/settings-extensions/autoscaling/src/lib.rs b/sources/settings-extensions/autoscaling/src/lib.rs deleted file mode 100644 index e1f8c390c25..00000000000 --- a/sources/settings-extensions/autoscaling/src/lib.rs +++ /dev/null @@ -1,68 +0,0 @@ -/// Settings related to auto scaling groups. -use bottlerocket_settings_sdk::{GenerateResult, SettingsModel}; -use model_derive::model; -use std::convert::Infallible; - -#[model(impl_default = true)] -pub struct AutoScalingSettingsV1 { - should_wait: bool, -} - -type Result = std::result::Result; - -impl SettingsModel for AutoScalingSettingsV1 { - type PartialKind = Self; - type ErrorKind = Infallible; - - fn get_version() -> &'static str { - "v1" - } - - fn set(_current_value: Option, _target: Self) -> Result<()> { - // Set anything that can be parsed as AutoScalingSettingsV1. - Ok(()) - } - - fn generate( - existing_partial: Option, - _dependent_settings: Option, - ) -> Result> { - Ok(GenerateResult::Complete( - existing_partial.unwrap_or_default(), - )) - } - - fn validate(_value: Self, _validated_settings: Option) -> Result<()> { - // AutoScalingSettingsV1 is validated during deserialization. - Ok(()) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_generate_autoscaling() { - assert_eq!( - AutoScalingSettingsV1::generate(None, None).unwrap(), - GenerateResult::Complete(AutoScalingSettingsV1 { should_wait: None }) - ) - } - - #[test] - fn test_serde_autoscaling() { - let test_json = r#"{"should-wait":true}"#; - - let autoscaling: AutoScalingSettingsV1 = serde_json::from_str(test_json).unwrap(); - assert_eq!( - autoscaling, - AutoScalingSettingsV1 { - should_wait: Some(true), - } - ); - - let results = serde_json::to_string(&autoscaling).unwrap(); - assert_eq!(results, test_json); - } -} diff --git a/sources/settings-extensions/autoscaling/src/main.rs b/sources/settings-extensions/autoscaling/src/main.rs deleted file mode 100644 index 9c11c03a40f..00000000000 --- a/sources/settings-extensions/autoscaling/src/main.rs +++ /dev/null @@ -1,18 +0,0 @@ -use bottlerocket_settings_sdk::{BottlerocketSetting, NullMigratorExtensionBuilder}; -use settings_extension_autoscaling::AutoScalingSettingsV1; -use std::process::ExitCode; - -fn main() -> ExitCode { - env_logger::init(); - - match NullMigratorExtensionBuilder::with_name("autoscaling") - .with_models(vec![BottlerocketSetting::::model()]) - .build() - { - Ok(extension) => extension.run(), - Err(e) => { - println!("{}", e); - ExitCode::FAILURE - } - } -} diff --git a/sources/settings-extensions/aws/Cargo.toml b/sources/settings-extensions/aws/Cargo.toml deleted file mode 100644 index 4f08a80008f..00000000000 --- a/sources/settings-extensions/aws/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "settings-extension-aws" -version = "0.1.0" -authors = ["Sam Berning "] -edition = "2021" -license = "Apache-2.0 OR MIT" -publish = false - -[dependencies] -env_logger = "0.10" -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -model-derive = { path = "../../models/model-derive", version = "0.1" } -serde = { version = "1", features = ["derive"] } -serde_json = "1" - -[dependencies.bottlerocket-settings-sdk] -git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" -tag = "bottlerocket-settings-sdk-v0.1.0" -version = "0.1.0" diff --git a/sources/settings-extensions/aws/aws.toml b/sources/settings-extensions/aws/aws.toml deleted file mode 100644 index 727dfb274cd..00000000000 --- a/sources/settings-extensions/aws/aws.toml +++ /dev/null @@ -1,13 +0,0 @@ -[extension] -supported-versions = [ - "v1" -] -default-version = "v1" - -[v1] -[v1.validation.cross-validates] - -[v1.templating] -helpers = [] - -[v1.generation.requires] diff --git a/sources/settings-extensions/aws/src/lib.rs b/sources/settings-extensions/aws/src/lib.rs deleted file mode 100644 index 08de279ea66..00000000000 --- a/sources/settings-extensions/aws/src/lib.rs +++ /dev/null @@ -1,84 +0,0 @@ -/// The aws settings can be used to configure settings related to AWS -use bottlerocket_settings_sdk::{GenerateResult, SettingsModel}; -use model_derive::model; -use modeled_types::{SingleLineString, ValidBase64}; -use std::convert::Infallible; - -// Platform-specific settings -#[model(impl_default = true)] -pub struct AwsSettingsV1 { - region: SingleLineString, - config: ValidBase64, - credentials: ValidBase64, - profile: SingleLineString, -} - -type Result = std::result::Result; - -impl SettingsModel for AwsSettingsV1 { - type PartialKind = Self; - type ErrorKind = Infallible; - - fn get_version() -> &'static str { - "v1" - } - - fn set(_current_value: Option, _target: Self) -> Result<()> { - // allow anything that parses as AwsSettingsV1 - Ok(()) - } - - fn generate( - existing_partial: Option, - _dependent_settings: Option, - ) -> Result> { - Ok(GenerateResult::Complete( - existing_partial.unwrap_or_default(), - )) - } - - fn validate(_value: Self, _validated_settings: Option) -> Result<()> { - Ok(()) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_generate_aws() { - let generated = AwsSettingsV1::generate(None, None).unwrap(); - assert_eq!( - generated, - GenerateResult::Complete(AwsSettingsV1 { - region: None, - config: None, - credentials: None, - profile: None, - }) - ) - } - - #[test] - fn test_serde_aws() { - let test_json = r#"{ - "region": "us-east-1", - "config": "Zm9vCg==", - "credentials": "Zm9vCg==", - "profile": "foo" - }"#; - - let aws: AwsSettingsV1 = serde_json::from_str(test_json).unwrap(); - - assert_eq!( - aws, - AwsSettingsV1 { - region: Some(SingleLineString::try_from("us-east-1").unwrap()), - config: Some(ValidBase64::try_from("Zm9vCg==").unwrap()), - credentials: Some(ValidBase64::try_from("Zm9vCg==").unwrap()), - profile: Some(SingleLineString::try_from("foo").unwrap()), - } - ); - } -} diff --git a/sources/settings-extensions/aws/src/main.rs b/sources/settings-extensions/aws/src/main.rs deleted file mode 100644 index 4786981b5bb..00000000000 --- a/sources/settings-extensions/aws/src/main.rs +++ /dev/null @@ -1,18 +0,0 @@ -use bottlerocket_settings_sdk::{BottlerocketSetting, NullMigratorExtensionBuilder}; -use settings_extension_aws::AwsSettingsV1; -use std::process::ExitCode; - -fn main() -> ExitCode { - env_logger::init(); - - match NullMigratorExtensionBuilder::with_name("aws") - .with_models(vec![BottlerocketSetting::::model()]) - .build() - { - Ok(extension) => extension.run(), - Err(e) => { - println!("{}", e); - ExitCode::FAILURE - } - } -} diff --git a/sources/settings-extensions/bootstrap-containers/Cargo.toml b/sources/settings-extensions/bootstrap-containers/Cargo.toml deleted file mode 100644 index 860f2142e33..00000000000 --- a/sources/settings-extensions/bootstrap-containers/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "settings-extension-bootstrap-containers" -version = "0.1.0" -authors = ["Gaurav Sharma "] -license = "Apache-2.0 OR MIT" -edition = "2021" -publish = false - -[dependencies] -env_logger = "0.10" -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -model-derive = { path = "../../models/model-derive", version = "0.1" } -serde = { version = "1", features = ["derive"] } -serde_json = "1" - -[dependencies.bottlerocket-settings-sdk] -git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" -tag = "bottlerocket-settings-sdk-v0.1.0" -version = "0.1.0" diff --git a/sources/settings-extensions/bootstrap-containers/bootstrap-containers.toml b/sources/settings-extensions/bootstrap-containers/bootstrap-containers.toml deleted file mode 100644 index 727dfb274cd..00000000000 --- a/sources/settings-extensions/bootstrap-containers/bootstrap-containers.toml +++ /dev/null @@ -1,13 +0,0 @@ -[extension] -supported-versions = [ - "v1" -] -default-version = "v1" - -[v1] -[v1.validation.cross-validates] - -[v1.templating] -helpers = [] - -[v1.generation.requires] diff --git a/sources/settings-extensions/bootstrap-containers/src/lib.rs b/sources/settings-extensions/bootstrap-containers/src/lib.rs deleted file mode 100644 index 6d432a3a99d..00000000000 --- a/sources/settings-extensions/bootstrap-containers/src/lib.rs +++ /dev/null @@ -1,137 +0,0 @@ -/// Settings related to bootstrap containers. -use bottlerocket_settings_sdk::{GenerateResult, SettingsModel}; -use model_derive::model; -use modeled_types::{BootstrapContainerMode, Identifier, Url, ValidBase64}; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use std::{collections::HashMap, convert::Infallible}; - -#[derive(Clone, Debug, Default, PartialEq)] -pub struct BootstrapContainersSettingsV1 { - pub bootstrap_containers: HashMap, -} - -// Custom serializer/deserializer added to maintain backwards -// compatibility with models created prior to settings extensions. -impl Serialize for BootstrapContainersSettingsV1 { - fn serialize(&self, serializer: S) -> std::result::Result - where - S: Serializer, - { - self.bootstrap_containers.serialize(serializer) - } -} - -impl<'de> Deserialize<'de> for BootstrapContainersSettingsV1 { - fn deserialize(deserializer: D) -> std::result::Result - where - D: Deserializer<'de>, - { - let bootstrap_containers = HashMap::deserialize(deserializer)?; - Ok(Self { - bootstrap_containers, - }) - } -} - -#[model(impl_default = true)] -struct BootstrapContainer { - source: Url, - mode: BootstrapContainerMode, - user_data: ValidBase64, - essential: bool, -} - -type Result = std::result::Result; - -impl SettingsModel for BootstrapContainersSettingsV1 { - type PartialKind = Self; - type ErrorKind = Infallible; - - fn get_version() -> &'static str { - "v1" - } - - fn set(_current_value: Option, _target: Self) -> Result<()> { - // Set anything that parses as BootstrapContainersSettingsV1. - Ok(()) - } - - fn generate( - existing_partial: Option, - _dependent_settings: Option, - ) -> Result> { - Ok(GenerateResult::Complete( - existing_partial.unwrap_or_default(), - )) - } - - fn validate(_value: Self, _validated_settings: Option) -> Result<()> { - // Validate anything that parses as BootstrapContainersSettingsV1. - Ok(()) - } -} - -#[cfg(test)] -mod test { - use super::*; - use serde_json::json; - - #[test] - fn test_generate_bootstrap_container_settings() { - let generated = BootstrapContainersSettingsV1::generate(None, None).unwrap(); - - assert_eq!( - generated, - GenerateResult::Complete(BootstrapContainersSettingsV1 { - bootstrap_containers: HashMap::new(), - }) - ) - } - - #[test] - fn test_serde_bootstrap_container() { - let test_json = json!({ - "mybootstrap": { - "source": "uri.to.container.in.oci-compatible-registry.example.com/foo:1.0.0", - "mode": "once", - "user-data": "dXNlcmRhdGE=", - "essential": true, - } - }); - - let test_json_str = test_json.to_string(); - - let bootstrap_containers: BootstrapContainersSettingsV1 = - serde_json::from_str(&test_json_str).unwrap(); - - let mut expected_bootstrap_container: HashMap = - HashMap::new(); - expected_bootstrap_container.insert( - Identifier::try_from("mybootstrap").unwrap(), - BootstrapContainer { - source: Some( - Url::try_from( - "uri.to.container.in.oci-compatible-registry.example.com/foo:1.0.0", - ) - .unwrap(), - ), - mode: Some(BootstrapContainerMode::try_from("once").unwrap()), - user_data: Some(ValidBase64::try_from("dXNlcmRhdGE=").unwrap()), - essential: Some(true), - }, - ); - - assert_eq!( - bootstrap_containers, - BootstrapContainersSettingsV1 { - bootstrap_containers: expected_bootstrap_container - } - ); - - let serialized_json: serde_json::Value = serde_json::to_string(&bootstrap_containers) - .map(|s| serde_json::from_str(&s).unwrap()) - .unwrap(); - - assert_eq!(serialized_json, test_json); - } -} diff --git a/sources/settings-extensions/bootstrap-containers/src/main.rs b/sources/settings-extensions/bootstrap-containers/src/main.rs deleted file mode 100644 index a85c55128b4..00000000000 --- a/sources/settings-extensions/bootstrap-containers/src/main.rs +++ /dev/null @@ -1,20 +0,0 @@ -use bottlerocket_settings_sdk::{BottlerocketSetting, NullMigratorExtensionBuilder}; -use settings_extension_bootstrap_containers::BootstrapContainersSettingsV1; -use std::process::ExitCode; - -fn main() -> ExitCode { - env_logger::init(); - - match NullMigratorExtensionBuilder::with_name("bootstrap-containers") - .with_models(vec![ - BottlerocketSetting::::model(), - ]) - .build() - { - Ok(extension) => extension.run(), - Err(e) => { - println!("{}", e); - ExitCode::FAILURE - } - } -} diff --git a/sources/settings-extensions/cloudformation/Cargo.toml b/sources/settings-extensions/cloudformation/Cargo.toml deleted file mode 100644 index 2dba2e0acd7..00000000000 --- a/sources/settings-extensions/cloudformation/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "settings-extension-cloudformation" -version = "0.1.0" -authors = ["Gaurav Sharma "] -license = "Apache-2.0 OR MIT" -edition = "2021" -publish = false - -[dependencies] -env_logger = "0.10" -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -model-derive = { path = "../../models/model-derive", version = "0.1" } -serde = { version = "1", features = ["derive"] } -serde_json = "1" - -[dependencies.bottlerocket-settings-sdk] -git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" -tag = "bottlerocket-settings-sdk-v0.1.0" -version = "0.1.0" diff --git a/sources/settings-extensions/cloudformation/cloudformation.toml b/sources/settings-extensions/cloudformation/cloudformation.toml deleted file mode 100644 index 727dfb274cd..00000000000 --- a/sources/settings-extensions/cloudformation/cloudformation.toml +++ /dev/null @@ -1,13 +0,0 @@ -[extension] -supported-versions = [ - "v1" -] -default-version = "v1" - -[v1] -[v1.validation.cross-validates] - -[v1.templating] -helpers = [] - -[v1.generation.requires] diff --git a/sources/settings-extensions/cloudformation/src/lib.rs b/sources/settings-extensions/cloudformation/src/lib.rs deleted file mode 100644 index 2ebab691804..00000000000 --- a/sources/settings-extensions/cloudformation/src/lib.rs +++ /dev/null @@ -1,89 +0,0 @@ -///Settings related to CloudFormation signaling -use bottlerocket_settings_sdk::{GenerateResult, SettingsModel}; -use model_derive::model; -use modeled_types::SingleLineString; -use std::convert::Infallible; - -#[model(impl_default = true)] -pub struct CloudFormationSettingsV1 { - should_signal: bool, - stack_name: SingleLineString, - logical_resource_id: SingleLineString, -} - -type Result = std::result::Result; - -impl SettingsModel for CloudFormationSettingsV1 { - type PartialKind = Self; - type ErrorKind = Infallible; - - fn get_version() -> &'static str { - "v1" - } - - fn set(_current_value: Option, _target: Self) -> Result<()> { - // Set anything that can be parsed as CloudFormationSettingsV1. - Ok(()) - } - - fn generate( - existing_partial: Option, - _dependent_settings: Option, - ) -> Result> { - Ok(GenerateResult::Complete( - existing_partial.unwrap_or_default(), - )) - } - - fn validate(_value: Self, _validated_settings: Option) -> Result<()> { - // CloudFormationSettingsV1 is validated during deserialization. - Ok(()) - } -} - -#[cfg(test)] -mod test { - use super::*; - use serde_json::json; - - #[test] - fn test_generate_cloudformation_settings() { - assert_eq!( - CloudFormationSettingsV1::generate(None, None), - Ok(GenerateResult::Complete(CloudFormationSettingsV1 { - should_signal: None, - stack_name: None, - logical_resource_id: None, - })) - ) - } - - #[test] - fn test_serde_cloudformation() { - let test_json = json!({ - "logical-resource-id": "MyEC2Instance", - "should-signal":true, - "stack-name":"MyStack" - }); - - let test_json_str = test_json.to_string(); - - let cloudformation_settings: CloudFormationSettingsV1 = - serde_json::from_str(&test_json_str).unwrap(); - - assert_eq!( - cloudformation_settings, - CloudFormationSettingsV1 { - logical_resource_id: Some(SingleLineString::try_from("MyEC2Instance").unwrap()), - should_signal: Some(true), - stack_name: Some(SingleLineString::try_from("MyStack").unwrap()) - } - ); - - let serialized_json: serde_json::Value = serde_json::to_string(&cloudformation_settings) - .map(|s| serde_json::from_str(&s).unwrap()) - .unwrap(); - - assert_eq!(serialized_json, test_json); - } -} diff --git a/sources/settings-extensions/cloudformation/src/main.rs b/sources/settings-extensions/cloudformation/src/main.rs deleted file mode 100644 index f6aaaa1788f..00000000000 --- a/sources/settings-extensions/cloudformation/src/main.rs +++ /dev/null @@ -1,20 +0,0 @@ -use bottlerocket_settings_sdk::{BottlerocketSetting, NullMigratorExtensionBuilder}; -use settings_extension_cloudformation::CloudFormationSettingsV1; -use std::process::ExitCode; - -fn main() -> ExitCode { - env_logger::init(); - - match NullMigratorExtensionBuilder::with_name("cloudformation") - .with_models(vec![ - BottlerocketSetting::::model(), - ]) - .build() - { - Ok(extension) => extension.run(), - Err(e) => { - println!("{}", e); - ExitCode::FAILURE - } - } -} diff --git a/sources/settings-extensions/container-registry/Cargo.toml b/sources/settings-extensions/container-registry/Cargo.toml deleted file mode 100644 index c7b86218b51..00000000000 --- a/sources/settings-extensions/container-registry/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "settings-extension-container-registry" -version = "0.1.0" -authors = ["Sam Berning "] -license = "Apache-2.0 OR MIT" -edition = "2021" -publish = false - -[dependencies] -env_logger = "0.10" -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -model-derive = { path = "../../models/model-derive", version = "0.1" } -serde = { version = "1", features = ["derive"] } -serde_json = "1" - -[dependencies.bottlerocket-settings-sdk] -git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" -tag = "bottlerocket-settings-sdk-v0.1.0" -version = "0.1.0" diff --git a/sources/settings-extensions/container-registry/container-registry.toml b/sources/settings-extensions/container-registry/container-registry.toml deleted file mode 100644 index 727dfb274cd..00000000000 --- a/sources/settings-extensions/container-registry/container-registry.toml +++ /dev/null @@ -1,13 +0,0 @@ -[extension] -supported-versions = [ - "v1" -] -default-version = "v1" - -[v1] -[v1.validation.cross-validates] - -[v1.templating] -helpers = [] - -[v1.generation.requires] diff --git a/sources/settings-extensions/container-registry/src/de.rs b/sources/settings-extensions/container-registry/src/de.rs deleted file mode 100644 index 8be4dd3ed18..00000000000 --- a/sources/settings-extensions/container-registry/src/de.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::RegistryMirrorV1; -use serde::de::value::SeqAccessDeserializer; -use serde::de::{MapAccess, SeqAccess, Visitor}; -use serde::{Deserialize, Deserializer}; -use std::fmt::Formatter; - -// Our standard representation of registry mirrors is a `Vec` of `RegistryMirror`; for backward compatibility, we also allow a `HashMap` of registry to endpoints. -pub(crate) fn deserialize_mirrors<'de, D>( - deserializer: D, -) -> Result>, D::Error> -where - D: Deserializer<'de>, -{ - struct TableOrArray; - - impl<'de> Visitor<'de> for TableOrArray { - type Value = Option>; - - fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { - formatter.write_str("TOML array or TOML table") - } - - fn visit_seq(self, seq: A) -> Result - where - A: SeqAccess<'de>, - { - Ok(Some(Deserialize::deserialize(SeqAccessDeserializer::new( - seq, - ))?)) - } - - fn visit_map(self, mut map: M) -> Result - where - M: MapAccess<'de>, - { - let mut vec = Vec::new(); - while let Some((k, v)) = map.next_entry()? { - vec.push(RegistryMirrorV1 { - registry: Some(k), - endpoint: Some(v), - }); - } - Ok(Some(vec)) - } - } - deserializer.deserialize_any(TableOrArray) -} diff --git a/sources/settings-extensions/container-registry/src/lib.rs b/sources/settings-extensions/container-registry/src/lib.rs deleted file mode 100644 index 5d648312752..00000000000 --- a/sources/settings-extensions/container-registry/src/lib.rs +++ /dev/null @@ -1,129 +0,0 @@ -/// The container-registry settings can be used to configure settings related to container -/// registries, including credentials for logging into a registry, or mirrors to use when -/// pulling from a registry. -mod de; - -use crate::de::deserialize_mirrors; -use bottlerocket_settings_sdk::{GenerateResult, SettingsModel}; -use model_derive::model; -use modeled_types::{SingleLineString, Url, ValidBase64}; -use std::convert::Infallible; - -#[model(impl_default = true)] -struct RegistryMirrorV1 { - registry: SingleLineString, - endpoint: Vec, -} - -#[model(impl_default = true)] -struct RegistryCredentialV1 { - registry: SingleLineString, - username: SingleLineString, - password: SingleLineString, - // This is the base64 encoding of "username:password" - auth: ValidBase64, - identitytoken: SingleLineString, -} - -#[model(impl_default = true)] -struct RegistrySettingsV1 { - #[serde( - default, - skip_serializing_if = "Option::is_none", - deserialize_with = "deserialize_mirrors" - )] - mirrors: Vec, - #[serde(alias = "creds", default, skip_serializing_if = "Option::is_none")] - credentials: Vec, -} - -type Result = std::result::Result; - -impl SettingsModel for RegistrySettingsV1 { - type PartialKind = Self; - type ErrorKind = Infallible; - - fn get_version() -> &'static str { - "v1" - } - - fn set( - _current_value: Option, - _target: Self, - ) -> std::result::Result<(), Self::ErrorKind> { - // Anything that correctly deserializes to RegistrySettingsV1 is ok - Ok(()) - } - - fn generate( - existing_partial: Option, - _dependent_settings: Option, - ) -> Result> { - Ok(GenerateResult::Complete( - existing_partial.unwrap_or_default(), - )) - } - - fn validate( - _value: Self, - _validated_settings: Option, - ) -> std::result::Result<(), Self::ErrorKind> { - Ok(()) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_generate_container_registry_settings() { - assert_eq!( - RegistrySettingsV1::generate(None, None), - Ok(GenerateResult::Complete(RegistrySettingsV1 { - mirrors: None, - credentials: None, - })) - ) - } - - #[test] - fn test_serde_container_registry_with_mirrors() { - let test_json = - r#"{"mirrors": [{"registry": "foo", "endpoint": ["https://example.net"]}]}"#; - - let container_registry: RegistrySettingsV1 = serde_json::from_str(test_json).unwrap(); - let mirrors = container_registry.mirrors.unwrap(); - - assert_eq!(mirrors.len(), 1); - assert_eq!( - mirrors[0].registry.clone().unwrap(), - SingleLineString::try_from("foo").unwrap(), - ); - assert_eq!( - mirrors[0].endpoint.clone().unwrap(), - vec!(Url::try_from("https://example.net").unwrap()), - ); - } - - #[test] - fn test_serde_container_registry_with_credentials() { - let test_json = r#"{"credentials": [{"registry": "foo", "auth": "Ym90dGxlcm9ja2V0"}]}"#; - - let container_registry: RegistrySettingsV1 = serde_json::from_str(test_json).unwrap(); - let credentials = container_registry.credentials.unwrap(); - - assert_eq!(credentials.len(), 1); - assert_eq!( - credentials[0].registry.clone().unwrap(), - SingleLineString::try_from("foo").unwrap(), - ); - assert_eq!( - credentials[0].auth.clone().unwrap(), - ValidBase64::try_from("Ym90dGxlcm9ja2V0").unwrap(), - ); - assert!(credentials[0].username.is_none()); - assert!(credentials[0].password.is_none()); - assert!(credentials[0].identitytoken.is_none()); - } -} diff --git a/sources/settings-extensions/container-registry/src/main.rs b/sources/settings-extensions/container-registry/src/main.rs deleted file mode 100644 index 84801723d3c..00000000000 --- a/sources/settings-extensions/container-registry/src/main.rs +++ /dev/null @@ -1,18 +0,0 @@ -use bottlerocket_settings_sdk::{BottlerocketSetting, NullMigratorExtensionBuilder}; -use settings_extension_container_registry::RegistrySettingsV1; -use std::process::ExitCode; - -fn main() -> ExitCode { - env_logger::init(); - - match NullMigratorExtensionBuilder::with_name("container-registry") - .with_models(vec![BottlerocketSetting::::model()]) - .build() - { - Ok(extension) => extension.run(), - Err(e) => { - println!("{}", e); - ExitCode::FAILURE - } - } -} diff --git a/sources/settings-extensions/container-runtime/Cargo.toml b/sources/settings-extensions/container-runtime/Cargo.toml deleted file mode 100644 index bacc9deda13..00000000000 --- a/sources/settings-extensions/container-runtime/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "settings-extension-container-runtime" -version = "0.1.0" -authors = ["Gaurav Sharma "] -license = "Apache-2.0 OR MIT" -edition = "2021" -publish = false - -[dependencies] -env_logger = "0.10" -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -model-derive = { path = "../../models/model-derive", version = "0.1" } -serde = { version = "1", features = ["derive"] } -serde_json = "1" - -[dependencies.bottlerocket-settings-sdk] -git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" -tag = "bottlerocket-settings-sdk-v0.1.0" -version = "0.1.0" diff --git a/sources/settings-extensions/container-runtime/container-runtime.toml b/sources/settings-extensions/container-runtime/container-runtime.toml deleted file mode 100644 index 727dfb274cd..00000000000 --- a/sources/settings-extensions/container-runtime/container-runtime.toml +++ /dev/null @@ -1,13 +0,0 @@ -[extension] -supported-versions = [ - "v1" -] -default-version = "v1" - -[v1] -[v1.validation.cross-validates] - -[v1.templating] -helpers = [] - -[v1.generation.requires] diff --git a/sources/settings-extensions/container-runtime/src/lib.rs b/sources/settings-extensions/container-runtime/src/lib.rs deleted file mode 100644 index d47ec522de1..00000000000 --- a/sources/settings-extensions/container-runtime/src/lib.rs +++ /dev/null @@ -1,92 +0,0 @@ -///Settings related to Container Runtime -use bottlerocket_settings_sdk::{GenerateResult, SettingsModel}; -use model_derive::model; -use std::convert::Infallible; - -#[model(impl_default = true)] -pub struct ContainerRuntimeSettingsV1 { - max_container_log_line_size: i32, - max_concurrent_downloads: i32, - enable_unprivileged_ports: bool, - enable_unprivileged_icmp: bool, -} - -type Result = std::result::Result; - -impl SettingsModel for ContainerRuntimeSettingsV1 { - type PartialKind = Self; - type ErrorKind = Infallible; - - fn get_version() -> &'static str { - "v1" - } - - fn set(_current_value: Option, _target: Self) -> Result<()> { - // Set anything that can be parsed as ContainerRuntimeSettingsV1. - Ok(()) - } - - fn generate( - existing_partial: Option, - _dependent_settings: Option, - ) -> Result> { - Ok(GenerateResult::Complete( - existing_partial.unwrap_or_default(), - )) - } - - fn validate(_value: Self, _validated_settings: Option) -> Result<()> { - // ContainerRuntimeSettingsV1 is validated during deserialization. - Ok(()) - } -} - -#[cfg(test)] -mod test { - use super::*; - use serde_json::json; - - #[test] - fn test_generate_container_runtime_settings() { - assert_eq!( - ContainerRuntimeSettingsV1::generate(None, None), - Ok(GenerateResult::Complete(ContainerRuntimeSettingsV1 { - max_container_log_line_size: None, - max_concurrent_downloads: None, - enable_unprivileged_ports: None, - enable_unprivileged_icmp: None, - })) - ) - } - - #[test] - fn test_serde_container_runtime() { - let test_json = json!({ - "max-container-log-line-size": 1024, - "max-concurrent-downloads": 5, - "enable-unprivileged-ports": true, - "enable-unprivileged-icmp": false - }); - - let test_json_str = test_json.to_string(); - - let container_runtime_settings: ContainerRuntimeSettingsV1 = - serde_json::from_str(&test_json_str).unwrap(); - - assert_eq!( - container_runtime_settings, - ContainerRuntimeSettingsV1 { - max_container_log_line_size: Some(1024), - max_concurrent_downloads: Some(5), - enable_unprivileged_ports: Some(true), - enable_unprivileged_icmp: Some(false), - } - ); - - let serialized_json: serde_json::Value = serde_json::to_string(&container_runtime_settings) - .map(|s| serde_json::from_str(&s).unwrap()) - .unwrap(); - - assert_eq!(serialized_json, test_json); - } -} diff --git a/sources/settings-extensions/container-runtime/src/main.rs b/sources/settings-extensions/container-runtime/src/main.rs deleted file mode 100644 index 0a1b034a26e..00000000000 --- a/sources/settings-extensions/container-runtime/src/main.rs +++ /dev/null @@ -1,20 +0,0 @@ -use bottlerocket_settings_sdk::{BottlerocketSetting, NullMigratorExtensionBuilder}; -use settings_extension_container_runtime::ContainerRuntimeSettingsV1; -use std::process::ExitCode; - -fn main() -> ExitCode { - env_logger::init(); - - match NullMigratorExtensionBuilder::with_name("container-runtime") - .with_models(vec![ - BottlerocketSetting::::model(), - ]) - .build() - { - Ok(extension) => extension.run(), - Err(e) => { - println!("{}", e); - ExitCode::FAILURE - } - } -} diff --git a/sources/settings-extensions/dns/Cargo.toml b/sources/settings-extensions/dns/Cargo.toml deleted file mode 100644 index f3655ddade2..00000000000 --- a/sources/settings-extensions/dns/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "settings-extension-dns" -version = "0.1.0" -authors = ["Gaurav Sharma "] -license = "Apache-2.0 OR MIT" -edition = "2021" -publish = false - -[dependencies] -env_logger = "0.10" -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -model-derive = { path = "../../models/model-derive", version = "0.1" } -serde = { version = "1", features = ["derive"] } -serde_json = "1" - -[dependencies.bottlerocket-settings-sdk] -git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" -tag = "bottlerocket-settings-sdk-v0.1.0" -version = "0.1.0" diff --git a/sources/settings-extensions/dns/dns.toml b/sources/settings-extensions/dns/dns.toml deleted file mode 100644 index 727dfb274cd..00000000000 --- a/sources/settings-extensions/dns/dns.toml +++ /dev/null @@ -1,13 +0,0 @@ -[extension] -supported-versions = [ - "v1" -] -default-version = "v1" - -[v1] -[v1.validation.cross-validates] - -[v1.templating] -helpers = [] - -[v1.generation.requires] diff --git a/sources/settings-extensions/dns/src/lib.rs b/sources/settings-extensions/dns/src/lib.rs deleted file mode 100644 index 6fd940f60d3..00000000000 --- a/sources/settings-extensions/dns/src/lib.rs +++ /dev/null @@ -1,84 +0,0 @@ -/// Settings related to custom DNS settings -use bottlerocket_settings_sdk::{GenerateResult, SettingsModel}; -use model_derive::model; -use modeled_types::ValidLinuxHostname; -use std::convert::Infallible; -use std::net::IpAddr; - -#[model(impl_default = true)] -pub struct DnsSettingsV1 { - name_servers: Vec, - search_list: Vec, -} - -type Result = std::result::Result; - -impl SettingsModel for DnsSettingsV1 { - type PartialKind = Self; - type ErrorKind = Infallible; - - fn get_version() -> &'static str { - "v1" - } - - fn set(_current_value: Option, _target: Self) -> Result<()> { - // Set anything that can be parsed as DnsSettingsV1. - Ok(()) - } - - fn generate( - existing_partial: Option, - _dependent_settings: Option, - ) -> Result> { - Ok(GenerateResult::Complete( - existing_partial.unwrap_or_default(), - )) - } - - fn validate(_value: Self, _validated_settings: Option) -> Result<()> { - // DnsSettingsV1 is validated during deserialization. - Ok(()) - } -} - -#[cfg(test)] -mod test { - use super::*; - use std::str::FromStr; - - #[test] - fn test_generate_dns_settings() { - assert_eq!( - DnsSettingsV1::generate(None, None), - Ok(GenerateResult::Complete(DnsSettingsV1 { - name_servers: None, - search_list: None, - })) - ) - } - - #[test] - fn test_serde_dns() { - let test_json = - r#"{"name-servers":["1.2.3.4","5.6.7.8"],"search-list":["foo.bar","baz.foo"]}"#; - - let dns: DnsSettingsV1 = serde_json::from_str(test_json).unwrap(); - assert_eq!( - dns.name_servers.clone().unwrap(), - vec!( - IpAddr::from_str("1.2.3.4").unwrap(), - IpAddr::from_str("5.6.7.8").unwrap(), - ) - ); - assert_eq!( - dns.search_list.clone().unwrap(), - vec!( - ValidLinuxHostname::try_from("foo.bar").unwrap(), - ValidLinuxHostname::try_from("baz.foo").unwrap(), - ) - ); - - let results = serde_json::to_string(&dns).unwrap(); - assert_eq!(results, test_json); - } -} diff --git a/sources/settings-extensions/dns/src/main.rs b/sources/settings-extensions/dns/src/main.rs deleted file mode 100644 index ebd3da5594e..00000000000 --- a/sources/settings-extensions/dns/src/main.rs +++ /dev/null @@ -1,18 +0,0 @@ -use bottlerocket_settings_sdk::{BottlerocketSetting, NullMigratorExtensionBuilder}; -use settings_extension_dns::DnsSettingsV1; -use std::process::ExitCode; - -fn main() -> ExitCode { - env_logger::init(); - - match NullMigratorExtensionBuilder::with_name("dns") - .with_models(vec![BottlerocketSetting::::model()]) - .build() - { - Ok(extension) => extension.run(), - Err(e) => { - println!("{}", e); - ExitCode::FAILURE - } - } -} diff --git a/sources/settings-extensions/ecs/Cargo.toml b/sources/settings-extensions/ecs/Cargo.toml deleted file mode 100644 index 75223a6a790..00000000000 --- a/sources/settings-extensions/ecs/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "settings-extension-ecs" -version = "0.1.0" -authors = ["Gaurav Sharma "] -license = "Apache-2.0 OR MIT" -edition = "2021" -publish = false - -[dependencies] -env_logger = "0.10" -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -model-derive = { path = "../../models/model-derive", version = "0.1" } -serde = { version = "1", features = ["derive"] } -serde_json = "1" - -[dependencies.bottlerocket-settings-sdk] -git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" -tag = "bottlerocket-settings-sdk-v0.1.0" -version = "0.1.0" diff --git a/sources/settings-extensions/ecs/ecs.toml b/sources/settings-extensions/ecs/ecs.toml deleted file mode 100644 index 727dfb274cd..00000000000 --- a/sources/settings-extensions/ecs/ecs.toml +++ /dev/null @@ -1,13 +0,0 @@ -[extension] -supported-versions = [ - "v1" -] -default-version = "v1" - -[v1] -[v1.validation.cross-validates] - -[v1.templating] -helpers = [] - -[v1.generation.requires] diff --git a/sources/settings-extensions/ecs/src/lib.rs b/sources/settings-extensions/ecs/src/lib.rs deleted file mode 100644 index f94840395f1..00000000000 --- a/sources/settings-extensions/ecs/src/lib.rs +++ /dev/null @@ -1,171 +0,0 @@ -/// Settings related to Amazon ECS -use bottlerocket_settings_sdk::{GenerateResult, SettingsModel}; -use model_derive::model; -use modeled_types::{ - ECSAgentImagePullBehavior, ECSAgentLogLevel, ECSAttributeKey, ECSAttributeValue, - ECSDurationValue, SingleLineString, -}; -use std::{collections::HashMap, convert::Infallible}; - -#[model(impl_default = true)] -pub struct ECSSettingsV1 { - cluster: String, - instance_attributes: HashMap, - allow_privileged_containers: bool, - logging_drivers: Vec, - loglevel: ECSAgentLogLevel, - enable_spot_instance_draining: bool, - image_pull_behavior: ECSAgentImagePullBehavior, - container_stop_timeout: ECSDurationValue, - task_cleanup_wait: ECSDurationValue, - metadata_service_rps: i64, - metadata_service_burst: i64, - reserved_memory: u16, - image_cleanup_wait: ECSDurationValue, - image_cleanup_delete_per_cycle: i64, - image_cleanup_enabled: bool, - image_cleanup_age: ECSDurationValue, - backend_host: String, - awsvpc_block_imds: bool, - enable_container_metadata: bool, -} - -type Result = std::result::Result; - -impl SettingsModel for ECSSettingsV1 { - type PartialKind = Self; - type ErrorKind = Infallible; - - fn get_version() -> &'static str { - "v1" - } - - fn set(_current_value: Option, _target: Self) -> Result<()> { - // Set anything that can be parsed as ECSSettingsV1. - Ok(()) - } - - fn generate( - existing_partial: Option, - _dependent_settings: Option, - ) -> Result> { - Ok(GenerateResult::Complete( - existing_partial.unwrap_or_default(), - )) - } - - fn validate(_value: Self, _validated_settings: Option) -> Result<()> { - // ECSSettingsV1 is validated during deserialization. - Ok(()) - } -} - -#[cfg(test)] -mod test { - use super::*; - use serde_json::json; - - #[test] - fn test_generate_ecs_settings() { - assert_eq!( - ECSSettingsV1::generate(None, None), - Ok(GenerateResult::Complete(ECSSettingsV1 { - cluster: None, - instance_attributes: None, - allow_privileged_containers: None, - logging_drivers: None, - loglevel: None, - enable_spot_instance_draining: None, - image_pull_behavior: None, - container_stop_timeout: None, - task_cleanup_wait: None, - metadata_service_rps: None, - metadata_service_burst: None, - reserved_memory: None, - image_cleanup_wait: None, - image_cleanup_delete_per_cycle: None, - image_cleanup_enabled: None, - image_cleanup_age: None, - backend_host: None, - awsvpc_block_imds: None, - enable_container_metadata: None, - })) - ) - } - - #[test] - fn test_serde_ecs() { - let test_json = json!({ - "cluster": "test-cluster", - "instance-attributes": { - "attribute1": "value1", - "attribute2": "value2" - }, - "allow-privileged-containers": true, - "logging-drivers": ["json-file", "awslogs"], - "loglevel": "info", - "enable-spot-instance-draining": true, - "image-pull-behavior": "always", - "container-stop-timeout": "30s", - "task-cleanup-wait": "1h", - "metadata-service-rps": 50, - "metadata-service-burst": 100, - "reserved-memory": 512, - "image-cleanup-wait": "1h", - "image-cleanup-delete-per-cycle": 2, - "image-cleanup-enabled": true, - "image-cleanup-age": "1h", - "backend-host": "ecs.us-east-1.amazonaws.com", - "awsvpc-block-imds": true, - "enable-container-metadata": true, - }); - - let test_json_str = test_json.to_string(); - - let ecs_settings: ECSSettingsV1 = serde_json::from_str(&test_json_str).unwrap(); - - let mut expected_instance_attributes: HashMap = - HashMap::new(); - expected_instance_attributes.insert( - ECSAttributeKey::try_from("attribute1").unwrap(), - ECSAttributeValue::try_from("value1").unwrap(), - ); - expected_instance_attributes.insert( - ECSAttributeKey::try_from("attribute2").unwrap(), - ECSAttributeValue::try_from("value2").unwrap(), - ); - - let expected_ecs_settings = ECSSettingsV1 { - cluster: Some("test-cluster".to_string()), - instance_attributes: Some(expected_instance_attributes), - allow_privileged_containers: Some(true), - logging_drivers: Some(vec![ - SingleLineString::try_from("json-file").unwrap(), - SingleLineString::try_from("awslogs").unwrap(), - ]), - loglevel: Some(ECSAgentLogLevel::Info), - enable_spot_instance_draining: Some(true), - image_pull_behavior: Some(ECSAgentImagePullBehavior::Always), - container_stop_timeout: Some(ECSDurationValue::try_from("30s").unwrap()), - task_cleanup_wait: Some(ECSDurationValue::try_from("1h").unwrap()), - metadata_service_rps: Some(50), - metadata_service_burst: Some(100), - reserved_memory: Some(512), - image_cleanup_wait: Some(ECSDurationValue::try_from("1h").unwrap()), - image_cleanup_delete_per_cycle: Some(2), - image_cleanup_enabled: Some(true), - image_cleanup_age: Some(ECSDurationValue::try_from("1h").unwrap()), - backend_host: Some("ecs.us-east-1.amazonaws.com".to_string()), - awsvpc_block_imds: Some(true), - enable_container_metadata: Some(true), - }; - - assert_eq!(ecs_settings, expected_ecs_settings); - - let serialized_json: serde_json::Value = serde_json::to_string(&ecs_settings) - .map(|s| serde_json::from_str(&s).unwrap()) - .unwrap(); - - assert_eq!(serialized_json, test_json); - } -} diff --git a/sources/settings-extensions/ecs/src/main.rs b/sources/settings-extensions/ecs/src/main.rs deleted file mode 100644 index 54e3d5012a7..00000000000 --- a/sources/settings-extensions/ecs/src/main.rs +++ /dev/null @@ -1,18 +0,0 @@ -use bottlerocket_settings_sdk::{BottlerocketSetting, NullMigratorExtensionBuilder}; -use settings_extension_ecs::ECSSettingsV1; -use std::process::ExitCode; - -fn main() -> ExitCode { - env_logger::init(); - - match NullMigratorExtensionBuilder::with_name("ecs") - .with_models(vec![BottlerocketSetting::::model()]) - .build() - { - Ok(extension) => extension.run(), - Err(e) => { - println!("{}", e); - ExitCode::FAILURE - } - } -} diff --git a/sources/settings-extensions/host-containers/Cargo.toml b/sources/settings-extensions/host-containers/Cargo.toml deleted file mode 100644 index df046f524a2..00000000000 --- a/sources/settings-extensions/host-containers/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "settings-extension-host-containers" -version = "0.1.0" -authors = ["Gaurav Sharma "] -edition = "2021" -license = "Apache-2.0 OR MIT" -publish = false - -[dependencies] -env_logger = "0.10" -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -model-derive = { path = "../../models/model-derive", version = "0.1" } -serde = { version = "1", features = ["derive"] } -serde_json = "1" - -[dependencies.bottlerocket-settings-sdk] -git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" -tag = "bottlerocket-settings-sdk-v0.1.0" -version = "0.1.0" diff --git a/sources/settings-extensions/host-containers/host-containers.toml b/sources/settings-extensions/host-containers/host-containers.toml deleted file mode 100644 index 727dfb274cd..00000000000 --- a/sources/settings-extensions/host-containers/host-containers.toml +++ /dev/null @@ -1,13 +0,0 @@ -[extension] -supported-versions = [ - "v1" -] -default-version = "v1" - -[v1] -[v1.validation.cross-validates] - -[v1.templating] -helpers = [] - -[v1.generation.requires] diff --git a/sources/settings-extensions/host-containers/src/lib.rs b/sources/settings-extensions/host-containers/src/lib.rs deleted file mode 100644 index 7ba1007021b..00000000000 --- a/sources/settings-extensions/host-containers/src/lib.rs +++ /dev/null @@ -1,120 +0,0 @@ -/// host-containers settings allow users to configure multiple host containers -use bottlerocket_settings_sdk::{GenerateResult, SettingsModel}; -use model_derive::model; -use modeled_types::{Identifier, Url, ValidBase64}; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use std::collections::HashMap; -use std::convert::Infallible; - -#[derive(Clone, Debug, Default, PartialEq)] -pub struct HostContainersSettingsV1 { - pub host_containers: HashMap, -} - -// Custom serializer/deserializer added to maintain backwards -// compatibility with models created prior to settings extensions. -impl Serialize for HostContainersSettingsV1 { - fn serialize(&self, serializer: S) -> std::result::Result - where - S: Serializer, - { - self.host_containers.serialize(serializer) - } -} - -impl<'de> Deserialize<'de> for HostContainersSettingsV1 { - fn deserialize(deserializer: D) -> std::result::Result - where - D: Deserializer<'de>, - { - let host_containers = HashMap::deserialize(deserializer)?; - Ok(Self { host_containers }) - } -} - -#[model(impl_default = true)] -struct HostContainer { - source: Url, - enabled: bool, - superpowered: bool, - user_data: ValidBase64, -} - -type Result = std::result::Result; - -impl SettingsModel for HostContainersSettingsV1 { - type PartialKind = Self; - type ErrorKind = Infallible; - - fn get_version() -> &'static str { - "v1" - } - - fn set(_current_value: Option, _target: Self) -> Result<()> { - // Set anything that can be parsed as HostContainersSettingsV1. - Ok(()) - } - - fn generate( - existing_partial: Option, - _dependent_settings: Option, - ) -> Result> { - Ok(GenerateResult::Complete( - existing_partial.unwrap_or_default(), - )) - } - - fn validate(_value: Self, _validated_settings: Option) -> Result<()> { - // HostContainersSettingsV1 is validated during deserialization. - Ok(()) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_generate_host_containers() { - let generated = HostContainersSettingsV1::generate(None, None).unwrap(); - - assert_eq!( - generated, - GenerateResult::Complete(HostContainersSettingsV1 { - host_containers: HashMap::new(), - }) - ) - } - - #[test] - fn test_serde_host_containers() { - let input_json = r#"{ - "foo": { - "source": "public.ecr.aws/example/example", - "enabled": true, - "superpowered": true, - "user-data": "Zm9vCg==" - } - }"#; - - let host_containers: HostContainersSettingsV1 = serde_json::from_str(input_json).unwrap(); - - let mut expected_host_containers: HashMap = HashMap::new(); - expected_host_containers.insert( - Identifier::try_from("foo").unwrap(), - HostContainer { - source: Some(Url::try_from("public.ecr.aws/example/example").unwrap()), - enabled: Some(true), - superpowered: Some(true), - user_data: Some(ValidBase64::try_from("Zm9vCg==").unwrap()), - }, - ); - - assert_eq!( - host_containers, - HostContainersSettingsV1 { - host_containers: expected_host_containers, - } - ); - } -} diff --git a/sources/settings-extensions/host-containers/src/main.rs b/sources/settings-extensions/host-containers/src/main.rs deleted file mode 100644 index e008c520552..00000000000 --- a/sources/settings-extensions/host-containers/src/main.rs +++ /dev/null @@ -1,20 +0,0 @@ -use bottlerocket_settings_sdk::{BottlerocketSetting, NullMigratorExtensionBuilder}; -use settings_extension_host_containers::HostContainersSettingsV1; -use std::process::ExitCode; - -fn main() -> ExitCode { - env_logger::init(); - - match NullMigratorExtensionBuilder::with_name("host-containers") - .with_models(vec![ - BottlerocketSetting::::model(), - ]) - .build() - { - Ok(extension) => extension.run(), - Err(e) => { - println!("{}", e); - ExitCode::FAILURE - } - } -} diff --git a/sources/settings-extensions/kernel/Cargo.toml b/sources/settings-extensions/kernel/Cargo.toml deleted file mode 100644 index 1ffd1770a81..00000000000 --- a/sources/settings-extensions/kernel/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "settings-extension-kernel" -version = "0.1.0" -authors = ["Sam Berning "] -license = "Apache-2.0 OR MIT" -edition = "2021" -publish = false - -[dependencies] -env_logger = "0.10" -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -model-derive = { path = "../../models/model-derive", version = "0.1" } -serde = { version = "1", features = ["derive"] } -serde_json = "1" - -[dependencies.bottlerocket-settings-sdk] -git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" -tag = "bottlerocket-settings-sdk-v0.1.0" -version = "0.1.0" diff --git a/sources/settings-extensions/kernel/kernel.toml b/sources/settings-extensions/kernel/kernel.toml deleted file mode 100644 index 727dfb274cd..00000000000 --- a/sources/settings-extensions/kernel/kernel.toml +++ /dev/null @@ -1,13 +0,0 @@ -[extension] -supported-versions = [ - "v1" -] -default-version = "v1" - -[v1] -[v1.validation.cross-validates] - -[v1.templating] -helpers = [] - -[v1.generation.requires] diff --git a/sources/settings-extensions/kernel/src/lib.rs b/sources/settings-extensions/kernel/src/lib.rs deleted file mode 100644 index e20173ed85d..00000000000 --- a/sources/settings-extensions/kernel/src/lib.rs +++ /dev/null @@ -1,103 +0,0 @@ -/// The kernel settings can be used to configure settings related to the kernel, e.g. -/// kernel modules -use bottlerocket_settings_sdk::{GenerateResult, SettingsModel}; -use model_derive::model; -use modeled_types::{KmodKey, Lockdown, SysctlKey}; -use std::collections::HashMap; -use std::convert::Infallible; - -#[model(impl_default = true)] -struct KernelSettingsV1 { - lockdown: Lockdown, - modules: HashMap, - // Values are almost always a single line and often just an integer... but not always. - sysctl: HashMap, -} - -#[model] -struct KmodSetting { - allowed: bool, - autoload: bool, -} - -type Result = std::result::Result; - -impl SettingsModel for KernelSettingsV1 { - type PartialKind = Self; - type ErrorKind = Infallible; - - fn get_version() -> &'static str { - "v1" - } - - fn set(_current_value: Option, _target: Self) -> Result<()> { - // allow anything that parses as KernelSettingsV1 - Ok(()) - } - - fn generate( - existing_partial: Option, - _dependent_settings: Option, - ) -> Result> { - Ok(GenerateResult::Complete( - existing_partial.unwrap_or_default(), - )) - } - - fn validate(_value: Self, _validated_settings: Option) -> Result<()> { - Ok(()) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_generate_kernel() { - let generated = KernelSettingsV1::generate(None, None).unwrap(); - - assert_eq!( - generated, - GenerateResult::Complete(KernelSettingsV1 { - lockdown: None, - modules: None, - sysctl: None, - }) - ) - } - - #[test] - fn test_serde_kernel() { - let test_json = r#"{ - "lockdown": "integrity", - "modules": {"foo": {"allowed": true, "autoload": true}}, - "sysctl": {"key": "value"} - }"#; - - let kernel: KernelSettingsV1 = serde_json::from_str(test_json).unwrap(); - - let mut modules = HashMap::new(); - modules.insert( - KmodKey::try_from("foo").unwrap(), - KmodSetting { - allowed: Some(true), - autoload: Some(true), - }, - ); - let modules = Some(modules); - - let mut sysctl = HashMap::new(); - sysctl.insert(SysctlKey::try_from("key").unwrap(), String::from("value")); - let sysctl = Some(sysctl); - - assert_eq!( - kernel, - KernelSettingsV1 { - lockdown: Some(Lockdown::try_from("integrity").unwrap()), - modules, - sysctl, - } - ); - } -} diff --git a/sources/settings-extensions/kernel/src/main.rs b/sources/settings-extensions/kernel/src/main.rs deleted file mode 100644 index 1138c399825..00000000000 --- a/sources/settings-extensions/kernel/src/main.rs +++ /dev/null @@ -1,18 +0,0 @@ -use bottlerocket_settings_sdk::{BottlerocketSetting, NullMigratorExtensionBuilder}; -use settings_extension_kernel::KernelSettingsV1; -use std::process::ExitCode; - -fn main() -> ExitCode { - env_logger::init(); - - match NullMigratorExtensionBuilder::with_name("kernel") - .with_models(vec![BottlerocketSetting::::model()]) - .build() - { - Ok(extension) => extension.run(), - Err(e) => { - println!("{}", e); - ExitCode::FAILURE - } - } -} diff --git a/sources/settings-extensions/metrics/Cargo.toml b/sources/settings-extensions/metrics/Cargo.toml deleted file mode 100644 index 34e592d84e4..00000000000 --- a/sources/settings-extensions/metrics/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "settings-extension-metrics" -version = "0.1.0" -authors = ["Sumukh Ballal "] -license = "Apache-2.0 OR MIT" -edition = "2021" -publish = false - -[dependencies] -env_logger = "0.10" -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -model-derive = { path = "../../models/model-derive", version = "0.1" } -serde = { version = "1", features = ["derive"] } -serde_json = "1" - -[dependencies.bottlerocket-settings-sdk] -git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" -tag = "bottlerocket-settings-sdk-v0.1.0" -version = "0.1.0" diff --git a/sources/settings-extensions/metrics/metrics.toml b/sources/settings-extensions/metrics/metrics.toml deleted file mode 100644 index 375dcc5b135..00000000000 --- a/sources/settings-extensions/metrics/metrics.toml +++ /dev/null @@ -1,14 +0,0 @@ -[extension] -supported-versions = [ - "v1" -] -default-version = "v1" - -[v1] -[v1.validation.cross-validates] - -[v1.templating] -helpers = [] - -[v1.generation.requires] - diff --git a/sources/settings-extensions/metrics/src/lib.rs b/sources/settings-extensions/metrics/src/lib.rs deleted file mode 100644 index 0d7f438a278..00000000000 --- a/sources/settings-extensions/metrics/src/lib.rs +++ /dev/null @@ -1,80 +0,0 @@ -/// The aws settings can be used to configure settings related to AWS -use bottlerocket_settings_sdk::{GenerateResult, SettingsModel}; -use model_derive::model; -use modeled_types::Url; -use std::convert::Infallible; - -// Platform-specific settings -#[model(impl_default = true)] -pub struct MetricsSettingsV1 { - metrics_url: Url, - send_metrics: bool, - service_checks: Vec, -} - -type Result = std::result::Result; - -impl SettingsModel for MetricsSettingsV1 { - type PartialKind = Self; - type ErrorKind = Infallible; - - fn get_version() -> &'static str { - "v1" - } - - fn set(_current_value: Option, _target: Self) -> Result<()> { - // allow anything that parses as MetricsSettingsV1 - Ok(()) - } - - fn generate( - existing_partial: Option, - _dependent_settings: Option, - ) -> Result> { - Ok(GenerateResult::Complete( - existing_partial.unwrap_or_default(), - )) - } - - fn validate(_value: Self, _validated_settings: Option) -> Result<()> { - Ok(()) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_generate_metrics() { - let generated = MetricsSettingsV1::generate(None, None).unwrap(); - assert_eq!( - generated, - GenerateResult::Complete(MetricsSettingsV1 { - metrics_url: None, - send_metrics: None, - service_checks: None, - }) - ) - } - - #[test] - fn test_serde_metrics() { - let test_json = r#"{"metrics-url":"https://metrics.bottlerocket.aws/v1/metrics","send-metrics":true,"service-checks":["apiserver","chronyd"]}"#; - - let metrics: MetricsSettingsV1 = serde_json::from_str(test_json).unwrap(); - assert_eq!( - metrics, - MetricsSettingsV1 { - metrics_url: Some( - Url::try_from("https://metrics.bottlerocket.aws/v1/metrics").unwrap() - ), - send_metrics: Some(true), - service_checks: Some(vec![String::from("apiserver"), String::from("chronyd")]) - } - ); - - let results = serde_json::to_string(&metrics).unwrap(); - assert_eq!(results, test_json); - } -} diff --git a/sources/settings-extensions/metrics/src/main.rs b/sources/settings-extensions/metrics/src/main.rs deleted file mode 100644 index f919620fb8b..00000000000 --- a/sources/settings-extensions/metrics/src/main.rs +++ /dev/null @@ -1,18 +0,0 @@ -use bottlerocket_settings_sdk::{BottlerocketSetting, NullMigratorExtensionBuilder}; -use settings_extension_metrics::MetricsSettingsV1; -use std::process::ExitCode; - -fn main() -> ExitCode { - env_logger::init(); - - match NullMigratorExtensionBuilder::with_name("metrics") - .with_models(vec![BottlerocketSetting::::model()]) - .build() - { - Ok(extension) => extension.run(), - Err(e) => { - println!("{}", e); - ExitCode::FAILURE - } - } -} diff --git a/sources/settings-extensions/motd/Cargo.toml b/sources/settings-extensions/motd/Cargo.toml deleted file mode 100644 index ed17b0ad3a9..00000000000 --- a/sources/settings-extensions/motd/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "settings-extension-motd" -version = "0.1.0" -authors = ["Sean P. Kelly "] -license = "Apache-2.0 OR MIT" -edition = "2021" -publish = false - -[dependencies] -serde = { version = "1", features = ["derive"] } -serde_json = "1" -string_impls_for = { version = "0.1", path = "../../models/string_impls_for" } - -[dependencies.bottlerocket-settings-sdk] -git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" -tag = "bottlerocket-settings-sdk-v0.1.0" -version = "0.1.0" diff --git a/sources/settings-extensions/motd/motd.toml b/sources/settings-extensions/motd/motd.toml deleted file mode 100644 index 727dfb274cd..00000000000 --- a/sources/settings-extensions/motd/motd.toml +++ /dev/null @@ -1,13 +0,0 @@ -[extension] -supported-versions = [ - "v1" -] -default-version = "v1" - -[v1] -[v1.validation.cross-validates] - -[v1.templating] -helpers = [] - -[v1.generation.requires] diff --git a/sources/settings-extensions/motd/src/lib.rs b/sources/settings-extensions/motd/src/lib.rs deleted file mode 100644 index eecb7c458aa..00000000000 --- a/sources/settings-extensions/motd/src/lib.rs +++ /dev/null @@ -1,92 +0,0 @@ -/// The motd setting is used to set the "message of the day" that is shown to users when logging -/// into the Bottlerocket control container. -use bottlerocket_settings_sdk::{GenerateResult, LinearlyMigrateable, NoMigration, SettingsModel}; -use std::convert::Infallible; -use string_impls_for::string_impls_for; - -#[derive(Clone, Debug, Default, PartialEq, Eq)] -pub struct MotdV1 { - inner: String, -} - -type Result = std::result::Result; - -impl SettingsModel for MotdV1 { - /// We only have one value, so there's no such thing as a partial - type PartialKind = Self; - type ErrorKind = Infallible; - - fn get_version() -> &'static str { - "v1" - } - - fn set(_current_value: Option, _target: Self) -> Result<()> { - // Allow anything that parses as MotdV1 - Ok(()) - } - - fn generate( - existing_partial: Option, - _dependent_settings: Option, - ) -> Result> { - Ok(GenerateResult::Complete( - existing_partial.unwrap_or_default(), - )) - } - - fn validate(_value: Self, _validated_settings: Option) -> Result<()> { - // No need to do any additional validation, any MotdV1 is acceptable - Ok(()) - } -} - -impl LinearlyMigrateable for MotdV1 { - type ForwardMigrationTarget = NoMigration; - type BackwardMigrationTarget = NoMigration; - - fn migrate_forward(&self) -> Result { - NoMigration::no_defined_migration() - } - - fn migrate_backward(&self) -> Result { - NoMigration::no_defined_migration() - } -} - -impl TryFrom<&str> for MotdV1 { - type Error = Infallible; - - fn try_from(input: &str) -> Result { - Ok(MotdV1 { - inner: input.to_string(), - }) - } -} - -string_impls_for!(MotdV1, "MotdV1"); - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_generate_motd() { - assert_eq!( - MotdV1::generate(None, None), - Ok(GenerateResult::Complete(MotdV1 { - inner: "".to_string() - })) - ) - } - - #[test] - fn test_serde_motd() { - let test_json = r#""This is a motd""#; - - let motd: MotdV1 = serde_json::from_str(test_json).unwrap(); - assert_eq!(motd.inner, "This is a motd".to_string()); - - let results = serde_json::to_string(&motd).unwrap(); - assert_eq!(results, test_json); - } -} diff --git a/sources/settings-extensions/motd/src/main.rs b/sources/settings-extensions/motd/src/main.rs deleted file mode 100644 index 3a9a0ae8e9a..00000000000 --- a/sources/settings-extensions/motd/src/main.rs +++ /dev/null @@ -1,16 +0,0 @@ -use bottlerocket_settings_sdk::{BottlerocketSetting, LinearMigratorExtensionBuilder}; -use settings_extension_motd::MotdV1; -use std::process::ExitCode; - -fn main() -> ExitCode { - match LinearMigratorExtensionBuilder::with_name("motd") - .with_models(vec![BottlerocketSetting::::model()]) - .build() - { - Ok(extension) => extension.run(), - Err(e) => { - println!("{}", e); - ExitCode::FAILURE - } - } -} diff --git a/sources/settings-extensions/network/Cargo.toml b/sources/settings-extensions/network/Cargo.toml deleted file mode 100644 index f86f24b93b3..00000000000 --- a/sources/settings-extensions/network/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "settings-extension-network" -version = "0.1.0" -authors = ["Gaurav Sharma "] -license = "Apache-2.0 OR MIT" -edition = "2021" -publish = false - -[dependencies] -env_logger = "0.10" -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -model-derive = { path = "../../models/model-derive", version = "0.1" } -serde = { version = "1", features = ["derive"] } -serde_json = "1" - -[dependencies.bottlerocket-settings-sdk] -git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" -tag = "bottlerocket-settings-sdk-v0.1.0" -version = "0.1.0" diff --git a/sources/settings-extensions/network/network.toml b/sources/settings-extensions/network/network.toml deleted file mode 100644 index 727dfb274cd..00000000000 --- a/sources/settings-extensions/network/network.toml +++ /dev/null @@ -1,13 +0,0 @@ -[extension] -supported-versions = [ - "v1" -] -default-version = "v1" - -[v1] -[v1.validation.cross-validates] - -[v1.templating] -helpers = [] - -[v1.generation.requires] diff --git a/sources/settings-extensions/network/src/lib.rs b/sources/settings-extensions/network/src/lib.rs deleted file mode 100644 index 1fc84df06f1..00000000000 --- a/sources/settings-extensions/network/src/lib.rs +++ /dev/null @@ -1,86 +0,0 @@ -/// Settings related to networking configuration. -use bottlerocket_settings_sdk::{GenerateResult, SettingsModel}; -use model_derive::model; -use modeled_types::{EtcHostsEntries, SingleLineString, Url, ValidLinuxHostname}; -use std::convert::Infallible; - -#[model(impl_default = true)] -struct NetworkSettingsV1 { - hostname: ValidLinuxHostname, - hosts: EtcHostsEntries, - https_proxy: Url, - no_proxy: Vec, -} - -type Result = std::result::Result; - -impl SettingsModel for NetworkSettingsV1 { - type PartialKind = Self; - type ErrorKind = Infallible; - - fn get_version() -> &'static str { - "v1" - } - - fn set(_current_value: Option, _target: Self) -> Result<()> { - // Set anything that can be parsed as NetworkSettingsV1. - Ok(()) - } - - fn generate( - existing_partial: Option, - _dependent_settings: Option, - ) -> Result> { - Ok(GenerateResult::Complete( - existing_partial.unwrap_or_default(), - )) - } - - fn validate(_value: Self, _validated_settings: Option) -> Result<()> { - // NetworkSettingsV1 is validated during deserialization. - Ok(()) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_generate_network_settings() { - assert_eq!( - NetworkSettingsV1::generate(None, None), - Ok(GenerateResult::Complete(NetworkSettingsV1 { - hostname: None, - hosts: None, - https_proxy: None, - no_proxy: None, - })) - ) - } - - #[test] - fn test_serde_network() { - let test_json = r#"{ - "hostname": "foo", - "hosts": [["127.0.0.1", ["localhost"]]], - "https-proxy": "https://example.net", - "no-proxy": ["foo"] - }"#; - - let network: NetworkSettingsV1 = serde_json::from_str(test_json).unwrap(); - - assert_eq!( - network, - NetworkSettingsV1 { - hostname: Some(ValidLinuxHostname::try_from("foo").unwrap()), - hosts: Some( - serde_json::from_str::(r#"[["127.0.0.1", ["localhost"]]]"#) - .unwrap() - ), - https_proxy: Some(Url::try_from("https://example.net").unwrap()), - no_proxy: Some(vec![SingleLineString::try_from("foo").unwrap()]), - } - ); - } -} diff --git a/sources/settings-extensions/network/src/main.rs b/sources/settings-extensions/network/src/main.rs deleted file mode 100644 index dce11d62d5b..00000000000 --- a/sources/settings-extensions/network/src/main.rs +++ /dev/null @@ -1,18 +0,0 @@ -use bottlerocket_settings_sdk::{BottlerocketSetting, NullMigratorExtensionBuilder}; -use settings_extension_network::NetworkSettingsV1; -use std::process::ExitCode; - -fn main() -> ExitCode { - env_logger::init(); - - match NullMigratorExtensionBuilder::with_name("network") - .with_models(vec![BottlerocketSetting::::model()]) - .build() - { - Ok(extension) => extension.run(), - Err(e) => { - println!("{}", e); - ExitCode::FAILURE - } - } -} diff --git a/sources/settings-extensions/ntp/Cargo.toml b/sources/settings-extensions/ntp/Cargo.toml deleted file mode 100644 index 7dddaaec01a..00000000000 --- a/sources/settings-extensions/ntp/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "settings-extension-ntp" -version = "0.1.0" -authors = ["Sam Berning "] -license = "Apache-2.0 OR MIT" -edition = "2021" -publish = false - -[dependencies] -env_logger = "0.10" -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -model-derive = { path = "../../models/model-derive", version = "0.1" } -serde = { version = "1", features = ["derive"] } -serde_json = "1" - -[dependencies.bottlerocket-settings-sdk] -git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" -tag = "bottlerocket-settings-sdk-v0.1.0" -version = "0.1.0" diff --git a/sources/settings-extensions/ntp/ntp.toml b/sources/settings-extensions/ntp/ntp.toml deleted file mode 100644 index 727dfb274cd..00000000000 --- a/sources/settings-extensions/ntp/ntp.toml +++ /dev/null @@ -1,13 +0,0 @@ -[extension] -supported-versions = [ - "v1" -] -default-version = "v1" - -[v1] -[v1.validation.cross-validates] - -[v1.templating] -helpers = [] - -[v1.generation.requires] diff --git a/sources/settings-extensions/ntp/src/lib.rs b/sources/settings-extensions/ntp/src/lib.rs deleted file mode 100644 index b653bc67980..00000000000 --- a/sources/settings-extensions/ntp/src/lib.rs +++ /dev/null @@ -1,104 +0,0 @@ -/// The ntp settings can be used to specify time servers with which to synchronize the instance's -/// clock. -use bottlerocket_settings_sdk::{GenerateResult, LinearlyMigrateable, NoMigration, SettingsModel}; -use model_derive::model; -use modeled_types::Url; -use std::convert::Infallible; - -#[model(impl_default = true)] -pub struct NtpSettingsV1 { - time_servers: Vec, - options: Vec, -} - -type Result = std::result::Result; - -impl SettingsModel for NtpSettingsV1 { - /// the `model` macro makes every field of the `NtpSettingsV1` struct an `Option`, so we can use - /// the type as its own `PartialKind`. - type PartialKind = Self; - type ErrorKind = Infallible; - - fn get_version() -> &'static str { - "v1" - } - - fn set(_current_value: Option, _target: Self) -> Result<()> { - // Anything that parses as a list of URLs is ok - Ok(()) - } - - fn generate( - existing_partial: Option, - _dependent_settings: Option, - ) -> Result> { - Ok(GenerateResult::Complete( - existing_partial.unwrap_or_default(), - )) - } - - fn validate(_value: Self, _validated_settings: Option) -> Result<()> { - // Anything that parses as a list of URLs is ok - Ok(()) - } -} - -impl LinearlyMigrateable for NtpSettingsV1 { - type ForwardMigrationTarget = NoMigration; - type BackwardMigrationTarget = NoMigration; - - fn migrate_forward(&self) -> Result { - NoMigration::no_defined_migration() - } - - fn migrate_backward(&self) -> Result { - NoMigration::no_defined_migration() - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_generate_ntp_settings() { - assert_eq!( - NtpSettingsV1::generate(None, None), - Ok(GenerateResult::Complete(NtpSettingsV1 { - time_servers: None, - options: None, - })) - ) - } - - #[test] - fn test_serde_ntp() { - let test_json = r#"{"time-servers":["https://example.net","http://www.example.com"]}"#; - - let ntp: NtpSettingsV1 = serde_json::from_str(test_json).unwrap(); - assert_eq!( - ntp.time_servers.clone().unwrap(), - vec!( - Url::try_from("https://example.net").unwrap(), - Url::try_from("http://www.example.com").unwrap(), - ) - ); - - let results = serde_json::to_string(&ntp).unwrap(); - assert_eq!(results, test_json); - } - - #[test] - fn test_options_ntp() { - let test_json = r#"{"time-servers":["https://example.net","http://www.example.com"],"options":["minpoll","1","maxpoll","2"]}"#; - - let ntp: NtpSettingsV1 = serde_json::from_str(test_json).unwrap(); - assert_eq!( - ntp.options.clone().unwrap(), - vec!("minpoll", "1", "maxpoll", "2",) - ); - - let results = serde_json::to_string(&ntp).unwrap(); - assert_eq!(results, test_json); - } -} diff --git a/sources/settings-extensions/ntp/src/main.rs b/sources/settings-extensions/ntp/src/main.rs deleted file mode 100644 index a3b2444f09c..00000000000 --- a/sources/settings-extensions/ntp/src/main.rs +++ /dev/null @@ -1,18 +0,0 @@ -use bottlerocket_settings_sdk::{BottlerocketSetting, LinearMigratorExtensionBuilder}; -use settings_extension_ntp::NtpSettingsV1; -use std::process::ExitCode; - -fn main() -> ExitCode { - env_logger::init(); - - match LinearMigratorExtensionBuilder::with_name("ntp") - .with_models(vec![BottlerocketSetting::::model()]) - .build() - { - Ok(extension) => extension.run(), - Err(e) => { - println!("{}", e); - ExitCode::FAILURE - } - } -} diff --git a/sources/settings-extensions/oci-defaults/Cargo.toml b/sources/settings-extensions/oci-defaults/Cargo.toml deleted file mode 100644 index 6149666f655..00000000000 --- a/sources/settings-extensions/oci-defaults/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "settings-extension-oci-defaults" -version = "0.1.0" -authors = ["Gaurav Sharma "] -license = "Apache-2.0 OR MIT" -edition = "2021" -publish = false - -[dependencies] -env_logger = "0.10" -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -model-derive = { path = "../../models/model-derive", version = "0.1" } -serde = { version = "1", features = ["derive"] } -serde_json = "1" -toml = "0.8" - -[dependencies.bottlerocket-settings-sdk] -git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" -tag = "bottlerocket-settings-sdk-v0.1.0" -version = "0.1.0" diff --git a/sources/settings-extensions/oci-defaults/oci-defaults.toml b/sources/settings-extensions/oci-defaults/oci-defaults.toml deleted file mode 100644 index 727dfb274cd..00000000000 --- a/sources/settings-extensions/oci-defaults/oci-defaults.toml +++ /dev/null @@ -1,13 +0,0 @@ -[extension] -supported-versions = [ - "v1" -] -default-version = "v1" - -[v1] -[v1.validation.cross-validates] - -[v1.templating] -helpers = [] - -[v1.generation.requires] diff --git a/sources/settings-extensions/oci-defaults/src/de.rs b/sources/settings-extensions/oci-defaults/src/de.rs deleted file mode 100644 index 7d4ec1c3ffb..00000000000 --- a/sources/settings-extensions/oci-defaults/src/de.rs +++ /dev/null @@ -1,126 +0,0 @@ -use serde::de::Error; -use serde::{Deserialize, Deserializer}; - -/// This specifies that any non negative i64 integer, -1, and "unlimited" -/// are the valid resource-limits. The hard-limit set to "unlimited" or -1 -/// and soft-limit set to "unlimited" or -1 are converted to u64::MAX in -/// the spec file for the container runtime which ultimately represents -/// unlimited for that resource -pub(crate) fn deserialize_limit<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - #[derive(Deserialize)] - #[serde(untagged)] - enum StringOrInt64 { - String(String), - Int(i64), - } - - match StringOrInt64::deserialize(deserializer)? { - StringOrInt64::String(s) => { - if s == "unlimited" { - Ok(-1) - } else { - Err(Error::custom(format!( - "Invalid rlimit {}, expected -1 to {} or \"unlimited\"", - s, - i64::MAX - ))) - } - } - StringOrInt64::Int(i) => { - if (-1..=i64::MAX).contains(&i) { - Ok(i) - } else { - Err(Error::custom(format!( - "Invalid rlimit {}, expected -1 to {} or \"unlimited\"", - i, - i64::MAX - ))) - } - } - } -} - -#[cfg(test)] -mod oci_default_resource_limit_tests { - use crate::OciDefaultsResourceLimitV1; - - #[test] - fn valid_any_integer_i_64() { - assert!(toml::from_str::( - r#" - hard-limit = 200000 - soft-limit = 10000 - "# - ) - .is_ok()); - } - - #[test] - fn valid_string_unlimited() { - assert!(toml::from_str::( - r#" - hard-limit = 'unlimited' - soft-limit = 10000 - "# - ) - .is_ok()); - } - - #[test] - fn valid_integer_i_64_max() { - assert!(toml::from_str::( - r#" - hard-limit = 9223372036854775807 - soft-limit = 10000 - "# - ) - .is_ok()); - } - - #[test] - fn valid_integer_minus_one() { - assert!(toml::from_str::( - r#" - hard-limit = -1 - soft-limit = 10000 - "# - ) - .is_ok()); - } - - #[test] - fn invalid_integer_greater_than_i_64_max() { - assert!(toml::from_str::( - r#" - hard-limit = 9223372036854775808 - soft-limit = 10000 - "# - ) - .is_err()); - } - - #[test] - fn invalid_minus_2() { - assert!(toml::from_str::( - r#" - hard-limit = -2 - soft-limit = 10000 - "# - ) - .is_err()); - } - - #[test] - fn invalid_string_abc() { - assert!(toml::from_str::( - r#" - hard-limit = 'abc' - soft-limit = 10000 - "# - ) - .is_err()); - } -} diff --git a/sources/settings-extensions/oci-defaults/src/lib.rs b/sources/settings-extensions/oci-defaults/src/lib.rs deleted file mode 100644 index 2240b0cc4f7..00000000000 --- a/sources/settings-extensions/oci-defaults/src/lib.rs +++ /dev/null @@ -1,122 +0,0 @@ -/// Settings related to orchestrated containers for overriding the OCI runtime spec defaults -mod de; - -use crate::de::deserialize_limit; -use bottlerocket_settings_sdk::{GenerateResult, SettingsModel}; -use model_derive::model; -use modeled_types::{OciDefaultsCapability, OciDefaultsResourceLimitType}; -use serde::{Deserialize, Serialize}; -use std::collections::HashMap; -use std::convert::Infallible; - -///// OCI defaults specifies the default values that will be used in cri-base-json. -#[model(impl_default = true)] -struct OciDefaultsV1 { - capabilities: HashMap, - resource_limits: HashMap, -} - -///// The hard and soft limit values for an OCI defaults resource limit. -#[model(add_option = false)] -#[derive(Copy, Clone, Debug, Deserialize, Serialize, Eq, Ord, PartialOrd, PartialEq)] -struct OciDefaultsResourceLimitV1 { - #[serde(deserialize_with = "deserialize_limit")] - hard_limit: i64, - #[serde(deserialize_with = "deserialize_limit")] - soft_limit: i64, -} - -type Result = std::result::Result; - -impl SettingsModel for OciDefaultsV1 { - type PartialKind = Self; - type ErrorKind = Infallible; - - fn get_version() -> &'static str { - "v1" - } - - fn set(_current_value: Option, _target: Self) -> Result<()> { - // Set anything that can be parsed as OciDefaultsV1. - Ok(()) - } - - fn generate( - existing_partial: Option, - _dependent_settings: Option, - ) -> Result> { - Ok(GenerateResult::Complete( - existing_partial.unwrap_or_default(), - )) - } - - fn validate(_value: Self, _validated_settings: Option) -> Result<()> { - // OciDefaultsV1 is validated during deserialization. - Ok(()) - } -} - -#[cfg(test)] -mod test { - use super::*; - use serde_json::json; - use std::collections::HashMap; - - #[test] - fn test_generate_oci_defaults() { - assert_eq!( - OciDefaultsV1::generate(None, None), - Ok(GenerateResult::Complete(OciDefaultsV1 { - capabilities: None, - resource_limits: None, - })) - ) - } - - #[test] - fn test_serde_oci_defaults() { - let test_json = json!({ - "capabilities": { - "sys-admin": true, - "net-admin": false - }, - "resource-limits": { - "max-cpu-time": { - "hard-limit": 1000, - "soft-limit": 500 - } - } - }); - - let test_json_str = test_json.to_string(); - - let oci_defaults: OciDefaultsV1 = serde_json::from_str(&test_json_str).unwrap(); - - let mut expected_capabilities = HashMap::new(); - expected_capabilities.insert(OciDefaultsCapability::SysAdmin, true); - expected_capabilities.insert(OciDefaultsCapability::NetAdmin, false); - - let mut expected_resource_limits = HashMap::new(); - expected_resource_limits.insert( - OciDefaultsResourceLimitType::MaxCpuTime, - OciDefaultsResourceLimitV1 { - hard_limit: 1000, - soft_limit: 500, - }, - ); - - assert_eq!( - oci_defaults, - OciDefaultsV1 { - capabilities: Some(expected_capabilities), - resource_limits: Some(expected_resource_limits), - } - ); - - let serialized_json: serde_json::Value = serde_json::to_string(&oci_defaults) - .map(|s| serde_json::from_str(&s).unwrap()) - .unwrap(); - - assert_eq!(serialized_json, test_json); - } -} diff --git a/sources/settings-extensions/oci-defaults/src/main.rs b/sources/settings-extensions/oci-defaults/src/main.rs deleted file mode 100644 index f75ee51705c..00000000000 --- a/sources/settings-extensions/oci-defaults/src/main.rs +++ /dev/null @@ -1,18 +0,0 @@ -use bottlerocket_settings_sdk::{BottlerocketSetting, NullMigratorExtensionBuilder}; -use settings_extension_oci_defaults::OciDefaultsV1; -use std::process::ExitCode; - -fn main() -> ExitCode { - env_logger::init(); - - match NullMigratorExtensionBuilder::with_name("oci-defaults") - .with_models(vec![BottlerocketSetting::::model()]) - .build() - { - Ok(extension) => extension.run(), - Err(e) => { - println!("{}", e); - ExitCode::FAILURE - } - } -} diff --git a/sources/settings-extensions/oci-hooks/Cargo.toml b/sources/settings-extensions/oci-hooks/Cargo.toml deleted file mode 100644 index 9a8e097db6f..00000000000 --- a/sources/settings-extensions/oci-hooks/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "settings-extension-oci-hooks" -version = "0.1.0" -authors = ["Gaurav Sharma "] -license = "Apache-2.0 OR MIT" -edition = "2021" -publish = false - -[dependencies] -env_logger = "0.10" -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -model-derive = { path = "../../models/model-derive", version = "0.1" } -serde = { version = "1", features = ["derive"] } -serde_json = "1" - -[dependencies.bottlerocket-settings-sdk] -git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" -tag = "bottlerocket-settings-sdk-v0.1.0" -version = "0.1.0" diff --git a/sources/settings-extensions/oci-hooks/oci-hooks.toml b/sources/settings-extensions/oci-hooks/oci-hooks.toml deleted file mode 100644 index 727dfb274cd..00000000000 --- a/sources/settings-extensions/oci-hooks/oci-hooks.toml +++ /dev/null @@ -1,13 +0,0 @@ -[extension] -supported-versions = [ - "v1" -] -default-version = "v1" - -[v1] -[v1.validation.cross-validates] - -[v1.templating] -helpers = [] - -[v1.generation.requires] diff --git a/sources/settings-extensions/oci-hooks/src/lib.rs b/sources/settings-extensions/oci-hooks/src/lib.rs deleted file mode 100644 index 6ea3e1d05f7..00000000000 --- a/sources/settings-extensions/oci-hooks/src/lib.rs +++ /dev/null @@ -1,72 +0,0 @@ -/// Settings related to host-provided OCI Hooks -use bottlerocket_settings_sdk::{GenerateResult, SettingsModel}; -use model_derive::model; -use std::convert::Infallible; - -/// The log4j hotpatch functionality is no longer included in Bottlerocket as of v1.15.0. -/// The setting still exists for backwards compatibility. -#[model(impl_default = true)] -pub struct OciHooksSettingsV1 { - log4j_hotpatch_enabled: bool, -} - -type Result = std::result::Result; - -impl SettingsModel for OciHooksSettingsV1 { - type PartialKind = Self; - type ErrorKind = Infallible; - - fn get_version() -> &'static str { - "v1" - } - - fn set(_current_value: Option, _target: Self) -> Result<()> { - // Set anything that can be parsed as OciHooksSettingsV1. - Ok(()) - } - - fn generate( - existing_partial: Option, - _dependent_settings: Option, - ) -> Result> { - Ok(GenerateResult::Complete( - existing_partial.unwrap_or_default(), - )) - } - - fn validate(_value: Self, _validated_settings: Option) -> Result<()> { - // OciHooksSettingsV1 is validated during deserialization. - Ok(()) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_generate_oci_hooks() { - assert_eq!( - OciHooksSettingsV1::generate(None, None).unwrap(), - GenerateResult::Complete(OciHooksSettingsV1 { - log4j_hotpatch_enabled: None, - }) - ) - } - - #[test] - fn test_serde_oci_hooks() { - let test_json = r#"{"log4j-hotpatch-enabled":true}"#; - - let oci_hooks: OciHooksSettingsV1 = serde_json::from_str(test_json).unwrap(); - assert_eq!( - oci_hooks, - OciHooksSettingsV1 { - log4j_hotpatch_enabled: Some(true), - } - ); - - let results = serde_json::to_string(&oci_hooks).unwrap(); - assert_eq!(results, test_json); - } -} diff --git a/sources/settings-extensions/oci-hooks/src/main.rs b/sources/settings-extensions/oci-hooks/src/main.rs deleted file mode 100644 index 52d2d152045..00000000000 --- a/sources/settings-extensions/oci-hooks/src/main.rs +++ /dev/null @@ -1,18 +0,0 @@ -use bottlerocket_settings_sdk::{BottlerocketSetting, NullMigratorExtensionBuilder}; -use settings_extension_oci_hooks::OciHooksSettingsV1; -use std::process::ExitCode; - -fn main() -> ExitCode { - env_logger::init(); - - match NullMigratorExtensionBuilder::with_name("oci-hooks") - .with_models(vec![BottlerocketSetting::::model()]) - .build() - { - Ok(extension) => extension.run(), - Err(e) => { - println!("{}", e); - ExitCode::FAILURE - } - } -} diff --git a/sources/settings-extensions/pki/Cargo.toml b/sources/settings-extensions/pki/Cargo.toml deleted file mode 100644 index 50b2a654d27..00000000000 --- a/sources/settings-extensions/pki/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "settings-extension-pki" -version = "0.1.0" -authors = ["Gaurav Sharma "] -license = "Apache-2.0 OR MIT" -edition = "2021" -publish = false - -[dependencies] -env_logger = "0.10" -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -model-derive = { path = "../../models/model-derive", version = "0.1" } -serde = { version = "1", features = ["derive"] } -serde_json = "1" - -[dependencies.bottlerocket-settings-sdk] -git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" -tag = "bottlerocket-settings-sdk-v0.1.0" -version = "0.1.0" diff --git a/sources/settings-extensions/pki/pki.toml b/sources/settings-extensions/pki/pki.toml deleted file mode 100644 index 727dfb274cd..00000000000 --- a/sources/settings-extensions/pki/pki.toml +++ /dev/null @@ -1,13 +0,0 @@ -[extension] -supported-versions = [ - "v1" -] -default-version = "v1" - -[v1] -[v1.validation.cross-validates] - -[v1.templating] -helpers = [] - -[v1.generation.requires] diff --git a/sources/settings-extensions/pki/src/lib.rs b/sources/settings-extensions/pki/src/lib.rs deleted file mode 100644 index c9e15e24172..00000000000 --- a/sources/settings-extensions/pki/src/lib.rs +++ /dev/null @@ -1,115 +0,0 @@ -/// Settings related to Custom CA Certificates. -use bottlerocket_settings_sdk::{GenerateResult, SettingsModel}; -use model_derive::model; -use modeled_types::{Identifier, PemCertificateString}; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use std::{collections::HashMap, convert::Infallible}; - -#[derive(Clone, Debug, Default, PartialEq)] -pub struct PkiSettingsV1 { - pub pki: HashMap, -} - -impl Serialize for PkiSettingsV1 { - fn serialize(&self, serializer: S) -> std::result::Result - where - S: Serializer, - { - self.pki.serialize(serializer) - } -} - -impl<'de> Deserialize<'de> for PkiSettingsV1 { - fn deserialize(deserializer: D) -> std::result::Result - where - D: Deserializer<'de>, - { - let pki = HashMap::deserialize(deserializer)?; - Ok(Self { pki }) - } -} - -#[model(impl_default = true)] -struct PemCertificate { - data: PemCertificateString, - trusted: bool, -} - -type Result = std::result::Result; - -impl SettingsModel for PkiSettingsV1 { - type PartialKind = Self; - type ErrorKind = Infallible; - - fn get_version() -> &'static str { - "v1" - } - - fn set(_current_value: Option, _target: Self) -> Result<()> { - // Set anything that parses as PkiSettingsV1. - Ok(()) - } - - fn generate( - _existing_partial: Option, - _dependent_settings: Option, - ) -> Result> { - Ok(GenerateResult::Complete(PkiSettingsV1 { - pki: HashMap::new(), - })) - } - - fn validate(_value: Self, _validated_settings: Option) -> Result<()> { - // Validate anything that parses as PkiSettingsV1. - Ok(()) - } -} - -#[cfg(test)] -mod test { - use super::*; - use serde_json::json; - - static VALID_PEM: &str = include_str!("../tests/data/test-pem"); - - #[test] - fn test_generate_pki_settings() { - assert_eq!( - PkiSettingsV1::generate(None, None), - Ok(GenerateResult::Complete(PkiSettingsV1 { - pki: HashMap::new(), - })) - ) - } - - #[test] - fn test_serde_pki() { - let test_json = json!({ - "foo": { - "data": VALID_PEM, - "trusted": true - } - }); - - let test_json_str = test_json.to_string(); - - let pki: PkiSettingsV1 = serde_json::from_str(&test_json_str).unwrap(); - - let mut expected_pki: HashMap = HashMap::new(); - expected_pki.insert( - Identifier::try_from("foo").unwrap(), - PemCertificate { - data: Some(PemCertificateString::try_from(VALID_PEM).unwrap()), - trusted: Some(true), - }, - ); - - assert_eq!(pki, PkiSettingsV1 { pki: expected_pki }); - - let serialized_json: serde_json::Value = serde_json::to_string(&pki) - .map(|s| serde_json::from_str(&s).unwrap()) - .unwrap(); - - assert_eq!(serialized_json, test_json); - } -} diff --git a/sources/settings-extensions/pki/src/main.rs b/sources/settings-extensions/pki/src/main.rs deleted file mode 100644 index 5fbb2fcc191..00000000000 --- a/sources/settings-extensions/pki/src/main.rs +++ /dev/null @@ -1,18 +0,0 @@ -use bottlerocket_settings_sdk::{BottlerocketSetting, NullMigratorExtensionBuilder}; -use settings_extension_pki::PkiSettingsV1; -use std::process::ExitCode; - -fn main() -> ExitCode { - env_logger::init(); - - match NullMigratorExtensionBuilder::with_name("pki") - .with_models(vec![BottlerocketSetting::::model()]) - .build() - { - Ok(extension) => extension.run(), - Err(e) => { - println!("{}", e); - ExitCode::FAILURE - } - } -} diff --git a/sources/settings-extensions/pki/tests/data/test-pem b/sources/settings-extensions/pki/tests/data/test-pem deleted file mode 100644 index 2e2d530e5cc..00000000000 --- a/sources/settings-extensions/pki/tests/data/test-pem +++ /dev/null @@ -1 +0,0 @@ -LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURVekNDQWp1Z0F3SUJBZ0lVVUNBbXU1MWU1NDZIakpGVEd6Z1BpS2ZxZXVVd0RRWUpLb1pJaHZjTkFRRUwKQlFBd09URVZNQk1HQTFVRUF3d01ZbTkwZEd4bGNtOWphMlYwTVFzd0NRWURWUVFHRXdKVlV6RVRNQkVHQTFVRQpCd3dLVjBGVFNFbE9SMVJQVGpBZUZ3MHlNVEEzTURjeU1UQXhNekJhRncweU5qQTNNRFl5TVRBeE16QmFNRGt4CkZUQVRCZ05WQkFNTURHSnZkSFJzWlhKdlkydGxkREVMTUFrR0ExVUVCaE1DVlZNeEV6QVJCZ05WQkFjTUNsZEIKVTBoSlRrZFVUMDR3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQzErSk5MbllIeApyeGowOTJsQUpwOGRwRlRYbTVpR25jZFRubjBwem1OLzByMWhXUWNLSU9JY1UwcUdlN1h0UkVMcUFPQW5Gb3ZqCktaREV5SjB4eU9TZ1k4NFF6MVdXbUtqSHVsMGZXRHJ0RWlFNU03UklwVXBlVjZwejhOclRoOUFiSEZ1UWFMMkoKWk1COHVRWnFWRUhFZFl0THpFaHhnTU9NMUtjaXVqcjczWVE5TElLYVA3aW5sMU14YWd4c1Y4cjYyZG9WR3g2UwpsT2l3WXVQdmdkNnZWamQ5Wjl1UU5KNHFUdzBVVjBMbGJ1bXZwN2NITHg3U0EzWU55elZBWG0xb2FKYmhKeWpNClJmZEFwZDB3dkc0T1RXd2d5d240N2JPc0pBK3BJMDY0ZlNEeEpIaWxtdGVCSVRmV3hpQ1k2dkFvc01kVHJtRWwKUEFxYzVuem1WRkI3QWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJRZlFJYWh1cFRFMUdaeFBicnhYS3RoVitzTwovekFmQmdOVkhTTUVHREFXZ0JRZlFJYWh1cFRFMUdaeFBicnhYS3RoVitzTy96QVBCZ05WSFJNQkFmOEVCVEFECkFRSC9NQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUFrc1BrNlhMTG5CdVRYK0xtYWJyK0VzcnNOQ2RBYitkOXkKc3Rpc2RDanBrbUtDc2VzSjk2UWdpMDYvMU04OHUvcCtHZHAreEhMUElKVUxyR2owMWoxdXJtRWJxd2lmeFVtawpmSkZ6bW00ZU56UVpqV1gyQm5HOVA4eHlHT1NWaWVHb1RFZW13MlBNT1hodUVFc0o5ckNQSXdzdlhMRzhOQW8yCnNjOGxaNXlOVnZkaHdwemdZL3lvM2pNKzJWeXZ4K2FnTXNhRGs3YmhjOTJGc3ZieTZ2a3ZweC82THZLSGFvSmgKbmxGcUwxcWZEZGZjOU81d1ZqeURyK3Q2NVBlVy9JN2ZCeXpZTEtyMDhIM3JCTzRQRXh0aVJrUHBJcGtEVWNnUAo3eTB6SGd6eVc5dHZNVlBXdXRDTDJ3UE1jb0hpdXJrRnNoOERtQzdzUytMMlNKTG1wbDJoCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KYmFkCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlEVXpDQ0FqdWdBd0lCQWdJVVVDQW11NTFlNTQ2SGpKRlRHemdQaUtmcWV1VXdEUVlKS29aSWh2Y05BUUVMCkJRQXdPVEVWTUJNR0ExVUVBd3dNWW05MGRHeGxjbTlqYTJWME1Rc3dDUVlEVlFRR0V3SlZVekVUTUJFR0ExVUUKQnd3S1YwRlRTRWxPUjFSUFRqQWVGdzB5TVRBM01EY3lNVEF4TXpCYUZ3MHlOakEzTURZeU1UQXhNekJhTURreApGVEFUQmdOVkJBTU1ER0p2ZEhSc1pYSnZZMnRsZERFTE1Ba0dBMVVFQmhNQ1ZWTXhFekFSQmdOVkJBY01DbGRCClUwaEpUa2RVVDA0d2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUUMxK0pOTG5ZSHgKcnhqMDkybEFKcDhkcEZUWG01aUduY2RUbm4wcHptTi8wcjFoV1FjS0lPSWNVMHFHZTdYdFJFTHFBT0FuRm92agpLWkRFeUoweHlPU2dZODRRejFXV21Lakh1bDBmV0RydEVpRTVNN1JJcFVwZVY2cHo4TnJUaDlBYkhGdVFhTDJKClpNQjh1UVpxVkVIRWRZdEx6RWh4Z01PTTFLY2l1anI3M1lROUxJS2FQN2lubDFNeGFneHNWOHI2MmRvVkd4NlMKbE9pd1l1UHZnZDZ2VmpkOVo5dVFOSjRxVHcwVVYwTGxidW12cDdjSEx4N1NBM1lOeXpWQVhtMW9hSmJoSnlqTQpSZmRBcGQwd3ZHNE9UV3dneXduNDdiT3NKQStwSTA2NGZTRHhKSGlsbXRlQklUZld4aUNZNnZBb3NNZFRybUVsClBBcWM1bnptVkZCN0FnTUJBQUdqVXpCUk1CMEdBMVVkRGdRV0JCUWZRSWFodXBURTFHWnhQYnJ4WEt0aFYrc08KL3pBZkJnTlZIU01FR0RBV2dCUWZRSWFodXBURTFHWnhQYnJ4WEt0aFYrc08vekFQQmdOVkhSTUJBZjhFQlRBRApBUUgvTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFBa3NQazZYTExuQnVUWCtMbWFicitFc3JzTkNkQWIrZDl5CnN0aXNkQ2pwa21LQ3Nlc0o5NlFnaTA2LzFNODh1L3ArR2RwK3hITFBJSlVMckdqMDFqMXVybUVicXdpZnhVbWsKZkpGem1tNGVOelFaaldYMkJuRzlQOHh5R09TVmllR29URWVtdzJQTU9YaHVFRXNKOXJDUEl3c3ZYTEc4TkFvMgpzYzhsWjV5TlZ2ZGh3cHpnWS95bzNqTSsyVnl2eCthZ01zYURrN2JoYzkyRnN2Ynk2dmt2cHgvNkx2S0hhb0poCm5sRnFMMXFmRGRmYzlPNXdWanlEcit0NjVQZVcvSTdmQnl6WUxLcjA4SDNyQk80UEV4dGlSa1BwSXBrRFVjZ1AKN3kwekhnenlXOXR2TVZQV3V0Q0wyd1BNY29IaXVya0ZzaDhEbUM3c1MrTDJTSkxtcGwyaAotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== \ No newline at end of file diff --git a/sources/settings-extensions/updates/Cargo.toml b/sources/settings-extensions/updates/Cargo.toml deleted file mode 100644 index effe1e2abed..00000000000 --- a/sources/settings-extensions/updates/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "settings-extension-updates" -version = "0.1.0" -authors = ["Sam Berning "] -license = "Apache-2.0 OR MIT" -edition = "2021" -publish = false - -[dependencies] -env_logger = "0.10" -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -model-derive = { path = "../../models/model-derive", version = "0.1" } -rand = "0.8" -serde = { version = "1", features = ["derive"] } -serde_json = "1" - -[dependencies.bottlerocket-settings-sdk] -git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" -tag = "bottlerocket-settings-sdk-v0.1.0" -version = "0.1.0" diff --git a/sources/settings-extensions/updates/src/generate.rs b/sources/settings-extensions/updates/src/generate.rs deleted file mode 100644 index ffef55999ab..00000000000 --- a/sources/settings-extensions/updates/src/generate.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Generators for updates settings. -use rand::{thread_rng, Rng}; - -pub fn generate_seed() -> u32 { - let mut rng = thread_rng(); - rng.gen_range(0..2048) -} diff --git a/sources/settings-extensions/updates/src/lib.rs b/sources/settings-extensions/updates/src/lib.rs deleted file mode 100644 index c15c95323cc..00000000000 --- a/sources/settings-extensions/updates/src/lib.rs +++ /dev/null @@ -1,94 +0,0 @@ -/// The updates settings can be used to configure settings related to updates, e.g. the -/// seed that determines in which wave the instance will update, etc. -pub mod generate; - -use bottlerocket_settings_sdk::{GenerateResult, SettingsModel}; -use model_derive::model; -use modeled_types::{FriendlyVersion, Url}; -use std::convert::Infallible; - -#[model(impl_default = true)] -pub struct UpdatesSettingsV1 { - metadata_base_url: Url, - targets_base_url: Url, - seed: u32, - // Version to update to when updating via the API. - version_lock: FriendlyVersion, - ignore_waves: bool, -} - -type Result = std::result::Result; - -impl SettingsModel for UpdatesSettingsV1 { - type PartialKind = Self; - type ErrorKind = Infallible; - - fn get_version() -> &'static str { - "v1" - } - - fn set(_current_value: Option, _target: Self) -> Result<()> { - // allow anything that parses as UpdatesSettingsV1 - Ok(()) - } - - fn generate( - existing_partial: Option, - _dependent_settings: Option, - ) -> Result> { - let partial = existing_partial.unwrap_or_default(); - - Ok(GenerateResult::Complete(UpdatesSettingsV1 { - seed: Some(partial.seed.unwrap_or_else(generate::generate_seed)), - ..partial - })) - } - - fn validate(_value: Self, _validated_settings: Option) -> Result<()> { - Ok(()) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_generate_updates() { - if let GenerateResult::Complete(generated_settings) = - UpdatesSettingsV1::generate(None, None).unwrap() - { - assert!(generated_settings.seed.unwrap() < 2048); - assert!(generated_settings.metadata_base_url.is_none()); - assert!(generated_settings.targets_base_url.is_none()); - assert!(generated_settings.version_lock.is_none()); - assert!(generated_settings.ignore_waves.is_none()); - } else { - panic!("generate() should return GenerateResult::Complete") - } - } - - #[test] - fn test_serde_updates() { - let test_json = r#"{ - "metadata-base-url": "https://example.net", - "targets-base-url": "https://example.net", - "seed": 1, - "version-lock": "latest", - "ignore-waves": false - }"#; - - let updates: UpdatesSettingsV1 = serde_json::from_str(test_json).unwrap(); - - assert_eq!( - updates, - UpdatesSettingsV1 { - metadata_base_url: Some(Url::try_from("https://example.net").unwrap()), - targets_base_url: Some(Url::try_from("https://example.net").unwrap()), - seed: Some(1), - version_lock: Some(FriendlyVersion::try_from("latest").unwrap()), - ignore_waves: Some(false), - } - ); - } -} diff --git a/sources/settings-extensions/updates/src/main.rs b/sources/settings-extensions/updates/src/main.rs deleted file mode 100644 index c23f93b54be..00000000000 --- a/sources/settings-extensions/updates/src/main.rs +++ /dev/null @@ -1,18 +0,0 @@ -use bottlerocket_settings_sdk::{BottlerocketSetting, NullMigratorExtensionBuilder}; -use settings_extension_updates::UpdatesSettingsV1; -use std::process::ExitCode; - -fn main() -> ExitCode { - env_logger::init(); - - match NullMigratorExtensionBuilder::with_name("updates") - .with_models(vec![BottlerocketSetting::::model()]) - .build() - { - Ok(extension) => extension.run(), - Err(e) => { - println!("{}", e); - ExitCode::FAILURE - } - } -} diff --git a/sources/settings-extensions/updates/updates.toml b/sources/settings-extensions/updates/updates.toml deleted file mode 100644 index 727dfb274cd..00000000000 --- a/sources/settings-extensions/updates/updates.toml +++ /dev/null @@ -1,13 +0,0 @@ -[extension] -supported-versions = [ - "v1" -] -default-version = "v1" - -[v1] -[v1.validation.cross-validates] - -[v1.templating] -helpers = [] - -[v1.generation.requires] diff --git a/sources/settings-plugins/aws-dev/Cargo.toml b/sources/settings-plugins/aws-dev/Cargo.toml index ae7ad39f223..2b2b52b98f0 100644 --- a/sources/settings-plugins/aws-dev/Cargo.toml +++ b/sources/settings-plugins/aws-dev/Cargo.toml @@ -13,28 +13,14 @@ name = "settings_aws_dev" abi_stable = "0.11.3" serde = "1.0.198" serde_json = "1.0.116" -model-derive = { path = "../../models/model-derive", version = "0.1" } -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -models = { path = "../../models", version = "0.1" } - -# settings extensions -settings-extension-aws = { path = "../../settings-extensions/aws", version = "0.1" } -settings-extension-bootstrap-containers = { path = "../../settings-extensions/bootstrap-containers", version = "0.1" } -settings-extension-cloudformation = { path = "../../settings-extensions/cloudformation", version = "0.1" } -settings-extension-container-registry = { path = "../../settings-extensions/container-registry", version = "0.1" } -settings-extension-dns = { path = "../../settings-extensions/dns", version = "0.1" } -settings-extension-host-containers = { path = "../../settings-extensions/host-containers", version = "0.1" } -settings-extension-kernel = { path = "../../settings-extensions/kernel", version = "0.1" } -settings-extension-metrics = { path = "../../settings-extensions/metrics", version = "0.1" } -settings-extension-motd = { path = "../../settings-extensions/motd", version = "0.1" } -settings-extension-network = { path = "../../settings-extensions/network", version = "0.1" } -settings-extension-ntp = { path = "../../settings-extensions/ntp", version = "0.1" } -settings-extension-oci-hooks = { path = "../../settings-extensions/oci-hooks", version = "0.1" } -settings-extension-pki = { path = "../../settings-extensions/pki", version = "0.1" } -settings-extension-updates = { path = "../../settings-extensions/updates", version = "0.1" } # settings plugins [dependencies.bottlerocket-settings-plugin] git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" tag = "bottlerocket-settings-plugin-v0.1.0" version = "0.1.0" + +[dependencies.bottlerocket-settings-models] +git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" +tag = "bottlerocket-settings-models-v0.1.0" +version = "0.1.0" diff --git a/sources/settings-plugins/aws-dev/src/lib.rs b/sources/settings-plugins/aws-dev/src/lib.rs index f75fe123008..921f298b2b9 100644 --- a/sources/settings-plugins/aws-dev/src/lib.rs +++ b/sources/settings-plugins/aws-dev/src/lib.rs @@ -1,23 +1,22 @@ +use bottlerocket_settings_models::model_derive::model; use bottlerocket_settings_plugin::SettingsPlugin; -use model::BootSettings; -use model_derive::model; #[derive(SettingsPlugin)] #[model(rename = "settings", impl_default = true)] struct AwsDevSettings { - motd: settings_extension_motd::MotdV1, - updates: settings_extension_updates::UpdatesSettingsV1, - host_containers: settings_extension_host_containers::HostContainersSettingsV1, - bootstrap_containers: settings_extension_bootstrap_containers::BootstrapContainersSettingsV1, - ntp: settings_extension_ntp::NtpSettingsV1, - network: settings_extension_network::NetworkSettingsV1, - kernel: settings_extension_kernel::KernelSettingsV1, - boot: BootSettings, - aws: settings_extension_aws::AwsSettingsV1, - metrics: settings_extension_metrics::MetricsSettingsV1, - pki: settings_extension_pki::PkiSettingsV1, - container_registry: settings_extension_container_registry::RegistrySettingsV1, - oci_hooks: settings_extension_oci_hooks::OciHooksSettingsV1, - cloudformation: settings_extension_cloudformation::CloudFormationSettingsV1, - dns: settings_extension_dns::DnsSettingsV1, + motd: bottlerocket_settings_models::MotdV1, + updates: bottlerocket_settings_models::UpdatesSettingsV1, + host_containers: bottlerocket_settings_models::HostContainersSettingsV1, + bootstrap_containers: bottlerocket_settings_models::BootstrapContainersSettingsV1, + ntp: bottlerocket_settings_models::NtpSettingsV1, + network: bottlerocket_settings_models::NetworkSettingsV1, + kernel: bottlerocket_settings_models::KernelSettingsV1, + boot: bottlerocket_settings_models::BootSettingsV1, + aws: bottlerocket_settings_models::AwsSettingsV1, + metrics: bottlerocket_settings_models::MetricsSettingsV1, + pki: bottlerocket_settings_models::PkiSettingsV1, + container_registry: bottlerocket_settings_models::RegistrySettingsV1, + oci_hooks: bottlerocket_settings_models::OciHooksSettingsV1, + cloudformation: bottlerocket_settings_models::CloudFormationSettingsV1, + dns: bottlerocket_settings_models::DnsSettingsV1, } diff --git a/sources/settings-plugins/aws-ecs-1/Cargo.toml b/sources/settings-plugins/aws-ecs-1/Cargo.toml index 3ea2144047b..1a519d0d3f4 100644 --- a/sources/settings-plugins/aws-ecs-1/Cargo.toml +++ b/sources/settings-plugins/aws-ecs-1/Cargo.toml @@ -13,31 +13,14 @@ name = "settings_aws_ecs_1" abi_stable = "0.11.3" serde = "1.0.198" serde_json = "1.0.116" -model-derive = { path = "../../models/model-derive", version = "0.1" } -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -models = { path = "../../models", version = "0.1" } - -# settings extensions -settings-extension-autoscaling = { path = "../../settings-extensions/autoscaling", version = "0.1" } -settings-extension-aws = { path = "../../settings-extensions/aws", version = "0.1" } -settings-extension-bootstrap-containers = { path = "../../settings-extensions/bootstrap-containers", version = "0.1" } -settings-extension-cloudformation = { path = "../../settings-extensions/cloudformation", version = "0.1" } -settings-extension-container-registry = { path = "../../settings-extensions/container-registry", version = "0.1" } -settings-extension-dns = { path = "../../settings-extensions/dns", version = "0.1" } -settings-extension-ecs = { path = "../../settings-extensions/ecs", version = "0.1" } -settings-extension-host-containers = { path = "../../settings-extensions/host-containers", version = "0.1" } -settings-extension-kernel = { path = "../../settings-extensions/kernel", version = "0.1" } -settings-extension-metrics = { path = "../../settings-extensions/metrics", version = "0.1" } -settings-extension-motd = { path = "../../settings-extensions/motd", version = "0.1" } -settings-extension-network = { path = "../../settings-extensions/network", version = "0.1" } -settings-extension-ntp = { path = "../../settings-extensions/ntp", version = "0.1" } -settings-extension-oci-defaults = { path = "../../settings-extensions/oci-defaults", version = "0.1" } -settings-extension-oci-hooks = { path = "../../settings-extensions/oci-hooks", version = "0.1" } -settings-extension-pki = { path = "../../settings-extensions/pki", version = "0.1" } -settings-extension-updates = { path = "../../settings-extensions/updates", version = "0.1" } # settings plugins [dependencies.bottlerocket-settings-plugin] git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" tag = "bottlerocket-settings-plugin-v0.1.0" version = "0.1.0" + +[dependencies.bottlerocket-settings-models] +git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" +tag = "bottlerocket-settings-models-v0.1.0" +version = "0.1.0" diff --git a/sources/settings-plugins/aws-ecs-1/src/lib.rs b/sources/settings-plugins/aws-ecs-1/src/lib.rs index e35c5290aa4..b85d2b47aba 100644 --- a/sources/settings-plugins/aws-ecs-1/src/lib.rs +++ b/sources/settings-plugins/aws-ecs-1/src/lib.rs @@ -1,24 +1,24 @@ +use bottlerocket_settings_models::model_derive::model; use bottlerocket_settings_plugin::SettingsPlugin; -use model_derive::model; #[derive(SettingsPlugin)] #[model(rename = "settings", impl_default = true)] struct AwsEcs1Settings { - motd: settings_extension_motd::MotdV1, - updates: settings_extension_updates::UpdatesSettingsV1, - host_containers: settings_extension_host_containers::HostContainersSettingsV1, - bootstrap_containers: settings_extension_bootstrap_containers::BootstrapContainersSettingsV1, - ntp: settings_extension_ntp::NtpSettingsV1, - network: settings_extension_network::NetworkSettingsV1, - kernel: settings_extension_kernel::KernelSettingsV1, - aws: settings_extension_aws::AwsSettingsV1, - ecs: settings_extension_ecs::ECSSettingsV1, - metrics: settings_extension_metrics::MetricsSettingsV1, - pki: settings_extension_pki::PkiSettingsV1, - container_registry: settings_extension_container_registry::RegistrySettingsV1, - oci_defaults: settings_extension_oci_defaults::OciDefaultsV1, - oci_hooks: settings_extension_oci_hooks::OciHooksSettingsV1, - cloudformation: settings_extension_cloudformation::CloudFormationSettingsV1, - autoscaling: settings_extension_autoscaling::AutoScalingSettingsV1, - dns: settings_extension_dns::DnsSettingsV1, + motd: bottlerocket_settings_models::MotdV1, + updates: bottlerocket_settings_models::UpdatesSettingsV1, + host_containers: bottlerocket_settings_models::HostContainersSettingsV1, + bootstrap_containers: bottlerocket_settings_models::BootstrapContainersSettingsV1, + ntp: bottlerocket_settings_models::NtpSettingsV1, + network: bottlerocket_settings_models::NetworkSettingsV1, + kernel: bottlerocket_settings_models::KernelSettingsV1, + aws: bottlerocket_settings_models::AwsSettingsV1, + ecs: bottlerocket_settings_models::ECSSettingsV1, + metrics: bottlerocket_settings_models::MetricsSettingsV1, + pki: bottlerocket_settings_models::PkiSettingsV1, + container_registry: bottlerocket_settings_models::RegistrySettingsV1, + oci_defaults: bottlerocket_settings_models::OciDefaultsV1, + oci_hooks: bottlerocket_settings_models::OciHooksSettingsV1, + cloudformation: bottlerocket_settings_models::CloudFormationSettingsV1, + autoscaling: bottlerocket_settings_models::AutoScalingSettingsV1, + dns: bottlerocket_settings_models::DnsSettingsV1, } diff --git a/sources/settings-plugins/aws-ecs-2/Cargo.toml b/sources/settings-plugins/aws-ecs-2/Cargo.toml index 4bb8f88eff7..7606dda15a8 100644 --- a/sources/settings-plugins/aws-ecs-2/Cargo.toml +++ b/sources/settings-plugins/aws-ecs-2/Cargo.toml @@ -13,31 +13,14 @@ name = "settings_aws_ecs_2" abi_stable = "0.11.3" serde = "1.0.198" serde_json = "1.0.116" -model-derive = { path = "../../models/model-derive", version = "0.1" } -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -models = { path = "../../models", version = "0.1" } - -# settings extensions -settings-extension-autoscaling = { path = "../../settings-extensions/autoscaling", version = "0.1" } -settings-extension-aws = { path = "../../settings-extensions/aws", version = "0.1" } -settings-extension-bootstrap-containers = { path = "../../settings-extensions/bootstrap-containers", version = "0.1" } -settings-extension-cloudformation = { path = "../../settings-extensions/cloudformation", version = "0.1" } -settings-extension-container-registry = { path = "../../settings-extensions/container-registry", version = "0.1" } -settings-extension-dns = { path = "../../settings-extensions/dns", version = "0.1" } -settings-extension-ecs = { path = "../../settings-extensions/ecs", version = "0.1" } -settings-extension-host-containers = { path = "../../settings-extensions/host-containers", version = "0.1" } -settings-extension-kernel = { path = "../../settings-extensions/kernel", version = "0.1" } -settings-extension-metrics = { path = "../../settings-extensions/metrics", version = "0.1" } -settings-extension-motd = { path = "../../settings-extensions/motd", version = "0.1" } -settings-extension-network = { path = "../../settings-extensions/network", version = "0.1" } -settings-extension-ntp = { path = "../../settings-extensions/ntp", version = "0.1" } -settings-extension-oci-defaults = { path = "../../settings-extensions/oci-defaults", version = "0.1" } -settings-extension-oci-hooks = { path = "../../settings-extensions/oci-hooks", version = "0.1" } -settings-extension-pki = { path = "../../settings-extensions/pki", version = "0.1" } -settings-extension-updates = { path = "../../settings-extensions/updates", version = "0.1" } # settings plugins [dependencies.bottlerocket-settings-plugin] git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" tag = "bottlerocket-settings-plugin-v0.1.0" version = "0.1.0" + +[dependencies.bottlerocket-settings-models] +git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" +tag = "bottlerocket-settings-models-v0.1.0" +version = "0.1.0" diff --git a/sources/settings-plugins/aws-ecs-2/src/lib.rs b/sources/settings-plugins/aws-ecs-2/src/lib.rs index 89b32a3d4fe..56d072f84f1 100644 --- a/sources/settings-plugins/aws-ecs-2/src/lib.rs +++ b/sources/settings-plugins/aws-ecs-2/src/lib.rs @@ -1,26 +1,25 @@ +use bottlerocket_settings_models::model_derive::model; use bottlerocket_settings_plugin::SettingsPlugin; -use model::BootSettings; -use model_derive::model; #[derive(SettingsPlugin)] #[model(rename = "settings", impl_default = true)] struct AwsEcs2Settings { - motd: settings_extension_motd::MotdV1, - updates: settings_extension_updates::UpdatesSettingsV1, - host_containers: settings_extension_host_containers::HostContainersSettingsV1, - bootstrap_containers: settings_extension_bootstrap_containers::BootstrapContainersSettingsV1, - ntp: settings_extension_ntp::NtpSettingsV1, - network: settings_extension_network::NetworkSettingsV1, - kernel: settings_extension_kernel::KernelSettingsV1, - boot: BootSettings, - aws: settings_extension_aws::AwsSettingsV1, - ecs: settings_extension_ecs::ECSSettingsV1, - metrics: settings_extension_metrics::MetricsSettingsV1, - pki: settings_extension_pki::PkiSettingsV1, - container_registry: settings_extension_container_registry::RegistrySettingsV1, - oci_defaults: settings_extension_oci_defaults::OciDefaultsV1, - oci_hooks: settings_extension_oci_hooks::OciHooksSettingsV1, - cloudformation: settings_extension_cloudformation::CloudFormationSettingsV1, - autoscaling: settings_extension_autoscaling::AutoScalingSettingsV1, - dns: settings_extension_dns::DnsSettingsV1, + motd: bottlerocket_settings_models::MotdV1, + updates: bottlerocket_settings_models::UpdatesSettingsV1, + host_containers: bottlerocket_settings_models::HostContainersSettingsV1, + bootstrap_containers: bottlerocket_settings_models::BootstrapContainersSettingsV1, + ntp: bottlerocket_settings_models::NtpSettingsV1, + network: bottlerocket_settings_models::NetworkSettingsV1, + kernel: bottlerocket_settings_models::KernelSettingsV1, + boot: bottlerocket_settings_models::BootSettingsV1, + aws: bottlerocket_settings_models::AwsSettingsV1, + ecs: bottlerocket_settings_models::ECSSettingsV1, + metrics: bottlerocket_settings_models::MetricsSettingsV1, + pki: bottlerocket_settings_models::PkiSettingsV1, + container_registry: bottlerocket_settings_models::RegistrySettingsV1, + oci_defaults: bottlerocket_settings_models::OciDefaultsV1, + oci_hooks: bottlerocket_settings_models::OciHooksSettingsV1, + cloudformation: bottlerocket_settings_models::CloudFormationSettingsV1, + autoscaling: bottlerocket_settings_models::AutoScalingSettingsV1, + dns: bottlerocket_settings_models::DnsSettingsV1, } diff --git a/sources/settings-plugins/aws-k8s/Cargo.toml b/sources/settings-plugins/aws-k8s/Cargo.toml index a3d3ec9f7d5..a3ba64af6c1 100644 --- a/sources/settings-plugins/aws-k8s/Cargo.toml +++ b/sources/settings-plugins/aws-k8s/Cargo.toml @@ -13,31 +13,14 @@ name = "settings_aws_k8s" abi_stable = "0.11.3" serde = "1.0.198" serde_json = "1.0.116" -model-derive = { path = "../../models/model-derive", version = "0.1" } -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -models = { path = "../../models", version = "0.1" } - -# settings extensions -settings-extension-autoscaling = { path = "../../settings-extensions/autoscaling", version = "0.1" } -settings-extension-aws = { path = "../../settings-extensions/aws", version = "0.1" } -settings-extension-bootstrap-containers = { path = "../../settings-extensions/bootstrap-containers", version = "0.1" } -settings-extension-cloudformation = { path = "../../settings-extensions/cloudformation", version = "0.1" } -settings-extension-container-registry = { path = "../../settings-extensions/container-registry", version = "0.1" } -settings-extension-container-runtime = { path = "../../settings-extensions/container-runtime", version = "0.1" } -settings-extension-dns = { path = "../../settings-extensions/dns", version = "0.1" } -settings-extension-host-containers = { path = "../../settings-extensions/host-containers", version = "0.1" } -settings-extension-kernel = { path = "../../settings-extensions/kernel", version = "0.1" } -settings-extension-metrics = { path = "../../settings-extensions/metrics", version = "0.1" } -settings-extension-motd = { path = "../../settings-extensions/motd", version = "0.1" } -settings-extension-network = { path = "../../settings-extensions/network", version = "0.1" } -settings-extension-ntp = { path = "../../settings-extensions/ntp", version = "0.1" } -settings-extension-oci-defaults = { path = "../../settings-extensions/oci-defaults", version = "0.1" } -settings-extension-oci-hooks = { path = "../../settings-extensions/oci-hooks", version = "0.1" } -settings-extension-pki = { path = "../../settings-extensions/pki", version = "0.1" } -settings-extension-updates = { path = "../../settings-extensions/updates", version = "0.1" } # settings plugins [dependencies.bottlerocket-settings-plugin] git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" tag = "bottlerocket-settings-plugin-v0.1.0" version = "0.1.0" + +[dependencies.bottlerocket-settings-models] +git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" +tag = "bottlerocket-settings-models-v0.1.0" +version = "0.1.0" diff --git a/sources/settings-plugins/aws-k8s/src/lib.rs b/sources/settings-plugins/aws-k8s/src/lib.rs index 0ef910c2023..5bd2b2fbf37 100644 --- a/sources/settings-plugins/aws-k8s/src/lib.rs +++ b/sources/settings-plugins/aws-k8s/src/lib.rs @@ -1,27 +1,26 @@ +use bottlerocket_settings_models::model_derive::model; use bottlerocket_settings_plugin::SettingsPlugin; -use model::{BootSettings, KubernetesSettings}; -use model_derive::model; #[derive(SettingsPlugin)] #[model(rename = "settings", impl_default = true)] struct AwsK8sSettings { - motd: settings_extension_motd::MotdV1, - kubernetes: KubernetesSettings, - updates: settings_extension_updates::UpdatesSettingsV1, - host_containers: settings_extension_host_containers::HostContainersSettingsV1, - bootstrap_containers: settings_extension_bootstrap_containers::BootstrapContainersSettingsV1, - ntp: settings_extension_ntp::NtpSettingsV1, - network: settings_extension_network::NetworkSettingsV1, - kernel: settings_extension_kernel::KernelSettingsV1, - boot: BootSettings, - aws: settings_extension_aws::AwsSettingsV1, - metrics: settings_extension_metrics::MetricsSettingsV1, - pki: settings_extension_pki::PkiSettingsV1, - container_registry: settings_extension_container_registry::RegistrySettingsV1, - oci_defaults: settings_extension_oci_defaults::OciDefaultsV1, - oci_hooks: settings_extension_oci_hooks::OciHooksSettingsV1, - cloudformation: settings_extension_cloudformation::CloudFormationSettingsV1, - dns: settings_extension_dns::DnsSettingsV1, - container_runtime: settings_extension_container_runtime::ContainerRuntimeSettingsV1, - autoscaling: settings_extension_autoscaling::AutoScalingSettingsV1, + motd: bottlerocket_settings_models::MotdV1, + kubernetes: bottlerocket_settings_models::KubernetesSettingsV1, + updates: bottlerocket_settings_models::UpdatesSettingsV1, + host_containers: bottlerocket_settings_models::HostContainersSettingsV1, + bootstrap_containers: bottlerocket_settings_models::BootstrapContainersSettingsV1, + ntp: bottlerocket_settings_models::NtpSettingsV1, + network: bottlerocket_settings_models::NetworkSettingsV1, + kernel: bottlerocket_settings_models::KernelSettingsV1, + boot: bottlerocket_settings_models::BootSettingsV1, + aws: bottlerocket_settings_models::AwsSettingsV1, + metrics: bottlerocket_settings_models::MetricsSettingsV1, + pki: bottlerocket_settings_models::PkiSettingsV1, + container_registry: bottlerocket_settings_models::RegistrySettingsV1, + oci_defaults: bottlerocket_settings_models::OciDefaultsV1, + oci_hooks: bottlerocket_settings_models::OciHooksSettingsV1, + cloudformation: bottlerocket_settings_models::CloudFormationSettingsV1, + dns: bottlerocket_settings_models::DnsSettingsV1, + container_runtime: bottlerocket_settings_models::ContainerRuntimeSettingsV1, + autoscaling: bottlerocket_settings_models::AutoScalingSettingsV1, } diff --git a/sources/settings-plugins/metal-dev/Cargo.toml b/sources/settings-plugins/metal-dev/Cargo.toml index 35e0f9b1101..471a95f2b10 100644 --- a/sources/settings-plugins/metal-dev/Cargo.toml +++ b/sources/settings-plugins/metal-dev/Cargo.toml @@ -13,26 +13,14 @@ name = "settings_metal_dev" abi_stable = "0.11.3" serde = "1.0.198" serde_json = "1.0.116" -model-derive = { path = "../../models/model-derive", version = "0.1" } -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -models = { path = "../../models", version = "0.1" } - -# settings extensions -settings-extension-bootstrap-containers = { path = "../../settings-extensions/bootstrap-containers", version = "0.1" } -settings-extension-container-registry = { path = "../../settings-extensions/container-registry", version = "0.1" } -settings-extension-dns = { path = "../../settings-extensions/dns", version = "0.1" } -settings-extension-host-containers = { path = "../../settings-extensions/host-containers", version = "0.1" } -settings-extension-kernel = { path = "../../settings-extensions/kernel", version = "0.1" } -settings-extension-metrics = { path = "../../settings-extensions/metrics", version = "0.1" } -settings-extension-motd = { path = "../../settings-extensions/motd", version = "0.1" } -settings-extension-network = { path = "../../settings-extensions/network", version = "0.1" } -settings-extension-ntp = { path = "../../settings-extensions/ntp", version = "0.1" } -settings-extension-oci-hooks = { path = "../../settings-extensions/oci-hooks", version = "0.1" } -settings-extension-pki = { path = "../../settings-extensions/pki", version = "0.1" } -settings-extension-updates = { path = "../../settings-extensions/updates", version = "0.1" } # settings plugins [dependencies.bottlerocket-settings-plugin] git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" tag = "bottlerocket-settings-plugin-v0.1.0" version = "0.1.0" + +[dependencies.bottlerocket-settings-models] +git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" +tag = "bottlerocket-settings-models-v0.1.0" +version = "0.1.0" diff --git a/sources/settings-plugins/metal-dev/src/lib.rs b/sources/settings-plugins/metal-dev/src/lib.rs index d0e69821bb0..d71c0cd6454 100644 --- a/sources/settings-plugins/metal-dev/src/lib.rs +++ b/sources/settings-plugins/metal-dev/src/lib.rs @@ -1,21 +1,20 @@ +use bottlerocket_settings_models::model_derive::model; use bottlerocket_settings_plugin::SettingsPlugin; -use model::BootSettings; -use model_derive::model; #[derive(SettingsPlugin)] #[model(rename = "settings", impl_default = true)] struct MetalDevSettings { - motd: settings_extension_motd::MotdV1, - updates: settings_extension_updates::UpdatesSettingsV1, - host_containers: settings_extension_host_containers::HostContainersSettingsV1, - bootstrap_containers: settings_extension_bootstrap_containers::BootstrapContainersSettingsV1, - ntp: settings_extension_ntp::NtpSettingsV1, - network: settings_extension_network::NetworkSettingsV1, - kernel: settings_extension_kernel::KernelSettingsV1, - boot: BootSettings, - metrics: settings_extension_metrics::MetricsSettingsV1, - pki: settings_extension_pki::PkiSettingsV1, - container_registry: settings_extension_container_registry::RegistrySettingsV1, - oci_hooks: settings_extension_oci_hooks::OciHooksSettingsV1, - dns: settings_extension_dns::DnsSettingsV1, + motd: bottlerocket_settings_models::MotdV1, + updates: bottlerocket_settings_models::UpdatesSettingsV1, + host_containers: bottlerocket_settings_models::HostContainersSettingsV1, + bootstrap_containers: bottlerocket_settings_models::BootstrapContainersSettingsV1, + ntp: bottlerocket_settings_models::NtpSettingsV1, + network: bottlerocket_settings_models::NetworkSettingsV1, + kernel: bottlerocket_settings_models::KernelSettingsV1, + boot: bottlerocket_settings_models::BootSettingsV1, + metrics: bottlerocket_settings_models::MetricsSettingsV1, + pki: bottlerocket_settings_models::PkiSettingsV1, + container_registry: bottlerocket_settings_models::RegistrySettingsV1, + oci_hooks: bottlerocket_settings_models::OciHooksSettingsV1, + dns: bottlerocket_settings_models::DnsSettingsV1, } diff --git a/sources/settings-plugins/metal-k8s/Cargo.toml b/sources/settings-plugins/metal-k8s/Cargo.toml index ab7d26d9b2b..7413fd2db26 100644 --- a/sources/settings-plugins/metal-k8s/Cargo.toml +++ b/sources/settings-plugins/metal-k8s/Cargo.toml @@ -13,29 +13,14 @@ name = "settings_metal_k8s" abi_stable = "0.11.3" serde = "1.0.198" serde_json = "1.0.116" -model-derive = { path = "../../models/model-derive", version = "0.1" } -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -models = { path = "../../models", version = "0.1" } - -# settings extensions -settings-extension-aws = { path = "../../settings-extensions/aws", version = "0.1" } -settings-extension-bootstrap-containers = { path = "../../settings-extensions/bootstrap-containers", version = "0.1" } -settings-extension-container-registry = { path = "../../settings-extensions/container-registry", version = "0.1" } -settings-extension-container-runtime = { path = "../../settings-extensions/container-runtime", version = "0.1" } -settings-extension-dns = { path = "../../settings-extensions/dns", version = "0.1" } -settings-extension-host-containers = { path = "../../settings-extensions/host-containers", version = "0.1" } -settings-extension-kernel = { path = "../../settings-extensions/kernel", version = "0.1" } -settings-extension-metrics = { path = "../../settings-extensions/metrics", version = "0.1" } -settings-extension-motd = { path = "../../settings-extensions/motd", version = "0.1" } -settings-extension-network = { path = "../../settings-extensions/network", version = "0.1" } -settings-extension-ntp = { path = "../../settings-extensions/ntp", version = "0.1" } -settings-extension-oci-defaults = { path = "../../settings-extensions/oci-defaults", version = "0.1" } -settings-extension-oci-hooks = { path = "../../settings-extensions/oci-hooks", version = "0.1" } -settings-extension-pki = { path = "../../settings-extensions/pki", version = "0.1" } -settings-extension-updates = { path = "../../settings-extensions/updates", version = "0.1" } # settings plugins [dependencies.bottlerocket-settings-plugin] git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" tag = "bottlerocket-settings-plugin-v0.1.0" version = "0.1.0" + +[dependencies.bottlerocket-settings-models] +git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" +tag = "bottlerocket-settings-models-v0.1.0" +version = "0.1.0" diff --git a/sources/settings-plugins/metal-k8s/src/lib.rs b/sources/settings-plugins/metal-k8s/src/lib.rs index ff1f15886c2..3952fe17086 100644 --- a/sources/settings-plugins/metal-k8s/src/lib.rs +++ b/sources/settings-plugins/metal-k8s/src/lib.rs @@ -1,25 +1,24 @@ +use bottlerocket_settings_models::model_derive::model; use bottlerocket_settings_plugin::SettingsPlugin; -use model::{BootSettings, KubernetesSettings}; -use model_derive::model; #[derive(SettingsPlugin)] #[model(rename = "settings", impl_default = true)] struct MetalK8sSettings { - motd: settings_extension_motd::MotdV1, - kubernetes: KubernetesSettings, - updates: settings_extension_updates::UpdatesSettingsV1, - host_containers: settings_extension_host_containers::HostContainersSettingsV1, - bootstrap_containers: settings_extension_bootstrap_containers::BootstrapContainersSettingsV1, - ntp: settings_extension_ntp::NtpSettingsV1, - network: settings_extension_network::NetworkSettingsV1, - kernel: settings_extension_kernel::KernelSettingsV1, - boot: BootSettings, - aws: settings_extension_aws::AwsSettingsV1, - metrics: settings_extension_metrics::MetricsSettingsV1, - pki: settings_extension_pki::PkiSettingsV1, - container_registry: settings_extension_container_registry::RegistrySettingsV1, - oci_defaults: settings_extension_oci_defaults::OciDefaultsV1, - oci_hooks: settings_extension_oci_hooks::OciHooksSettingsV1, - dns: settings_extension_dns::DnsSettingsV1, - container_runtime: settings_extension_container_runtime::ContainerRuntimeSettingsV1, + motd: bottlerocket_settings_models::MotdV1, + kubernetes: bottlerocket_settings_models::KubernetesSettingsV1, + updates: bottlerocket_settings_models::UpdatesSettingsV1, + host_containers: bottlerocket_settings_models::HostContainersSettingsV1, + bootstrap_containers: bottlerocket_settings_models::BootstrapContainersSettingsV1, + ntp: bottlerocket_settings_models::NtpSettingsV1, + network: bottlerocket_settings_models::NetworkSettingsV1, + kernel: bottlerocket_settings_models::KernelSettingsV1, + boot: bottlerocket_settings_models::BootSettingsV1, + aws: bottlerocket_settings_models::AwsSettingsV1, + metrics: bottlerocket_settings_models::MetricsSettingsV1, + pki: bottlerocket_settings_models::PkiSettingsV1, + container_registry: bottlerocket_settings_models::RegistrySettingsV1, + oci_defaults: bottlerocket_settings_models::OciDefaultsV1, + oci_hooks: bottlerocket_settings_models::OciHooksSettingsV1, + dns: bottlerocket_settings_models::DnsSettingsV1, + container_runtime: bottlerocket_settings_models::ContainerRuntimeSettingsV1, } diff --git a/sources/settings-plugins/vmware-dev/Cargo.toml b/sources/settings-plugins/vmware-dev/Cargo.toml index 91cbc5b0124..009c6597026 100644 --- a/sources/settings-plugins/vmware-dev/Cargo.toml +++ b/sources/settings-plugins/vmware-dev/Cargo.toml @@ -13,26 +13,14 @@ name = "settings_vmware_dev" abi_stable = "0.11.3" serde = "1.0.198" serde_json = "1.0.116" -model-derive = { path = "../../models/model-derive", version = "0.1" } -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -models = { path = "../../models", version = "0.1" } - -# settings extensions -settings-extension-bootstrap-containers = { path = "../../settings-extensions/bootstrap-containers", version = "0.1" } -settings-extension-container-registry = { path = "../../settings-extensions/container-registry", version = "0.1" } -settings-extension-dns = { path = "../../settings-extensions/dns", version = "0.1" } -settings-extension-host-containers = { path = "../../settings-extensions/host-containers", version = "0.1" } -settings-extension-kernel = { path = "../../settings-extensions/kernel", version = "0.1" } -settings-extension-metrics = { path = "../../settings-extensions/metrics", version = "0.1" } -settings-extension-motd = { path = "../../settings-extensions/motd", version = "0.1" } -settings-extension-network = { path = "../../settings-extensions/network", version = "0.1" } -settings-extension-ntp = { path = "../../settings-extensions/ntp", version = "0.1" } -settings-extension-oci-hooks = { path = "../../settings-extensions/oci-hooks", version = "0.1" } -settings-extension-pki = { path = "../../settings-extensions/pki", version = "0.1" } -settings-extension-updates = { path = "../../settings-extensions/updates", version = "0.1" } # settings plugins [dependencies.bottlerocket-settings-plugin] git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" tag = "bottlerocket-settings-plugin-v0.1.0" version = "0.1.0" + +[dependencies.bottlerocket-settings-models] +git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" +tag = "bottlerocket-settings-models-v0.1.0" +version = "0.1.0" diff --git a/sources/settings-plugins/vmware-dev/src/lib.rs b/sources/settings-plugins/vmware-dev/src/lib.rs index cee9e62ee7c..03258430e91 100644 --- a/sources/settings-plugins/vmware-dev/src/lib.rs +++ b/sources/settings-plugins/vmware-dev/src/lib.rs @@ -1,21 +1,20 @@ +use bottlerocket_settings_models::model_derive::model; use bottlerocket_settings_plugin::SettingsPlugin; -use model::BootSettings; -use model_derive::model; #[derive(SettingsPlugin)] #[model(rename = "settings", impl_default = true)] struct VmwareDevSettings { - motd: settings_extension_motd::MotdV1, - updates: settings_extension_updates::UpdatesSettingsV1, - host_containers: settings_extension_host_containers::HostContainersSettingsV1, - bootstrap_containers: settings_extension_bootstrap_containers::BootstrapContainersSettingsV1, - ntp: settings_extension_ntp::NtpSettingsV1, - network: settings_extension_network::NetworkSettingsV1, - kernel: settings_extension_kernel::KernelSettingsV1, - boot: BootSettings, - metrics: settings_extension_metrics::MetricsSettingsV1, - pki: settings_extension_pki::PkiSettingsV1, - container_registry: settings_extension_container_registry::RegistrySettingsV1, - oci_hooks: settings_extension_oci_hooks::OciHooksSettingsV1, - dns: settings_extension_dns::DnsSettingsV1, + motd: bottlerocket_settings_models::MotdV1, + updates: bottlerocket_settings_models::UpdatesSettingsV1, + host_containers: bottlerocket_settings_models::HostContainersSettingsV1, + bootstrap_containers: bottlerocket_settings_models::BootstrapContainersSettingsV1, + ntp: bottlerocket_settings_models::NtpSettingsV1, + network: bottlerocket_settings_models::NetworkSettingsV1, + kernel: bottlerocket_settings_models::KernelSettingsV1, + boot: bottlerocket_settings_models::BootSettingsV1, + metrics: bottlerocket_settings_models::MetricsSettingsV1, + pki: bottlerocket_settings_models::PkiSettingsV1, + container_registry: bottlerocket_settings_models::RegistrySettingsV1, + oci_hooks: bottlerocket_settings_models::OciHooksSettingsV1, + dns: bottlerocket_settings_models::DnsSettingsV1, } diff --git a/sources/settings-plugins/vmware-k8s/Cargo.toml b/sources/settings-plugins/vmware-k8s/Cargo.toml index f053f24f574..3e5d470a072 100644 --- a/sources/settings-plugins/vmware-k8s/Cargo.toml +++ b/sources/settings-plugins/vmware-k8s/Cargo.toml @@ -13,29 +13,14 @@ name = "settings_vmware_k8s" abi_stable = "0.11.3" serde = "1.0.198" serde_json = "1.0.116" -model-derive = { path = "../../models/model-derive", version = "0.1" } -modeled-types = { path = "../../models/modeled-types", version = "0.1" } -models = { path = "../../models", version = "0.1" } - -# settings extensions -settings-extension-aws = { path = "../../settings-extensions/aws", version = "0.1" } -settings-extension-bootstrap-containers = { path = "../../settings-extensions/bootstrap-containers", version = "0.1" } -settings-extension-container-registry = { path = "../../settings-extensions/container-registry", version = "0.1" } -settings-extension-container-runtime = { path = "../../settings-extensions/container-runtime", version = "0.1" } -settings-extension-dns = { path = "../../settings-extensions/dns", version = "0.1" } -settings-extension-host-containers = { path = "../../settings-extensions/host-containers", version = "0.1" } -settings-extension-kernel = { path = "../../settings-extensions/kernel", version = "0.1" } -settings-extension-metrics = { path = "../../settings-extensions/metrics", version = "0.1" } -settings-extension-motd = { path = "../../settings-extensions/motd", version = "0.1" } -settings-extension-network = { path = "../../settings-extensions/network", version = "0.1" } -settings-extension-ntp = { path = "../../settings-extensions/ntp", version = "0.1" } -settings-extension-oci-defaults = { path = "../../settings-extensions/oci-defaults", version = "0.1" } -settings-extension-oci-hooks = { path = "../../settings-extensions/oci-hooks", version = "0.1" } -settings-extension-pki = { path = "../../settings-extensions/pki", version = "0.1" } -settings-extension-updates = { path = "../../settings-extensions/updates", version = "0.1" } # settings plugins [dependencies.bottlerocket-settings-plugin] git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" tag = "bottlerocket-settings-plugin-v0.1.0" version = "0.1.0" + +[dependencies.bottlerocket-settings-models] +git = "https://github.com/bottlerocket-os/bottlerocket-settings-sdk" +tag = "bottlerocket-settings-models-v0.1.0" +version = "0.1.0" diff --git a/sources/settings-plugins/vmware-k8s/src/lib.rs b/sources/settings-plugins/vmware-k8s/src/lib.rs index 0c400b1eddf..0b8ee40823e 100644 --- a/sources/settings-plugins/vmware-k8s/src/lib.rs +++ b/sources/settings-plugins/vmware-k8s/src/lib.rs @@ -1,25 +1,24 @@ +use bottlerocket_settings_models::model_derive::model; use bottlerocket_settings_plugin::SettingsPlugin; -use model::{BootSettings, KubernetesSettings}; -use model_derive::model; #[derive(SettingsPlugin)] #[model(rename = "settings", impl_default = true)] struct VmwareK8sSettings { - motd: settings_extension_motd::MotdV1, - kubernetes: KubernetesSettings, - updates: settings_extension_updates::UpdatesSettingsV1, - host_containers: settings_extension_host_containers::HostContainersSettingsV1, - bootstrap_containers: settings_extension_bootstrap_containers::BootstrapContainersSettingsV1, - ntp: settings_extension_ntp::NtpSettingsV1, - network: settings_extension_network::NetworkSettingsV1, - kernel: settings_extension_kernel::KernelSettingsV1, - aws: settings_extension_aws::AwsSettingsV1, - boot: BootSettings, - metrics: settings_extension_metrics::MetricsSettingsV1, - pki: settings_extension_pki::PkiSettingsV1, - container_registry: settings_extension_container_registry::RegistrySettingsV1, - oci_defaults: settings_extension_oci_defaults::OciDefaultsV1, - oci_hooks: settings_extension_oci_hooks::OciHooksSettingsV1, - dns: settings_extension_dns::DnsSettingsV1, - container_runtime: settings_extension_container_runtime::ContainerRuntimeSettingsV1, + motd: bottlerocket_settings_models::MotdV1, + kubernetes: bottlerocket_settings_models::KubernetesSettingsV1, + updates: bottlerocket_settings_models::UpdatesSettingsV1, + host_containers: bottlerocket_settings_models::HostContainersSettingsV1, + bootstrap_containers: bottlerocket_settings_models::BootstrapContainersSettingsV1, + ntp: bottlerocket_settings_models::NtpSettingsV1, + network: bottlerocket_settings_models::NetworkSettingsV1, + kernel: bottlerocket_settings_models::KernelSettingsV1, + aws: bottlerocket_settings_models::AwsSettingsV1, + boot: bottlerocket_settings_models::BootSettingsV1, + metrics: bottlerocket_settings_models::MetricsSettingsV1, + pki: bottlerocket_settings_models::PkiSettingsV1, + container_registry: bottlerocket_settings_models::RegistrySettingsV1, + oci_defaults: bottlerocket_settings_models::OciDefaultsV1, + oci_hooks: bottlerocket_settings_models::OciHooksSettingsV1, + dns: bottlerocket_settings_models::DnsSettingsV1, + container_runtime: bottlerocket_settings_models::ContainerRuntimeSettingsV1, }