From f1b51d0660789efc281ed78b190b18b4561a6c58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcus=20Sch=C3=A4fer?= Date: Sat, 2 Sep 2023 23:00:22 +0200 Subject: [PATCH] Added support for systemwide flake config Let podman and firecracker pilots read /etc/flakes.yml if present to allow configuration of several general settings. Proper defaults are encoded in case no data is provided --- Makefile | 1 + common/Cargo.toml | 2 + common/src/config.rs | 93 ++++++++++++++++++++++++++++ common/src/defaults.rs | 27 ++++++++ common/src/lib.rs | 2 + firecracker-pilot/src/app_path.rs | 7 +-- firecracker-pilot/src/config.rs | 31 ++++++++-- firecracker-pilot/src/defaults.rs | 4 -- firecracker-pilot/src/firecracker.rs | 7 ++- flakes.yml | 4 ++ package/flake-pilot.spec | 4 ++ podman-pilot/src/config.rs | 30 +++++++-- podman-pilot/src/defaults.rs | 2 - podman-pilot/src/podman.rs | 11 ++-- 14 files changed, 198 insertions(+), 27 deletions(-) create mode 100644 common/src/config.rs create mode 100644 common/src/defaults.rs create mode 100644 flakes.yml diff --git a/Makefile b/Makefile index 1fe91e3..970fa69 100644 --- a/Makefile +++ b/Makefile @@ -33,6 +33,7 @@ sourcetar: rm -rf package/flake-pilot mkdir package/flake-pilot cp Makefile package/flake-pilot + cp flakes.yml package/flake-pilot cp -a common package/flake-pilot/ cp -a podman-pilot package/flake-pilot/ cp -a flake-ctl package/flake-pilot/ diff --git a/common/Cargo.toml b/common/Cargo.toml index 5ba4c38..88c01e5 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -11,6 +11,8 @@ serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", optional = true } log = { version = "0.4" } thiserror = { version = "1.0" } +serde_yaml = { version = "0.9" } +lazy_static = { version = "1.4" } [features] json = ["serde_json"] diff --git a/common/src/config.rs b/common/src/config.rs new file mode 100644 index 0000000..92e998f --- /dev/null +++ b/common/src/config.rs @@ -0,0 +1,93 @@ +// +// Copyright (c) 2023 SUSE Software Solutions Germany GmbH +// +// This file is part of flake-pilot +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +use serde::Deserialize; +use std::path::Path; +use lazy_static::lazy_static; + +use crate::defaults; + +lazy_static! { + static ref FLAKES_CONFIG: FlakesConfig = read_flakes_config(); +} + +pub fn get_flakes_dir() -> String { + let GenericData { flakes_dir, .. } = &flakes_config().generic; + flakes_dir.clone().unwrap_or(defaults::FLAKES_DIR.to_string()) +} + +pub fn get_podman_ids_dir() -> String { + let GenericData { podman_ids_dir, .. } = &flakes_config().generic; + podman_ids_dir.clone().unwrap_or(defaults::PODMAN_IDS_DIR.to_string()) +} + +pub fn get_firecracker_ids_dir() -> String { + let GenericData { firecracker_ids_dir, .. } = &flakes_config().generic; + firecracker_ids_dir.clone().unwrap_or(defaults::FIRECRACKER_IDS_DIR.to_string()) +} + +fn flakes_config() -> &'static FlakesConfig { + &FLAKES_CONFIG +} + +fn read_flakes_config() -> FlakesConfig { + /*! + Read systemwide flakes configuration file + + generic: + flakes_dir: ~ + podman_ids_dir: ~ + firecracker_ids_dir: ~ + !*/ + if Path::new(defaults::FLAKES_CONFIG).exists() { + let flakes_file = std::fs::File::open(defaults::FLAKES_CONFIG) + .unwrap_or_else(|_| panic!("Failed to open {}", defaults::FLAKES_CONFIG)); + serde_yaml::from_reader(flakes_file) + .unwrap_or_else(|error| panic!("Failed to import {}: {}", defaults::FLAKES_CONFIG, error)) + } else { + FlakesConfig { + generic: GenericData { + flakes_dir: None::, + podman_ids_dir: None::, + firecracker_ids_dir: None:: + } + } + } +} + +#[derive(Deserialize)] +struct FlakesConfig { + generic: GenericData, +} + +#[derive(Deserialize)] +struct GenericData { + /// Flakes directory to store registrations + flakes_dir: Option, + + /// ID files directory for podman registrations + podman_ids_dir: Option, + + /// ID files directory for firecracker registrations + firecracker_ids_dir: Option +} diff --git a/common/src/defaults.rs b/common/src/defaults.rs new file mode 100644 index 0000000..5654a39 --- /dev/null +++ b/common/src/defaults.rs @@ -0,0 +1,27 @@ +// +// Copyright (c) 2023 SUSE Software Solutions Germany GmbH +// +// This file is part of flake-pilot +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +pub const FLAKES_CONFIG: &str = "/etc/flakes.yml"; +pub const FLAKES_DIR: &str = "/usr/share/flakes"; +pub const PODMAN_IDS_DIR: &str = "/tmp/flakes"; +pub const FIRECRACKER_IDS_DIR: &str = "/tmp/flakes"; diff --git a/common/src/lib.rs b/common/src/lib.rs index ac11385..60bbf0e 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -28,4 +28,6 @@ pub mod lookup; pub mod user; pub mod command; pub mod error; +pub mod config; pub mod flakelog; +pub mod defaults; diff --git a/firecracker-pilot/src/app_path.rs b/firecracker-pilot/src/app_path.rs index ab50008..f63770b 100644 --- a/firecracker-pilot/src/app_path.rs +++ b/firecracker-pilot/src/app_path.rs @@ -30,8 +30,7 @@ use std::process::exit; use std::fs; use yaml_rust::Yaml; use yaml_rust::YamlLoader; - -use crate::defaults; +use flakes::config::get_flakes_dir; pub fn program_abs_path() -> String { /*! @@ -60,7 +59,7 @@ pub fn program_config_file(program_basename: &String) -> String { Provide expected config file path for the given program_basename !*/ let config_file = &format!( - "{}/{}.yaml", defaults::FIRECRACKER_FLAKE_DIR, program_basename + "{}/{}.yaml", get_flakes_dir(), program_basename ); config_file.to_string() } @@ -70,7 +69,7 @@ pub fn program_config_dir(program_basename: &String) -> String { Provide expected config directory for the given program_basename !*/ let config_dir = &format!( - "{}/{}.d", defaults::FIRECRACKER_FLAKE_DIR, program_basename + "{}/{}.d", get_flakes_dir(), program_basename ); config_dir.to_string() } diff --git a/firecracker-pilot/src/config.rs b/firecracker-pilot/src/config.rs index 5305269..0f1ff8c 100644 --- a/firecracker-pilot/src/config.rs +++ b/firecracker-pilot/src/config.rs @@ -1,11 +1,32 @@ +// +// Copyright (c) 2023 SUSE Software Solutions Germany GmbH +// +// This file is part of flake-pilot +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// use flakes::user::User; use lazy_static::lazy_static; use serde::Deserialize; use strum::Display; - use std::{env, fs, path::PathBuf}; - -use crate::defaults; +use flakes::config::get_flakes_dir; lazy_static! { static ref CONFIG: Config<'static> = load_config(); @@ -72,11 +93,11 @@ fn config_from_str(input: &str) -> Config<'static> { } fn config_file(program: &str) -> String { - format!("{}/{}.yaml", defaults::FIRECRACKER_FLAKE_DIR, program) + format!("{}/{}.yaml", get_flakes_dir(), program) } fn config_dir(program: &str) -> String { - format!("{}/{}.d", defaults::FIRECRACKER_FLAKE_DIR, program) + format!("{}/{}.d", get_flakes_dir(), program) } #[derive(Deserialize)] diff --git a/firecracker-pilot/src/defaults.rs b/firecracker-pilot/src/defaults.rs index 26aa5a5..a0d08cc 100644 --- a/firecracker-pilot/src/defaults.rs +++ b/firecracker-pilot/src/defaults.rs @@ -37,10 +37,6 @@ pub const FIRECRACKER_OVERLAY_DIR:&str = "/var/lib/firecracker/storage"; pub const FIRECRACKER_TEMPLATE:&str = "/etc/flakes/firecracker.json"; -pub const FIRECRACKER_FLAKE_DIR: &str = - "/usr/share/flakes"; -pub const FIRECRACKER_VMID_DIR: &str = - "/var/lib/firecracker/storage/tmp/flakes"; pub const FIRECRACKER_VSOCK_PREFIX: &str = "/run/sci_cmd_"; pub const FIRECRACKER_VSOCK_PORT_START: u32 = 49200; diff --git a/firecracker-pilot/src/firecracker.rs b/firecracker-pilot/src/firecracker.rs index fa0a8db..46c5b24 100644 --- a/firecracker-pilot/src/firecracker.rs +++ b/firecracker-pilot/src/firecracker.rs @@ -39,6 +39,7 @@ use std::io::{Write, SeekFrom, Seek}; use std::fs::File; use serde::{Serialize, Deserialize}; use serde_json::{self}; +use flakes::config::get_firecracker_ids_dir; use crate::defaults; @@ -163,7 +164,7 @@ pub fn create(program_name: &String) -> Result<(String, String), FlakeError> { } // setup VM ID file name let vm_id_file_path = get_meta_file_name( - program_name, defaults::FIRECRACKER_VMID_DIR, "vmid" + program_name, &get_firecracker_ids_dir(), "vmid" ); // get flake config sections @@ -663,7 +664,7 @@ pub fn get_target_app_path( } pub fn init_meta_dirs() -> Result<(), CommandError> { - [defaults::FIRECRACKER_OVERLAY_DIR, defaults::FIRECRACKER_VMID_DIR].iter() + [defaults::FIRECRACKER_OVERLAY_DIR, &get_firecracker_ids_dir()].iter() .filter(|path| !Path::new(path).is_dir()) .try_for_each(|path| mkdir(path, "777", User::ROOT)) } @@ -783,7 +784,7 @@ pub fn gc(user: User, program_name: &String) -> Result<(), FlakeError> { /*! Garbage collect VMID files for which no VM exists anymore !*/ - let vmid_file_names: Vec<_> = fs::read_dir(defaults::FIRECRACKER_VMID_DIR)? + let vmid_file_names: Vec<_> = fs::read_dir(get_firecracker_ids_dir())? .filter_map(|entry| entry.ok()) .filter_map(|x| x.path() .to_str() diff --git a/flakes.yml b/flakes.yml new file mode 100644 index 0000000..14ffce7 --- /dev/null +++ b/flakes.yml @@ -0,0 +1,4 @@ +generic: + flakes_dir: /usr/share/flakes + podman_ids_dir: /tmp + firecracker_ids_dir: /tmp diff --git a/package/flake-pilot.spec b/package/flake-pilot.spec index bcfaec5..09f7000 100644 --- a/package/flake-pilot.spec +++ b/package/flake-pilot.spec @@ -172,10 +172,14 @@ install -m 644 firecracker-pilot/dracut/etc/dracut.conf.d/extramodules.conf \ install -m 755 %{buildroot}/usr/sbin/sci \ %{buildroot}/usr/lib/flake-pilot/sci +mkdir -p %{buildroot}/etc +install -m 644 flakes.yml %{buildroot}/etc/flakes.yml + %files %defattr(-,root,root) %dir /usr/share/flakes %dir /etc/flakes +%config /etc/flakes.yml /usr/bin/flake-ctl %doc /usr/share/man/man8/flake-ctl.8.gz %doc /usr/share/man/man8/flake-ctl-list.8.gz diff --git a/podman-pilot/src/config.rs b/podman-pilot/src/config.rs index 7c113e2..7263de0 100644 --- a/podman-pilot/src/config.rs +++ b/podman-pilot/src/config.rs @@ -1,9 +1,31 @@ +// +// Copyright (c) 2023 SUSE Software Solutions Germany GmbH +// +// This file is part of flake-pilot +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// use flakes::user::User; use lazy_static::lazy_static; use serde::Deserialize; use std::{env, path::PathBuf, fs}; - -use crate::defaults; +use flakes::config::get_flakes_dir; lazy_static! { static ref CONFIG: Config<'static> = load_config(); @@ -68,11 +90,11 @@ fn config_from_str(input: &str) -> Config<'static> { } fn config_file(program: &str) -> String { - format!("{}/{}.yaml", defaults::CONTAINER_FLAKE_DIR, program) + format!("{}/{}.yaml", get_flakes_dir(), program) } fn config_dir(program: &str) -> String { - format!("{}/{}.d", defaults::CONTAINER_FLAKE_DIR, program) + format!("{}/{}.d", get_flakes_dir(), program) } #[derive(Deserialize)] diff --git a/podman-pilot/src/defaults.rs b/podman-pilot/src/defaults.rs index f1c6af4..0234a0a 100644 --- a/podman-pilot/src/defaults.rs +++ b/podman-pilot/src/defaults.rs @@ -21,8 +21,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // -pub const CONTAINER_FLAKE_DIR: &str = "/usr/share/flakes"; pub const CONTAINER_DIR: &str = "/var/lib/containers"; -pub const CONTAINER_CID_DIR: &str = "/var/lib/containers/storage/tmp/flakes"; pub const GC_THRESHOLD: i32 = 20; pub const HOST_DEPENDENCIES: &str = "removed"; diff --git a/podman-pilot/src/podman.rs b/podman-pilot/src/podman.rs index 8c806de..70eb10a 100644 --- a/podman-pilot/src/podman.rs +++ b/podman-pilot/src/podman.rs @@ -36,6 +36,7 @@ use std::io::{Write, Read}; use std::fs::File; use std::io::Seek; use std::io::SeekFrom; +use flakes::config::get_podman_ids_dir; use crate::defaults; @@ -120,7 +121,7 @@ pub fn create( // setup container ID file name let suffix = name.first().map(String::as_str).unwrap_or(""); - let container_cid_file = format!("{}/{}{suffix}.cid", defaults::CONTAINER_CID_DIR, program_name); + let container_cid_file = format!("{}/{}{suffix}.cid", get_podman_ids_dir(), program_name); // setup app command path name to call let target_app_path = get_target_app_path(program_name); @@ -494,9 +495,9 @@ pub fn init_cid_dir() -> Result<(), FlakeError> { /*! Create meta data directory structure !*/ - if ! Path::new(defaults::CONTAINER_CID_DIR).is_dir() { + if ! Path::new(&get_podman_ids_dir()).is_dir() { chmod(defaults::CONTAINER_DIR, "755", User::ROOT)?; - mkdir(defaults::CONTAINER_CID_DIR, "777", User::ROOT)?; + mkdir(&get_podman_ids_dir(), "777", User::ROOT)?; } Ok(()) } @@ -607,13 +608,13 @@ pub fn gc(user: User) -> Result<(), FlakeError> { let mut cid_file_names: Vec = Vec::new(); let mut cid_file_count: i32 = 0; let paths; - match fs::read_dir(defaults::CONTAINER_CID_DIR) { + match fs::read_dir(get_podman_ids_dir()) { Ok(result) => { paths = result }, Err(error) => { return Err(FlakeError::IOError { kind: format!("{:?}", error.kind()), message: format!("fs::read_dir failed on {}: {}", - defaults::CONTAINER_CID_DIR, error + get_podman_ids_dir(), error ) }) }