diff --git a/README.md b/README.md index cd521dc1e7b..2c7a46e9cda 100644 --- a/README.md +++ b/README.md @@ -164,13 +164,13 @@ apiclient -u /settings This will return all of the current settings in JSON format. For example, here's an abbreviated response: ``` -{"timezone":"America/Los_Angeles","kubernetes":{...}} +{"motd":"...", {"kubernetes": ...}} ``` You can change settings by sending back the same type of JSON data in a PATCH request. This can include any number of settings changes. ``` -apiclient -m PATCH -u /settings -d '{"timezone": "America/Thunder_Bay"}' +apiclient -m PATCH -u /settings -d '{"motd": "my own value!"}' ``` This will *stage* the setting in a "pending" area - a transaction. @@ -204,7 +204,7 @@ Here's the user data to change the time zone setting, as we did in the last sect ``` [settings] -timezone = "America/Thunder_Bay" +motd = "my own value!" ``` ### Description of settings @@ -225,7 +225,7 @@ In this format, "settings.kubernetes.cluster-name" refers to the same key as in #### Top-level settings -* `settings.timezone`, `settings.hostname`: These don't function currently, but are intended to let you override the system timezone or the hostname retrieved from DHCP. At the moment they're used as example settings. +* `settings.motd`: This setting is just written out to /etc/motd. It's useful as a way to get familiar with the API! Try changing it. #### Kubernetes settings diff --git a/Release.toml b/Release.toml index 6e331a7c480..ca0e165fc31 100644 --- a/Release.toml +++ b/Release.toml @@ -1,12 +1,3 @@ -version = "0.2.2" +version = "0.3.0" [migrations] -# Happy path - skip over 0.1, which had an issue with compressed migrations. Normal new migrations go here. -"(0.0, 0.2)" = ["migrate_0.1_borkseed", "migrate_0.1_host-containers-version-migration", "migrate_0.2_containerd-config-path"] -"(0.2, 0.3)" = ["migrate_0.3_remove-region"] -# We don't want to block updating into 0.1 if a user specifically wants the related OS version... -"(0.0, 0.1)" = ["migrate_0.1_borkseed", "migrate_0.1_host-containers-version-migration"] -# ...but to migrate out of the OS with version 0.1 we have to have copies of the migration with the lz4 extension. -# (These filenames are also supported by newer OS versions.) -"(0.1, 0.2)" = ["migrate_0.2_containerd-config-path.lz4"] -"(0.1, 0.3)" = ["migrate_0.2_containerd-config-path.lz4", "migrate_0.3_remove-region.lz4"] diff --git a/packages/os/os.spec b/packages/os/os.spec index ed920cd2614..75f778007a7 100644 --- a/packages/os/os.spec +++ b/packages/os/os.spec @@ -200,7 +200,10 @@ done install -d %{buildroot}%{_cross_datadir}/migrations for version_path in %{_builddir}/sources/api/migration/migrations/*; do + [ -e "${version_path}" ] || continue for migration_path in "${version_path}"/*; do + [ -e "${migration_path}" ] || continue + version="${version_path##*/}" crate_name="${migration_path##*/}" migration_binary_name="migrate_${version}_${crate_name#migrate-}" diff --git a/packages/release/hostname.template b/packages/release/hostname.template deleted file mode 100644 index df561e2718a..00000000000 --- a/packages/release/hostname.template +++ /dev/null @@ -1 +0,0 @@ -{{ settings.hostname }} diff --git a/packages/release/motd.template b/packages/release/motd.template new file mode 100644 index 00000000000..74813dc9fb6 --- /dev/null +++ b/packages/release/motd.template @@ -0,0 +1 @@ +{{ settings.motd }} diff --git a/packages/release/release.spec b/packages/release/release.spec index 8c7656d29ea..7264cc0a4b1 100644 --- a/packages/release/release.spec +++ b/packages/release/release.spec @@ -11,8 +11,7 @@ Source11: nsswitch.conf Source98: release-sysctl.conf Source99: release-tmpfiles.conf -# FIXME What should own system-level file templates? -Source200: hostname.template +Source200: motd.template Source1000: eth0.xml Source1002: configured.target @@ -99,7 +98,7 @@ sed -e 's|PREFIX|%{_cross_prefix}|' %{S:1011} > ${LICENSEPATH}.mount install -p -m 0644 ${LICENSEPATH}.mount %{buildroot}%{_cross_unitdir} install -d %{buildroot}%{_cross_templatedir} -install -p -m 0644 %{S:200} %{buildroot}%{_cross_templatedir}/hostname +install -p -m 0644 %{S:200} %{buildroot}%{_cross_templatedir}/motd %files %{_cross_factorydir}%{_cross_sysconfdir}/hosts @@ -116,6 +115,6 @@ install -p -m 0644 %{S:200} %{buildroot}%{_cross_templatedir}/hostname %{_cross_unitdir}/*-licenses.mount %{_cross_unitdir}/var-lib-bottlerocket.mount %dir %{_cross_templatedir} -%{_cross_templatedir}/hostname +%{_cross_templatedir}/motd %changelog diff --git a/sources/Cargo.lock b/sources/Cargo.lock index 4dc5bb81f2b..6b26cde3508 100644 --- a/sources/Cargo.lock +++ b/sources/Cargo.lock @@ -1502,52 +1502,6 @@ dependencies = [ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "migrate-borkseed" -version = "0.1.0" -dependencies = [ - "migration-helpers 0.1.0", - "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", - "snafu 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "migrate-containerd-config-path" -version = "0.1.0" -dependencies = [ - "migration-helpers 0.1.0", - "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", - "snafu 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "migrate-host-containers-v03" -version = "0.1.0" -dependencies = [ - "migration-helpers 0.1.0", - "schnauzer 0.1.0", - "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", - "snafu 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "migrate-host-containers-version" -version = "0.1.0" -dependencies = [ - "migration-helpers 0.1.0", - "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", - "snafu 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "migrate-remove-region" -version = "0.1.0" -dependencies = [ - "migration-helpers 0.1.0", - "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", - "snafu 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "migration-helpers" version = "0.1.0" diff --git a/sources/Cargo.toml b/sources/Cargo.toml index ebd48cacf1f..4cab59ace46 100644 --- a/sources/Cargo.toml +++ b/sources/Cargo.toml @@ -16,11 +16,7 @@ members = [ "api/migration/migrator", "api/migration/migration-helpers", - "api/migration/migrations/v0.1/migrate-borkseed", - "api/migration/migrations/v0.1/migrate-host-containers-version", - "api/migration/migrations/v0.2/migrate-containerd-config-path", - "api/migration/migrations/v0.2/migrate-remove-region", - "api/migration/migrations/v0.2/migrate-host-containers-v03", + # "api/migration/migrations/vX.Y.Z/... "bottlerocket-release", diff --git a/sources/api/apiclient/README.md b/sources/api/apiclient/README.md index 6aeac21ff8d..e8c9579933d 100644 --- a/sources/api/apiclient/README.md +++ b/sources/api/apiclient/README.md @@ -30,7 +30,7 @@ apiclient -m GET -u /settings Changing settings: ``` -apiclient -X PATCH -u /settings -d '{"timezone": "OldLosAngeles"}' +apiclient -X PATCH -u /settings -d '{"motd": "my own value!"}' apiclient -m POST -u /tx/commit_and_apply ``` diff --git a/sources/api/apiclient/README.tpl b/sources/api/apiclient/README.tpl index 3d28f239fd0..b0009e09e01 100644 --- a/sources/api/apiclient/README.tpl +++ b/sources/api/apiclient/README.tpl @@ -30,7 +30,7 @@ apiclient -m GET -u /settings Changing settings: ``` -apiclient -X PATCH -u /settings -d '{"timezone": "OldLosAngeles"}' +apiclient -X PATCH -u /settings -d '{"motd": "my own value!"}' apiclient -m POST -u /tx/commit_and_apply ``` diff --git a/sources/api/apiserver/src/server/controller.rs b/sources/api/apiserver/src/server/controller.rs index dd4ac68baeb..37993df36dc 100644 --- a/sources/api/apiserver/src/server/controller.rs +++ b/sources/api/apiserver/src/server/controller.rs @@ -381,7 +381,7 @@ mod test { let mut ds = MemoryDataStore::new(); // Set directly with data store ds.set_key( - &Key::new(KeyType::Data, "settings.hostname").unwrap(), + &Key::new(KeyType::Data, "settings.motd").unwrap(), "\"json string\"", &Committed::Live, ) @@ -389,7 +389,7 @@ mod test { // Retrieve with helper let settings = get_settings(&ds, &Committed::Live).unwrap(); - assert_eq!(settings.hostname, Some("json string".try_into().unwrap())); + assert_eq!(settings.motd, Some("json string".try_into().unwrap())); } #[test] @@ -397,7 +397,7 @@ mod test { let mut ds = MemoryDataStore::new(); // Set directly with data store ds.set_key( - &Key::new(KeyType::Data, "settings.timezone").unwrap(), + &Key::new(KeyType::Data, "settings.motd").unwrap(), "\"json string\"", &Committed::Live, ) @@ -405,13 +405,13 @@ mod test { // Retrieve with helper let settings = get_settings_prefix(&ds, "", &Committed::Live).unwrap(); - assert_eq!(settings.timezone, Some("json string".try_into().unwrap())); + assert_eq!(settings.motd, Some("json string".try_into().unwrap())); - let settings = get_settings_prefix(&ds, "tim", &Committed::Live).unwrap(); - assert_eq!(settings.timezone, Some("json string".try_into().unwrap())); + let settings = get_settings_prefix(&ds, "mot", &Committed::Live).unwrap(); + assert_eq!(settings.motd, Some("json string".try_into().unwrap())); - let settings = get_settings_prefix(&ds, "timbits", &Committed::Live).unwrap(); - assert_eq!(settings.timezone, None); + let settings = get_settings_prefix(&ds, "motdxxx", &Committed::Live).unwrap(); + assert_eq!(settings.motd, None); } #[test] @@ -419,14 +419,14 @@ mod test { let mut ds = MemoryDataStore::new(); // Set directly with data store ds.set_key( - &Key::new(KeyType::Data, "settings.timezone").unwrap(), + &Key::new(KeyType::Data, "settings.motd").unwrap(), "\"json string 1\"", &Committed::Live, ) .unwrap(); ds.set_key( - &Key::new(KeyType::Data, "settings.hostname").unwrap(), + &Key::new(KeyType::Data, "settings.ntp.time-servers").unwrap(), "\"json string 2\"", &Committed::Live, ) @@ -434,9 +434,9 @@ mod test { // Retrieve with helper let settings = - get_settings_keys(&ds, &hashset!("settings.timezone"), &Committed::Live).unwrap(); - assert_eq!(settings.timezone, Some("json string 1".try_into().unwrap())); - assert_eq!(settings.hostname, None); + get_settings_keys(&ds, &hashset!("settings.motd"), &Committed::Live).unwrap(); + assert_eq!(settings.motd, Some("json string 1".try_into().unwrap())); + assert_eq!(settings.ntp, None); } #[test] @@ -471,7 +471,7 @@ mod test { #[test] fn set_settings_works() { let mut settings = Settings::default(); - settings.timezone = Some("tz".try_into().unwrap()); + settings.motd = Some("tz".try_into().unwrap()); // Set with helper let mut ds = MemoryDataStore::new(); @@ -480,7 +480,7 @@ mod test { set_settings(&mut ds, &settings, tx).unwrap(); // Retrieve directly - let key = Key::new(KeyType::Data, "settings.timezone").unwrap(); + let key = Key::new(KeyType::Data, "settings.motd").unwrap(); assert_eq!( Some("\"tz\"".to_string()), ds.get_key(&key, &pending).unwrap() @@ -541,7 +541,7 @@ mod test { let tx = "test transaction"; let pending = Committed::Pending { tx: tx.into() }; ds.set_key( - &Key::new(KeyType::Data, "settings.hostname").unwrap(), + &Key::new(KeyType::Data, "settings.motd").unwrap(), "\"json string\"", &pending, ) @@ -549,7 +549,7 @@ mod test { // Confirm pending let settings = get_settings(&ds, &pending).unwrap(); - assert_eq!(settings.hostname, Some("json string".try_into().unwrap())); + assert_eq!(settings.motd, Some("json string".try_into().unwrap())); // No live settings yet get_settings(&ds, &Committed::Live).unwrap_err(); @@ -560,6 +560,6 @@ mod test { get_settings(&ds, &pending).unwrap_err(); // Confirm live let settings = get_settings(&ds, &Committed::Live).unwrap(); - assert_eq!(settings.hostname, Some("json string".try_into().unwrap())); + assert_eq!(settings.motd, Some("json string".try_into().unwrap())); } } diff --git a/sources/api/migration/migration-helpers/src/args.rs b/sources/api/migration/migration-helpers/src/args.rs index 3b96b754c0c..9a9854f543f 100644 --- a/sources/api/migration/migration-helpers/src/args.rs +++ b/sources/api/migration/migration-helpers/src/args.rs @@ -36,7 +36,6 @@ pub(crate) fn parse_args(args: env::Args) -> Result { let mut migration_type = None; let mut source_datastore = None; let mut target_datastore = None; - let mut datastore_path = None; let mut iter = args.skip(1); while let Some(arg) = iter.next() { @@ -55,14 +54,6 @@ pub(crate) fn parse_args(args: env::Args) -> Result { })) } - // Support the argument of the old migrator interface, with some caveats - "--datastore-path" => { - datastore_path = Some( - iter.next() - .unwrap_or_else(|| usage_msg("Did not give argument to --datastore-path")), - ); - } - "--forward" => migration_type = Some(MigrationType::Forward), "--backward" => migration_type = Some(MigrationType::Backward), @@ -70,20 +61,9 @@ pub(crate) fn parse_args(args: env::Args) -> Result { } } - if let Some(datastore_path) = datastore_path { - // For compatibility with old migration interface that had single source+target; other code - // in migration-helpers checks if source==target to see if it needs to do a workaround. - if source_datastore.is_some() || target_datastore.is_some() { - usage_msg("--datastore-path is only for backward compatibility and \ - cannot be used with --source-datastore / --target-datastore"); - } - source_datastore = Some(datastore_path.clone()); - target_datastore = Some(datastore_path); - } else { - // In no other case should they be the same; we use it for compatibility checks. - if source_datastore == target_datastore { - usage_msg("--source-datastore and --target-datastore cannot be the same"); - } + // In no other case should they be the same; we use it for compatibility checks. + if source_datastore == target_datastore { + usage_msg("--source-datastore and --target-datastore cannot be the same"); } Ok(Args { diff --git a/sources/api/migration/migration-helpers/src/lib.rs b/sources/api/migration/migration-helpers/src/lib.rs index dfbb6dddf6e..5f1ea49bab7 100644 --- a/sources/api/migration/migration-helpers/src/lib.rs +++ b/sources/api/migration/migration-helpers/src/lib.rs @@ -15,7 +15,6 @@ mod args; pub mod common_migrations; mod datastore; pub mod error; -mod workarounds; use snafu::ResultExt; use std::collections::HashMap; @@ -28,7 +27,6 @@ pub use apiserver::datastore::{DataStore, FilesystemDataStore}; use args::{parse_args, Args}; use datastore::{get_input_data, set_output_data}; pub use error::Result; -use workarounds::fix_migrated_data; /// The data store implementation currently in use. Used by the simpler `migrate` interface; can /// be overridden by using the `run_migration` interface. @@ -106,15 +104,6 @@ pub fn run_migration(mut migration: impl Migration, args: &Args) -> Result<()> { MigrationType::Backward => migration.backward(migrated), }?; - fix_migrated_data( - &input, - &mut migrated, - &source, - &mut target, - &committed, - &args, - )?; - validate_migrated_data(&migrated)?; set_output_data(&mut target, &migrated, &committed)?; diff --git a/sources/api/migration/migration-helpers/src/workarounds.rs b/sources/api/migration/migration-helpers/src/workarounds.rs deleted file mode 100644 index fb825bf3d59..00000000000 --- a/sources/api/migration/migration-helpers/src/workarounds.rs +++ /dev/null @@ -1,168 +0,0 @@ -use crate::args::Args; -use crate::{error, MigrationData, Result}; -use apiserver::datastore::{Committed, DataStore, Key, KeyType}; -use snafu::ResultExt; -use std::collections::HashSet; - -/// Here we can fix known issues with migrated data, for example issues related to changes -/// in migration interface that we don't want the migrations to have to deal with. -pub(crate) fn fix_migrated_data( - input: &MigrationData, - output: &MigrationData, - _source_datastore: &D, - target_datastore: &mut D, - committed: &Committed, - args: &Args, -) -> Result<()> { - // If the source and target data store path are the same, we're using the old migrator - // interface, and have to use a workaround to be able to delete keys. They can't just be - // removed from the MigrationData struct, because the old interface used the same data store - // for input and output, and removing from MigrationData just means we won't write it out - // again - but the file will still be there from the input. We need to tell the data store - // to remove it. - if args.source_datastore == args.target_datastore { - // Data keys first - let old_keys: HashSet<_> = input.data.keys().collect(); - let new_keys: HashSet<_> = output.data.keys().collect(); - for removed_key_str in old_keys.difference(&new_keys) { - // We need to make a Key from the key's name to fit the data store interface; we - // don't use Key in MigrationData for the convenience of migration authors. - let removed_key = - Key::new(KeyType::Data, removed_key_str).context(error::InvalidKey { - key_type: KeyType::Data, - key: *removed_key_str, - })?; - target_datastore - .unset_key(&removed_key, &committed) - .context(error::DataStoreRemove { - key: *removed_key_str, - })?; - } - - // Now the same thing for metadata - for (data_key_str, old_metadata) in &input.metadata { - let removed: HashSet<_> = if let Some(new_metadata) = output.metadata.get(data_key_str) - { - // Find which metadata keys the migration removed, for this data key - let old_keys: HashSet<_> = old_metadata.keys().collect(); - let new_keys: HashSet<_> = new_metadata.keys().collect(); - old_keys.difference(&new_keys).map(|&s| s).collect() - } else { - // Migration output has no metadata for this data key, so it was all removed - old_metadata.keys().collect() - }; - - for removed_meta_str in removed { - let removed_meta = - Key::new(KeyType::Meta, removed_meta_str).context(error::InvalidKey { - key_type: KeyType::Meta, - key: removed_meta_str, - })?; - let removed_data = - Key::new(KeyType::Data, data_key_str).context(error::InvalidKey { - key_type: KeyType::Data, - key: data_key_str, - })?; - target_datastore - .unset_metadata(&removed_meta, &removed_data) - .context(error::DataStoreRemove { - key: removed_meta_str, - })?; - } - } - } - - Ok(()) -} - -#[cfg(test)] -mod test { - use super::fix_migrated_data; - use crate::datastore::set_output_data; - use crate::{Args, MigrationData, MigrationType}; - use apiserver::datastore::memory::MemoryDataStore; - use apiserver::datastore::{Committed, DataStore, Key, KeyType}; - use maplit::hashmap; - use serde_json::json; - - #[test] - fn test_fix_migrated_data() { - // Data/metadata starting with "remove" should be removed - let input = MigrationData { - data: hashmap!( - "keepdata".into() => json!("hi"), - "removedata".into() => json!("sup"), - ), - metadata: hashmap!( - "keepdata".into() => hashmap!( - "keepmeta".into() => json!("howdy"), - "removemeta".into() => json!("yo"), - ), - "removedata".into() => hashmap!( - "keepmeta".into() => json!("hello"), - "removemeta".into() => json!("hiya"), - ), - ), - }; - // This represents 'input' after a migration removes some data, so it should match the - // data store after we call fix_migrated_data - let expected = MigrationData { - data: hashmap!( - "keepdata".into() => json!("hi"), - ), - metadata: hashmap!( - "keepdata".into() => hashmap!( - "keepmeta".into() => json!("howdy"), - ), - "removedata".into() => hashmap!( - "keepmeta".into() => json!("hello"), - ), - ), - }; - - // The point of the workaround is affecting the data store directly, so make test stores - let mut source = MemoryDataStore::new(); - set_output_data(&mut source, &input, &Committed::Live).unwrap(); - // To replicate old interface, the target data store starts with the input data, and - // we're going to confirm that removed values are actually removed - let mut target = MemoryDataStore::new(); - set_output_data(&mut target, &input, &Committed::Live).unwrap(); - - // Ensure values are there at the start - let kept_data = Key::new(KeyType::Data, "keepdata").unwrap(); - let removed_data = Key::new(KeyType::Data, "removedata").unwrap(); - let kept_meta = Key::new(KeyType::Meta, "keepmeta").unwrap(); - let removed_meta = Key::new(KeyType::Meta, "removemeta").unwrap(); - assert_eq!(target.get_key(&kept_data, &Committed::Live).unwrap(), Some("\"hi\"".into())); - assert_eq!(target.get_key(&removed_data, &Committed::Live).unwrap(), Some("\"sup\"".into())); - assert_eq!(target.get_metadata(&kept_meta, &kept_data).unwrap(), Some("\"howdy\"".into())); - assert_eq!(target.get_metadata(&kept_meta, &removed_data).unwrap(), Some("\"hello\"".into())); - assert_eq!(target.get_metadata(&removed_meta, &kept_data).unwrap(), Some("\"yo\"".into())); - assert_eq!(target.get_metadata(&removed_meta, &removed_data).unwrap(), Some("\"hiya\"".into())); - - // Same source and target, i.e. using old interface, so we should do our fix - let args = Args { - source_datastore: "same".into(), - target_datastore: "same".into(), - migration_type: MigrationType::Forward, - }; - fix_migrated_data( - &input, - &expected, - &source, - &mut target, - &Committed::Live, - &args, - ) - .unwrap(); - - // Ensure unaffected values were kept - assert_eq!(target.get_key(&kept_data, &Committed::Live).unwrap(), Some("\"hi\"".into())); - assert_eq!(target.get_metadata(&kept_meta, &kept_data).unwrap(), Some("\"howdy\"".into())); - assert_eq!(target.get_metadata(&kept_meta, &removed_data).unwrap(), Some("\"hello\"".into())); - // Ensure removed values were removed - assert_eq!(target.get_key(&removed_data, &Committed::Live).unwrap(), None); - assert_eq!(target.get_metadata(&removed_meta, &kept_data).unwrap(), None); - assert_eq!(target.get_metadata(&removed_meta, &removed_data).unwrap(), None); - } -} diff --git a/sources/api/migration/migrations/.keep b/sources/api/migration/migrations/.keep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/sources/api/migration/migrations/v0.1/migrate-borkseed/Cargo.toml b/sources/api/migration/migrations/v0.1/migrate-borkseed/Cargo.toml deleted file mode 100644 index 2f1725bd0ae..00000000000 --- a/sources/api/migration/migrations/v0.1/migrate-borkseed/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "migrate-borkseed" -version = "0.1.0" -authors = ["Tom Kirchner "] -license = "Apache-2.0 OR MIT" -edition = "2018" -publish = false - -[dependencies] -migration-helpers = { path = "../../../migration-helpers" } -serde_json = "1.0" -snafu = "0.6" diff --git a/sources/api/migration/migrations/v0.1/migrate-borkseed/src/main.rs b/sources/api/migration/migrations/v0.1/migrate-borkseed/src/main.rs deleted file mode 100644 index 12f77230560..00000000000 --- a/sources/api/migration/migrations/v0.1/migrate-borkseed/src/main.rs +++ /dev/null @@ -1,95 +0,0 @@ -#![deny(rust_2018_idioms)] - -use migration_helpers::{error, migrate, Migration, MigrationData, Result}; -use std::convert::TryFrom; -use std::process; - -/// We moved from String to u32 for the seed value generated by bork and used by updog. -struct BorkSeedIntMigration; - -impl Migration for BorkSeedIntMigration { - fn forward(&mut self, mut input: MigrationData) -> Result { - if let Some(seed_val) = input.data.get_mut("settings.updates.seed") { - // We have the seed setting; check its type to see what we can do. - if let Some(seed_str) = seed_val.as_str() { - // Confirm the string is a valid u32. - let seed: u32 = seed_str.parse().or_else(|e| { - error::Migration { - msg: format!("Existing update seed string is not a valid u32: {}", e), - } - .fail() - })?; - *seed_val = serde_json::Value::Number(seed.into()); - } else if let Some(seed_num) = seed_val.as_u64() { - // We shouldn't find a number because the migration should only run against a - // version with a String seed, but... as long as it's a valid u32, allow it. - let seed = u32::try_from(seed_num).or_else(|e| { - error::Migration { - msg: format!("Existing update seed number(!) is not a valid u32: {}", e), - } - .fail() - })?; - *seed_val = serde_json::Value::Number(seed.into()); - } else { - // Other type, shouldn't happen, error. - return error::Migration { - msg: format!("Unsupported type of existing update seed: '{:?}'", seed_val), - } - .fail(); - } - } else { - // If they don't have a seed, one will be generated on startup. - } - Ok(input) - } - - fn backward(&mut self, mut input: MigrationData) -> Result { - if let Some(seed_val) = input.data.get_mut("settings.updates.seed") { - // We have the seed setting; check its type to see what we can do. - if let Some(seed_num) = seed_val.as_u64() { - // Number back to string, just serialize. - let seed_str = serde_json::to_string(&seed_num).or_else(|e| { - error::Migration { - msg: format!("Existing update seed number failed serialization: {}", e), - } - .fail() - })?; - *seed_val = serde_json::Value::String(seed_str); - } else if let Some(seed_str) = seed_val.as_str() { - // We shouldn't find a string because the migration should only run against a - // version with a number seed, but... as long as it's a valid u32, allow it. - // JUST FOR VALIDATION: - let _seed: u32 = seed_str.parse().or_else(|e| { - error::Migration { - msg: format!("Existing update seed string(!) is not a valid u32: {}", e), - } - .fail() - })?; - // Do nothing; keep the original (valid) string. - } else { - // Other type, shouldn't happen, error. - return error::Migration { - msg: format!("Unsupported type of existing update seed: '{:?}'", seed_val), - } - .fail(); - } - } else { - // If they don't have a seed, one will be generated on startup. - } - Ok(input) - } -} - -fn run() -> Result<()> { - migrate(BorkSeedIntMigration) -} - -// Returning a Result from main makes it print a Debug representation of the error, but with Snafu -// we have nice Display representations of the error, so we wrap "main" (run) and print any error. -// https://github.com/shepmaster/snafu/issues/110 -fn main() { - if let Err(e) = run() { - eprintln!("{}", e); - process::exit(1); - } -} diff --git a/sources/api/migration/migrations/v0.1/migrate-host-containers-version/Cargo.toml b/sources/api/migration/migrations/v0.1/migrate-host-containers-version/Cargo.toml deleted file mode 100644 index 22d874232a9..00000000000 --- a/sources/api/migration/migrations/v0.1/migrate-host-containers-version/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "migrate-host-containers-version" -version = "0.1.0" -authors = ["Erikson Tung "] -license = "Apache-2.0 OR MIT" -edition = "2018" -publish = false - -[dependencies] -migration-helpers = { path = "../../../migration-helpers" } -serde_json = "1.0" -snafu = "0.6" diff --git a/sources/api/migration/migrations/v0.1/migrate-host-containers-version/src/main.rs b/sources/api/migration/migrations/v0.1/migrate-host-containers-version/src/main.rs deleted file mode 100644 index f2a975f642d..00000000000 --- a/sources/api/migration/migrations/v0.1/migrate-host-containers-version/src/main.rs +++ /dev/null @@ -1,38 +0,0 @@ -#![deny(rust_2018_idioms)] - -use migration_helpers::{migrate, Result}; -use migration_helpers::common_migrations::ReplaceStringMigration; -use std::process; - -const DEFAULT_ADMIN_CTR_IMG_OLD: &str = - "328549459982.dkr.ecr.us-west-2.amazonaws.com/thar-admin:v0.1"; -const DEFAULT_ADMIN_CTR_IMG_NEW: &str = - "328549459982.dkr.ecr.us-west-2.amazonaws.com/thar-admin:v0.2"; -const DEFAULT_CONTROL_CTR_IMG_OLD: &str = - "328549459982.dkr.ecr.us-west-2.amazonaws.com/thar-control:v0.1"; -const DEFAULT_CONTROL_CTR_IMG_NEW: &str = - "328549459982.dkr.ecr.us-west-2.amazonaws.com/thar-control:v0.2"; - -/// We bumped the versions of the default admin container and the default control container from v0.1 to v0.2 -fn run() -> Result<()> { - migrate(ReplaceStringMigration { - setting: "settings.host-containers.admin.source", - old_val: DEFAULT_ADMIN_CTR_IMG_OLD, - new_val: DEFAULT_ADMIN_CTR_IMG_NEW, - })?; - migrate(ReplaceStringMigration { - setting: "settings.host-containers.control.source", - old_val: DEFAULT_CONTROL_CTR_IMG_OLD, - new_val: DEFAULT_CONTROL_CTR_IMG_NEW, - }) -} - -// Returning a Result from main makes it print a Debug representation of the error, but with Snafu -// we have nice Display representations of the error, so we wrap "main" (run) and print any error. -// https://github.com/shepmaster/snafu/issues/110 -fn main() { - if let Err(e) = run() { - eprintln!("{}", e); - process::exit(1); - } -} diff --git a/sources/api/migration/migrations/v0.2/migrate-containerd-config-path/Cargo.toml b/sources/api/migration/migrations/v0.2/migrate-containerd-config-path/Cargo.toml deleted file mode 100644 index ab5e245036f..00000000000 --- a/sources/api/migration/migrations/v0.2/migrate-containerd-config-path/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "migrate-containerd-config-path" -version = "0.1.0" -authors = ["Tom Kirchner "] -license = "Apache-2.0 OR MIT" -edition = "2018" -publish = false - -[dependencies] -migration-helpers = { path = "../../../migration-helpers" } -serde_json = "1.0" -snafu = "0.6" diff --git a/sources/api/migration/migrations/v0.2/migrate-containerd-config-path/src/main.rs b/sources/api/migration/migrations/v0.2/migrate-containerd-config-path/src/main.rs deleted file mode 100644 index f9510b42ae4..00000000000 --- a/sources/api/migration/migrations/v0.2/migrate-containerd-config-path/src/main.rs +++ /dev/null @@ -1,32 +0,0 @@ -#![deny(rust_2018_idioms)] - -use migration_helpers::{migrate, Result}; -use migration_helpers::common_migrations::ReplaceStringMigration; -use std::process; - -const SETTING: &str = "configuration-files.containerd-config-toml.template-path"; -// Old version with no variant -const DEFAULT_CTRD_CONFIG_OLD: &str = "/usr/share/templates/containerd-config-toml"; -// Any users coming from old versions would be using the aws-k8s variant because no other existed :) -const DEFAULT_CTRD_CONFIG_NEW: &str = "/usr/share/templates/containerd-config-toml_aws-k8s"; - -/// We changed the path to our containerd configuration template so that we could support image -/// variants with different configs. We need to update old images to the new path, and on -/// downgrade, new images to the old path. -fn run() -> Result<()> { - migrate(ReplaceStringMigration { - setting: SETTING, - old_val: DEFAULT_CTRD_CONFIG_OLD, - new_val: DEFAULT_CTRD_CONFIG_NEW - }) -} - -// Returning a Result from main makes it print a Debug representation of the error, but with Snafu -// we have nice Display representations of the error, so we wrap "main" (run) and print any error. -// https://github.com/shepmaster/snafu/issues/110 -fn main() { - if let Err(e) = run() { - eprintln!("{}", e); - process::exit(1); - } -} diff --git a/sources/api/migration/migrations/v0.2/migrate-host-containers-v03/Cargo.toml b/sources/api/migration/migrations/v0.2/migrate-host-containers-v03/Cargo.toml deleted file mode 100644 index 170b3a591ba..00000000000 --- a/sources/api/migration/migrations/v0.2/migrate-host-containers-v03/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "migrate-host-containers-v03" -version = "0.1.0" -authors = ["Erikson Tung "] -license = "Apache-2.0 OR MIT" -edition = "2018" -publish = false - -[dependencies] -migration-helpers = { path = "../../../migration-helpers" } -schnauzer = { path = "../../../../schnauzer" } -serde_json = "1.0" -snafu = "0.6" diff --git a/sources/api/migration/migrations/v0.2/migrate-host-containers-v03/src/main.rs b/sources/api/migration/migrations/v0.2/migrate-host-containers-v03/src/main.rs deleted file mode 100644 index 69086146aa2..00000000000 --- a/sources/api/migration/migrations/v0.2/migrate-host-containers-v03/src/main.rs +++ /dev/null @@ -1,39 +0,0 @@ -#![deny(rust_2018_idioms)] - -use migration_helpers::common_migrations::ReplaceTemplateMigration; -use migration_helpers::{migrate, Result}; -use std::process; - -const OLD_ADMIN_CTR_TEMPLATE: &str = - "328549459982.dkr.ecr.{{ settings.aws.region }}.amazonaws.com/thar-admin:v0.2"; -const NEW_ADMIN_CTR_TEMPLATE: &str = - "328549459982.dkr.ecr.{{ settings.aws.region }}.amazonaws.com/bottlerocket-admin:v0.3"; -const OLD_CONTROL_CTR_TEMPLATE: &str = - "328549459982.dkr.ecr.{{ settings.aws.region }}.amazonaws.com/thar-control:v0.2"; -const NEW_CONTROL_CTR_TEMPLATE: &str = - "328549459982.dkr.ecr.{{ settings.aws.region }}.amazonaws.com/bottlerocket-control:v0.3"; - -/// We bumped the versions of the default admin container and the default control container from v0.2 to v0.3 -/// This migration also includes a name change for the host-container images -fn run() -> Result<()> { - migrate(ReplaceTemplateMigration { - setting: "settings.host-containers.admin.source", - old_template: OLD_ADMIN_CTR_TEMPLATE, - new_template: NEW_ADMIN_CTR_TEMPLATE, - })?; - migrate(ReplaceTemplateMigration { - setting: "settings.host-containers.control.source", - old_template: OLD_CONTROL_CTR_TEMPLATE, - new_template: NEW_CONTROL_CTR_TEMPLATE, - }) -} - -// Returning a Result from main makes it print a Debug representation of the error, but with Snafu -// we have nice Display representations of the error, so we wrap "main" (run) and print any error. -// https://github.com/shepmaster/snafu/issues/110 -fn main() { - if let Err(e) = run() { - eprintln!("{}", e); - process::exit(1); - } -} diff --git a/sources/api/migration/migrations/v0.2/migrate-remove-region/Cargo.toml b/sources/api/migration/migrations/v0.2/migrate-remove-region/Cargo.toml deleted file mode 100644 index f92aa74f7ea..00000000000 --- a/sources/api/migration/migrations/v0.2/migrate-remove-region/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "migrate-remove-region" -version = "0.1.0" -authors = ["Tom Kirchner "] -license = "Apache-2.0 OR MIT" -edition = "2018" -publish = false - -[dependencies] -migration-helpers = { path = "../../../migration-helpers" } -serde_json = "1.0" -snafu = "0.6" diff --git a/sources/api/migration/migrations/v0.2/migrate-remove-region/src/main.rs b/sources/api/migration/migrations/v0.2/migrate-remove-region/src/main.rs deleted file mode 100644 index 9f9dcb0071c..00000000000 --- a/sources/api/migration/migrations/v0.2/migrate-remove-region/src/main.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![deny(rust_2018_idioms)] - -use migration_helpers::{migrate, Result}; -use migration_helpers::common_migrations::AddSettingMigration; -use std::process; - -/// We added a generated setting, "settings.aws.region", and want to make sure it's removed before -/// we go back to old versions that don't understand it. -fn run() -> Result<()> { - migrate(AddSettingMigration("settings.aws.region")) -} - -// Returning a Result from main makes it print a Debug representation of the error, but with Snafu -// we have nice Display representations of the error, so we wrap "main" (run) and print any error. -// https://github.com/shepmaster/snafu/issues/110 -fn main() { - if let Err(e) = run() { - eprintln!("{}", e); - process::exit(1); - } -} diff --git a/sources/api/storewolf/src/main.rs b/sources/api/storewolf/src/main.rs index ae3e6d140df..94db763cda8 100644 --- a/sources/api/storewolf/src/main.rs +++ b/sources/api/storewolf/src/main.rs @@ -208,7 +208,7 @@ fn create_new_datastore>(base_path: P, version: Option) // validating the types and structure. The resulting Vec looks like: // // [ -// Metadata {key: "settings.hostname", md: "affected-services", val: Array([ ... ])}, +// Metadata {key: "settings.motd", md: "affected-services", val: Array([ ... ])}, // Metadata { ... }, // ] fn parse_metadata_toml(md_toml_val: toml::Value) -> Result> { @@ -222,7 +222,7 @@ fn parse_metadata_toml(md_toml_val: toml::Value) -> Result> // associated with that key. It ends up looking like: // [ // ( - // ["settings", "hostname"], + // ["settings", "motd"], // toml::Value // ), // ... @@ -259,7 +259,7 @@ fn parse_metadata_toml(md_toml_val: toml::Value) -> Result> msg: "parse_metadata_toml found empty 'path' in the to_process vec - is 'metadata' not a Table?", })?; - // Make sure that the path contains more than 1 item, i.e. ["settings", "hostname"] + // Make sure that the path contains more than 1 item, i.e. ["settings", "motd"] ensure!( path.len() >= 1, error::Internal { diff --git a/sources/api/thar-be-settings/src/service.rs b/sources/api/thar-be-settings/src/service.rs index d234eba477c..9596590dfe6 100644 --- a/sources/api/thar-be-settings/src/service.rs +++ b/sources/api/thar-be-settings/src/service.rs @@ -168,18 +168,17 @@ mod test { #[test] fn test_get_affected_service_names() { let input_map = hashmap!( - "settings.hostname".to_string() => vec![ - "hostname".to_string(), - "timezone".to_string(), + "settings.example".to_string() => vec![ + "example".to_string(), ], "settings.foobar".to_string() => vec![ - "timezone".to_string(), + "example".to_string(), "barbaz".to_string() ] ); let expected_output = - hashset! {"hostname".to_string(), "timezone".to_string(), "barbaz".to_string()}; + hashset! {"example".to_string(), "barbaz".to_string()}; assert_eq!(get_affected_service_names(input_map), expected_output) } diff --git a/sources/models/defaults.toml b/sources/models/defaults.toml index d386bafe04c..90790398824 100644 --- a/sources/models/defaults.toml +++ b/sources/models/defaults.toml @@ -6,23 +6,18 @@ # as defined in src/VARIANT/mod.rs. [settings] -timezone = "America/Los_Angeles" -hostname = "localhost" +motd = "Welcome to Bottlerocket!" -[settings.updates] -metadata-base-url = "https://d25d9m6x9pxh9h.cloudfront.net/45efedef4afe/metadata/" -target-base-url = "https://d25d9m6x9pxh9h.cloudfront.net/45efedef4afe/targets/" +[metadata.settings.motd] +affected-services = ["motd"] -[services.hostname] -configuration-files = ["hostname"] +[services.motd] +configuration-files = ["motd"] restart-commands = [] -[configuration-files.hostname] -path = "/etc/hostname" -template-path = "/usr/share/templates/hostname" - -[metadata.settings.hostname] -affected-services = ["hostname"] +[configuration-files.motd] +path = "/etc/motd" +template-path = "/usr/share/templates/motd" # Container runtime. @@ -34,8 +29,11 @@ restart-commands = [] path = "/etc/containerd/config.toml" template-path = "/usr/share/templates/containerd-config-toml" +# Updates. -# Updog. +[settings.updates] +metadata-base-url = "https://d25d9m6x9pxh9h.cloudfront.net/45efedef4afe/metadata/" +target-base-url = "https://d25d9m6x9pxh9h.cloudfront.net/45efedef4afe/targets/" [services.updog] configuration-files = ["updog-toml"] diff --git a/sources/models/src/aws-dev/mod.rs b/sources/models/src/aws-dev/mod.rs index 73c809a2e84..8baad6cc6f9 100644 --- a/sources/models/src/aws-dev/mod.rs +++ b/sources/models/src/aws-dev/mod.rs @@ -2,15 +2,14 @@ use model_derive::model; use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use crate::modeled_types::{Identifier, SingleLineString}; +use crate::modeled_types::Identifier; use crate::{AwsSettings, ContainerImage, NtpSettings, UpdatesSettings}; // Note: we have to use 'rename' here because the top-level Settings structure is the only one // that uses its name in serialization; internal structures use the field name that points to it #[model(rename = "settings", impl_default = true)] struct Settings { - timezone: SingleLineString, - hostname: SingleLineString, + motd: String, updates: UpdatesSettings, host_containers: HashMap, ntp: NtpSettings, diff --git a/sources/models/src/aws-k8s/mod.rs b/sources/models/src/aws-k8s/mod.rs index a321f53b910..7167fec71bf 100644 --- a/sources/models/src/aws-k8s/mod.rs +++ b/sources/models/src/aws-k8s/mod.rs @@ -2,15 +2,14 @@ use model_derive::model; use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use crate::modeled_types::{Identifier, SingleLineString}; +use crate::modeled_types::Identifier; use crate::{AwsSettings, ContainerImage, KubernetesSettings, NtpSettings, UpdatesSettings}; // Note: we have to use 'rename' here because the top-level Settings structure is the only one // that uses its name in serialization; internal structures use the field name that points to it #[model(rename = "settings", impl_default = true)] struct Settings { - timezone: SingleLineString, - hostname: SingleLineString, + motd: String, kubernetes: KubernetesSettings, updates: UpdatesSettings, host_containers: HashMap, diff --git a/sources/updater/update_metadata/src/se.rs b/sources/updater/update_metadata/src/se.rs index 1ac26624c80..36272594448 100644 --- a/sources/updater/update_metadata/src/se.rs +++ b/sources/updater/update_metadata/src/se.rs @@ -12,7 +12,6 @@ where { let mut map = BTreeMap::new(); for ((from, to), val) in value { - // NOTE: The space in this tuple is required for versions of Bottlerocket < 0.2.0 let key = format!( "({}, {})", serde_plain::to_string(&from).map_err(|e| S::Error::custom(format!( diff --git a/tools/rpm2migrations b/tools/rpm2migrations index e222b05426b..8dd995054b6 100755 --- a/tools/rpm2migrations +++ b/tools/rpm2migrations @@ -2,7 +2,6 @@ # # Retrieve migrations from the RPM and output an appropriately named tarball set -eu -o pipefail -shopt -qs failglob for opt in "$@"; do optarg="$(expr "${opt}" : '[^=]*=\(.*\)')" @@ -30,6 +29,7 @@ fi # lz4 compress each migration for migration in "${MIGRATIONS_DIR}"/*; do + [ -e "${migration}" ] || continue lz4 -v "${migration}" "${migration}.lz4" done