diff --git a/Release.toml b/Release.toml index d5f6de186b4..0c0d5e65487 100644 --- a/Release.toml +++ b/Release.toml @@ -1,4 +1,4 @@ -version = "1.19.1" +version = "1.20.0" [migrations] "(0.3.1, 0.3.2)" = ["migrate_v0.3.2_admin-container-v0-5-0.lz4"] @@ -270,3 +270,7 @@ version = "1.19.1" "migrate_v1.19.1_aws-control-container-v0-7-8.lz4", "migrate_v1.19.1_public-control-container-v0-7-8.lz4", ] +"(1.19.1, 1.20.0)" = [ + "migrate_v1.20.0_prairiedog-config-file-v0-1-0.lz4", + "migrate_v1.20.0_prairiedog-services-cfg-v0-1-0.lz4" +] diff --git a/Twoliter.toml b/Twoliter.toml index c031b2d1152..0d81797a3c6 100644 --- a/Twoliter.toml +++ b/Twoliter.toml @@ -1,5 +1,5 @@ schema-version = 1 -release-version = "1.19.1" +release-version = "1.20.0" [sdk] registry = "public.ecr.aws/bottlerocket" diff --git a/packages/os/os.spec b/packages/os/os.spec index 477c895a023..52b5e7b3f73 100644 --- a/packages/os/os.spec +++ b/packages/os/os.spec @@ -31,6 +31,7 @@ Source12: 00-resolved.conf %if %{with k8s_runtime} Source13: cis-checks-k8s-metadata-json %endif +Source15: prairiedog-toml # 1xx sources: systemd units Source100: apiserver.service @@ -472,7 +473,7 @@ install -d %{buildroot}%{_cross_datadir}/updog install -p -m 0644 %{_cross_repo_root_json} %{buildroot}%{_cross_datadir}/updog install -d %{buildroot}%{_cross_templatedir} -install -p -m 0644 %{S:5} %{S:6} %{S:7} %{S:8} %{buildroot}%{_cross_templatedir} +install -p -m 0644 %{S:5} %{S:6} %{S:7} %{S:8} %{S:15} %{buildroot}%{_cross_templatedir} install -d %{buildroot}%{_cross_unitdir} install -p -m 0644 \ @@ -681,6 +682,7 @@ install -p -m 0644 %{S:400} %{S:401} %{S:402} %{buildroot}%{_cross_licensedir} %files -n %{_cross_os}prairiedog %{_cross_bindir}/prairiedog %{_cross_unitdir}/reboot-if-required.service +%{_cross_templatedir}/prairiedog-toml %files -n %{_cross_os}certdog %{_cross_bindir}/certdog diff --git a/packages/os/prairiedog-toml b/packages/os/prairiedog-toml new file mode 100644 index 00000000000..57e630357b8 --- /dev/null +++ b/packages/os/prairiedog-toml @@ -0,0 +1,22 @@ +[required-extensions] +boot = "v1" ++++ +{{#if settings.boot}} +{{#if settings.boot.reboot-to-reconcile}} +reboot-to-reconcile = {{settings.boot.reboot-to-reconcile}} +{{/if}} + +{{#if settings.boot.kernel}} +[kernel] +{{#each settings.boot.kernel}} +"{{@key}}" = [ {{#each this}}"{{this}}",{{/each}} ] +{{/each}} +{{/if}} + +{{#if settings.boot.init}} +[init] +{{#each settings.boot.init}} +"{{@key}}" = [ {{#each this}}"{{this}}",{{/each}} ] +{{/each}} +{{/if}} +{{/if}} diff --git a/sources/Cargo.lock b/sources/Cargo.lock index af7a4af03ee..d01fcb4c264 100644 --- a/sources/Cargo.lock +++ b/sources/Cargo.lock @@ -3094,7 +3094,21 @@ dependencies = [ "signpost", "simplelog", "snafu", - "tokio", + "toml 0.8.8", +] + +[[package]] +name = "prairiedog-config-file-v0-1-0" +version = "0.1.0" +dependencies = [ + "migration-helpers", +] + +[[package]] +name = "prairiedog-services-cfg-v0-1-0" +version = "0.1.0" +dependencies = [ + "migration-helpers", ] [[package]] diff --git a/sources/Cargo.toml b/sources/Cargo.toml index e696d67a2c3..6def090dff4 100644 --- a/sources/Cargo.toml +++ b/sources/Cargo.toml @@ -61,6 +61,8 @@ members = [ "api/migration/migrations/v1.19.1/public-admin-container-v0-11-4", "api/migration/migrations/v1.19.1/aws-control-container-v0-7-8", "api/migration/migrations/v1.19.1/public-control-container-v0-7-8", + "api/migration/migrations/v1.20.0/prairiedog-config-file-v0-1-0", + "api/migration/migrations/v1.20.0/prairiedog-services-cfg-v0-1-0", "bloodhound", diff --git a/sources/api/migration/migrations/v1.20.0/prairiedog-config-file-v0-1-0/Cargo.toml b/sources/api/migration/migrations/v1.20.0/prairiedog-config-file-v0-1-0/Cargo.toml new file mode 100644 index 00000000000..524c7e687cd --- /dev/null +++ b/sources/api/migration/migrations/v1.20.0/prairiedog-config-file-v0-1-0/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "prairiedog-config-file-v0-1-0" +version = "0.1.0" +authors = ["Jarrett Tierney "] +license = "Apache-2.0 OR MIT" +edition = "2021" +publish = false +exclude = ["README.md"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +migration-helpers = { path = "../../../migration-helpers", version = "0.1.0" } diff --git a/sources/api/migration/migrations/v1.20.0/prairiedog-config-file-v0-1-0/src/main.rs b/sources/api/migration/migrations/v1.20.0/prairiedog-config-file-v0-1-0/src/main.rs new file mode 100644 index 00000000000..7d89c43fb38 --- /dev/null +++ b/sources/api/migration/migrations/v1.20.0/prairiedog-config-file-v0-1-0/src/main.rs @@ -0,0 +1,16 @@ +use migration_helpers::common_migrations::AddPrefixesMigration; +use migration_helpers::{migrate, Result}; +use std::process; + +fn run() -> Result<()> { + migrate(AddPrefixesMigration(vec![ + "configuration-files.prairiedog-toml", + ])) +} + +fn main() { + if let Err(e) = run() { + eprintln!("{}", e); + process::exit(1); + } +} diff --git a/sources/api/migration/migrations/v1.20.0/prairiedog-services-cfg-v0-1-0/Cargo.toml b/sources/api/migration/migrations/v1.20.0/prairiedog-services-cfg-v0-1-0/Cargo.toml new file mode 100644 index 00000000000..44d43d76497 --- /dev/null +++ b/sources/api/migration/migrations/v1.20.0/prairiedog-services-cfg-v0-1-0/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "prairiedog-services-cfg-v0-1-0" +version = "0.1.0" +authors = ["Jarrett Tierney "] +license = "Apache-2.0 OR MIT" +edition = "2021" +publish = false +exclude = ["README.md"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +migration-helpers = { path = "../../../migration-helpers", version = "0.1.0" } diff --git a/sources/api/migration/migrations/v1.20.0/prairiedog-services-cfg-v0-1-0/src/main.rs b/sources/api/migration/migrations/v1.20.0/prairiedog-services-cfg-v0-1-0/src/main.rs new file mode 100644 index 00000000000..391529368df --- /dev/null +++ b/sources/api/migration/migrations/v1.20.0/prairiedog-services-cfg-v0-1-0/src/main.rs @@ -0,0 +1,18 @@ +use migration_helpers::common_migrations::{ListReplacement, ReplaceListsMigration}; +use migration_helpers::{migrate, Result}; +use std::process; + +fn run() -> Result<()> { + migrate(ReplaceListsMigration(vec![ListReplacement { + setting: "services.bootconfig.configuration-files", + old_vals: &[], + new_vals: &["prairiedog-toml"], + }])) +} + +fn main() { + if let Err(e) = run() { + eprintln!("{}", e); + process::exit(1); + } +} diff --git a/sources/api/prairiedog/Cargo.toml b/sources/api/prairiedog/Cargo.toml index 173afd5b3fc..eef75aeb3f6 100644 --- a/sources/api/prairiedog/Cargo.toml +++ b/sources/api/prairiedog/Cargo.toml @@ -20,7 +20,7 @@ signpost = { path = "../../updater/signpost", version = "0.1" } simplelog = "0.12" snafu = "0.7" serde_json = "1" -tokio = { version = "~1.32", default-features = false, features = ["macros", "rt-multi-thread"] } # LTS +toml = "0.8" [dev-dependencies] maplit = "1" diff --git a/sources/api/prairiedog/src/bootconfig.rs b/sources/api/prairiedog/src/bootconfig.rs index 0c3a9846a46..b6320eb94dd 100644 --- a/sources/api/prairiedog/src/bootconfig.rs +++ b/sources/api/prairiedog/src/bootconfig.rs @@ -6,8 +6,8 @@ use model::BootSettings; use snafu::{ensure, ResultExt}; use std::collections::HashMap; use std::convert::TryInto; +use std::{fs, io}; use std::path::Path; -use tokio::io; // Boot config related consts const BOOTCONFIG_INITRD_PATH: &str = "/var/lib/bottlerocket/bootconfig.data"; @@ -66,11 +66,11 @@ fn serialize_boot_settings_to_boot_config(boot_settings: &BootSettings) -> Resul } /// Queries Bottlerocket boot settings and generates initrd image file with boot config as the only data -pub(crate) async fn generate_boot_config

(socket_path: P) -> Result<()> +pub(crate) fn generate_boot_config

(config_path: P) -> Result<()> where P: AsRef, { - let bootconfig_bytes = match get_boot_config_settings(socket_path).await? { + let bootconfig_bytes = match get_boot_config_settings(config_path)? { Some(boot_settings) => { info!("Generating initrd boot config from boot settings"); trace!("Boot settings: {:?}", boot_settings); @@ -86,36 +86,25 @@ where }; let initrd = generate_initrd(&bootconfig_bytes)?; trace!("Writing initrd image file: {:?}", initrd); - tokio::fs::write(BOOTCONFIG_INITRD_PATH, &initrd) - .await - .context(error::WriteInitrdSnafu)?; + fs::write(BOOTCONFIG_INITRD_PATH, &initrd).context(error::WriteInitrdSnafu)?; Ok(()) } /// Retrieves boot config related Bottlerocket settings. If they don't exist in the settings model, /// we return `None` instead. -async fn get_boot_config_settings

(socket_path: P) -> Result> +fn get_boot_config_settings

(config_path: P) -> Result> where P: AsRef, { - let uri = "/settings"; - let settings: serde_json::Value = - schnauzer::v1::get_json(socket_path, uri, Some(("prefix", "boot"))) - .await - .context(error::RetrieveSettingsSnafu)?; - - match settings.get("boot") { - None => Ok(None), - Some(boot_settings_val) => Ok(Some( - serde_json::from_value(boot_settings_val.to_owned()) - .context(error::BootSettingsFromJsonValueSnafu)?, - )), - } + let config_str = fs::read_to_string(config_path.as_ref()).context(error::ReadFileSnafu { + path: config_path.as_ref().to_path_buf(), + })?; + toml::from_str(config_str.as_str()).context(error::InputTomlSnafu) } /// Reads `/proc/bootconfig`. Not having any boot config is ignored. -async fn read_proc_bootconfig() -> Result> { - match tokio::fs::read_to_string(PROC_BOOTCONFIG).await { +fn read_proc_bootconfig() -> Result> { + match fs::read_to_string(PROC_BOOTCONFIG) { Ok(s) => Ok(Some(s)), Err(e) => { // If there's no `/proc/bootconfig`, then the user hasn't provisioned any kernel boot configuration. @@ -131,8 +120,8 @@ async fn read_proc_bootconfig() -> Result> { } /// Reads `/proc/bootconfig` and populates the Bottlerocket boot settings based on the existing boot config data -pub(crate) async fn generate_boot_settings() -> Result<()> { - if let Some(proc_bootconfig) = read_proc_bootconfig().await? { +pub(crate) fn generate_boot_settings() -> Result<()> { + if let Some(proc_bootconfig) = read_proc_bootconfig()? { debug!( "Generating kernel boot config settings from `{}`", PROC_BOOTCONFIG @@ -275,18 +264,16 @@ fn boot_config_to_boot_settings_json(bootconfig_str: &str) -> Result { } /// Decides whether the host should be rebooted to have its boot settings take effect -pub(crate) async fn is_reboot_required

(socket_path: P) -> Result +pub(crate) fn is_reboot_required

(config_path: P) -> Result where P: AsRef, { - let old_boot_settings = match read_proc_bootconfig().await? { + let old_boot_settings = match read_proc_bootconfig()? { Some(proc_bootconfig) => parse_boot_config_to_boot_settings(&proc_bootconfig)?, None => DEFAULT_BOOT_SETTINGS, }; - let new_boot_settings = get_boot_config_settings(socket_path) - .await? - .unwrap_or(DEFAULT_BOOT_SETTINGS); + let new_boot_settings = get_boot_config_settings(config_path)?.unwrap_or(DEFAULT_BOOT_SETTINGS); let reboot_required = if new_boot_settings.reboot_to_reconcile.unwrap_or(false) { boot_settings_change_requires_reboot(&old_boot_settings, &new_boot_settings) diff --git a/sources/api/prairiedog/src/error.rs b/sources/api/prairiedog/src/error.rs index 690d364f960..c1c733dcdc1 100644 --- a/sources/api/prairiedog/src/error.rs +++ b/sources/api/prairiedog/src/error.rs @@ -56,9 +56,6 @@ pub(super) enum Error { path: PathBuf, }, - #[snafu(display("Failed to retrieve settings: {}", source))] - RetrieveSettings { source: schnauzer::v1::Error }, - #[snafu(display("Failed to convert usize to u32: {}", source))] UsizeToU32 { source: std::num::TryFromIntError }, @@ -68,12 +65,12 @@ pub(super) enum Error { #[snafu(display("Failed to write initrd image file: {}", source))] WriteInitrd { source: std::io::Error }, + #[snafu(display("Error deserializing `BootSettings` from TOML: {}", source))] + InputToml { source: toml::de::Error }, + #[snafu(display("Error serializing `BootSettings` to JSON: {}", source))] OutputJson { source: serde_json::error::Error }, - #[snafu(display("Failed to deserialize `BootSettings` from JSON value: {}", source))] - BootSettingsFromJsonValue { source: serde_json::error::Error }, - #[snafu(display( "Invalid boot config file, expected key-value, or key entries for each line" ))] diff --git a/sources/api/prairiedog/src/main.rs b/sources/api/prairiedog/src/main.rs index 0d22ace7cd9..bae875f4786 100644 --- a/sources/api/prairiedog/src/main.rs +++ b/sources/api/prairiedog/src/main.rs @@ -20,7 +20,7 @@ use simplelog::{Config as LogConfig, LevelFilter, SimpleLogger, WriteLogger}; use snafu::{ensure, ResultExt}; use std::ffi::OsStr; use std::fs::{self, File}; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::process::{self, Command}; use std::thread; use std::time::Duration; @@ -29,6 +29,8 @@ mod bootconfig; mod error; mod initrd; +// Prairie dog config path +const DEFAULT_CONFIG_FILE: &str = "/etc/prairiedog.toml"; // Kdump related binary paths const MAKEDUMPFILE_PATH: &str = "/sbin/makedumpfile"; const KEXEC_PATH: &str = "/sbin/kexec"; @@ -60,9 +62,9 @@ struct Args { #[argh(option, default = "LevelFilter::Info", short = 'l')] /// log-level trace|debug|info|warn|error log_level: LevelFilter, - #[argh(option, default = "constants::API_SOCKET.to_string()", short = 's')] - /// socket-path path to apiserver socket - socket_path: String, + #[argh(option, default = "PathBuf::from(DEFAULT_CONFIG_FILE)", short = 'c')] + /// config-path to provide alternate config file path + config_path: PathBuf, #[argh(subcommand)] subcommand: Subcommand, } @@ -283,11 +285,11 @@ fn load_crash_kernel() -> Result<()> { Ok(()) } -async fn reboot_if_required

(socket_path: P) -> Result<()> +fn reboot_if_required

(config_path: P) -> Result<()> where P: AsRef, { - if is_reboot_required(socket_path).await? { + if is_reboot_required(config_path)? { info!("Boot settings changed and require a reboot to take effect. Initiating reboot..."); command("/usr/bin/systemctl", ["reboot"])?; // The "systemctl reboot" process will not block until the host does @@ -333,7 +335,7 @@ fn setup_logger(args: &Args) -> Result<()> { Ok(()) } -async fn run() -> Result<()> { +fn run() -> Result<()> { let args: Args = argh::from_env(); setup_logger(&args)?; @@ -341,15 +343,14 @@ async fn run() -> Result<()> { Subcommand::CaptureDump(_) => capture_dump(), Subcommand::PrepareBoot(_) => prepare_boot(), Subcommand::LoadCrashKernel(_) => load_crash_kernel(), - Subcommand::GenerateBootConfig(_) => generate_boot_config(args.socket_path).await, - Subcommand::GenerateBootSettings(_) => generate_boot_settings().await, - Subcommand::RebootIfRequired(_) => reboot_if_required(args.socket_path).await, + Subcommand::GenerateBootConfig(_) => generate_boot_config(args.config_path), + Subcommand::GenerateBootSettings(_) => generate_boot_settings(), + Subcommand::RebootIfRequired(_) => reboot_if_required(args.config_path), } } -#[tokio::main] -async fn main() { - if let Err(e) = run().await { +fn main() { + if let Err(e) = run() { error!("{}", e); process::exit(1); } diff --git a/sources/models/shared-defaults/boot.toml b/sources/models/shared-defaults/boot.toml index f3d39dd4778..abf4ad53535 100644 --- a/sources/models/shared-defaults/boot.toml +++ b/sources/models/shared-defaults/boot.toml @@ -5,5 +5,9 @@ affected-services = ["bootconfig"] setting-generator = "/usr/bin/prairiedog generate-boot-settings" [services.bootconfig] -configuration-files = [] +configuration-files = ["prairiedog-toml"] restart-commands = ["/usr/bin/prairiedog generate-boot-config"] + +[configuration-files.prairiedog-toml] +path = "/etc/prairiedog.toml" +template-path = "/usr/share/templates/prairiedog-toml"