From ef5723b9dbadf4c6f4a5d5d7936991bf0c328dbb Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Thu, 20 Jan 2022 12:05:52 -0500 Subject: [PATCH] rust/treefile: Support creating client from /etc dropins Add support for creating a client treefile based on the dropins in `/etc/rpm-ostree/origin.d`. This will currently be used only by the container flow, but could eventually also end up being used client-side as discussed in #2326. --- rust/src/lib.rs | 1 + rust/src/treefile.rs | 49 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/rust/src/lib.rs b/rust/src/lib.rs index c48a1560ee..4ee4c8cf12 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -392,6 +392,7 @@ pub mod ffi { workdir: i32, ) -> Result>; fn treefile_new_client(filename: &str, basearch: &str) -> Result>; + fn treefile_new_client_from_etc(basearch: &str) -> Result>; fn get_workdir(&self) -> i32; fn get_passwd_fd(&mut self) -> i32; diff --git a/rust/src/treefile.rs b/rust/src/treefile.rs index b064e456aa..daeaa82c60 100644 --- a/rust/src/treefile.rs +++ b/rust/src/treefile.rs @@ -28,11 +28,11 @@ use ostree_ext::{glib, ostree}; use serde_derive::{Deserialize, Serialize}; use std::collections::btree_map::Entry; use std::collections::{BTreeMap, HashMap, HashSet}; -use std::fs::File; +use std::fs::{read_dir, File}; use std::io::prelude::*; use std::os::unix::fs::{MetadataExt, PermissionsExt}; use std::os::unix::io::{AsRawFd, RawFd}; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::pin::Pin; use std::{collections, fs, io}; use tracing::{event, instrument, Level}; @@ -46,6 +46,9 @@ const INCLUDE_MAXDEPTH: u32 = 50; /// it's intended to be informative. const COMPOSE_JSON_PATH: &str = "usr/share/rpm-ostree/treefile.json"; +/// Path to client-side treefiles. +const CLIENT_TREEFILES_DIR: &str = "/etc/rpm-ostree/origin.d"; + /// This struct holds file descriptors for any external files/data referenced by /// a TreeComposeConfig. #[derive(Debug, Default)] @@ -1021,6 +1024,14 @@ impl TreefileExternals { } Ok(()) } + + fn assert_nonempty(&self) { + // can't use the Default trick here because we can't auto-derive Eq because of `File` + assert!(self.postprocess_script.is_none()); + assert!(self.add_files.is_empty()); + assert!(self.passwd.is_none()); + assert!(self.group.is_none()); + } } /// For increased readability in YAML/JSON, we support whitespace in individual @@ -2260,3 +2271,37 @@ pub(crate) fn treefile_new_client(filename: &str, basearch: &str) -> CxxResult Result>> { + Ok(read_dir(CLIENT_TREEFILES_DIR)?.filter_map(|res| match res { + Ok(e) => { + let path = e.path(); + if let Some(ext) = path.extension() { + if ext == "yaml" { + return Some(anyhow::Result::Ok(path)); + } + } + None + } + Err(err) => Some(Err(anyhow::Error::msg(err))), + })) +} + +/// Create a new client treefile using the treefile dropins in /etc/rpm-ostree/origin.d/. +pub(crate) fn treefile_new_client_from_etc(basearch: &str) -> CxxResult> { + let basearch = opt_string(basearch); + let mut cfg = TreeComposeConfig::default(); + let mut tfs = iter_etc_treefiles()?.collect::>>()?; + tfs.sort(); // sort because order matters; later treefiles override earlier ones + for tf in tfs { + let new_cfg = treefile_parse_and_process(tf, basearch)?; + new_cfg.config.base.error_if_nonempty()?; + new_cfg.externals.assert_nonempty(); + let mut new_cfg = new_cfg.config; + treefile_merge(&mut new_cfg, &mut cfg); + cfg = new_cfg; + } + let r = Treefile::new_from_config(cfg, None)?; + r.error_if_base()?; + Ok(Box::new(r)) +}