Skip to content

Commit

Permalink
pack: Support --real-rootdev for RHCOS+LUKS
Browse files Browse the repository at this point in the history
Pairs with: coreos/coreos-assembler#1483

We want RHCOS to support offline installs too (it's key to the UX)
but the LUKS container complicates things.  We discussed changing
the RHCOS LUKS bits to save the header in e.g. `/boot` but it's
a big change to that code, and introduces yet another layout
when we really want to switch to Ignition+LUKS.
  • Loading branch information
cgwalters committed May 27, 2020
1 parent b52b3d7 commit ae787b5
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 4 deletions.
30 changes: 29 additions & 1 deletion src/cmdline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,17 @@ pub struct OsmetFiemapConfig {
pub file: String,
}

pub struct OsmetRootBlkDevReal {
pub underlying_device: String,
pub offset_bytes: u32,
}

pub struct OsmetPackConfig {
pub output: String,
pub device: String,
pub checksum: String,
pub description: String,
pub rootdev: Option<OsmetRootBlkDevReal>,
}

pub struct OsmetUnpackConfig {
Expand Down Expand Up @@ -416,6 +422,13 @@ pub fn parse_args() -> Result<Config> {
.help("Description of OS")
.takes_value(true),
)
.arg(
Arg::with_name("real-rootdev")
.long("real-rootdev")
.value_name("PATH,OFFSET")
.help("Underlying device for e.g. RHCOS LUKS container; /dev/disk/by-label/root should be mountable")
.takes_value(true),
)
// positional args
.arg(
Arg::with_name("device")
Expand Down Expand Up @@ -669,6 +682,20 @@ fn parse_iso_remove(matches: &ArgMatches) -> Result<Config> {
}))
}

fn parse_real_rootdev<T: AsRef<str>>(s: Option<T>) -> Result<Option<OsmetRootBlkDevReal>> {
if let Some(v) = s {
let v = v.as_ref();
let parts : Vec<_> = v.splitn(2, ",").collect();
if parts.len() < 2 {
bail!("Expected DEVICE,OFFSET but found {}", v);
}
let offset = parts[1].parse()?;
Ok(Some(OsmetRootBlkDevReal { underlying_device: parts[0].to_string(), offset_bytes: offset }))
} else {
Ok(None)
}
}

fn parse_osmet_pack(matches: &ArgMatches) -> Result<Config> {
Ok(Config::OsmetPack(OsmetPackConfig {
output: matches
Expand All @@ -687,7 +714,8 @@ fn parse_osmet_pack(matches: &ArgMatches) -> Result<Config> {
.value_of("description")
.map(String::from)
.expect("description missing"),
}))
rootdev: parse_real_rootdev(matches.value_of("real-rootdev"))?,
}))
}

fn parse_osmet_unpack(matches: &ArgMatches) -> Result<Config> {
Expand Down
20 changes: 17 additions & 3 deletions src/osmet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ pub fn osmet_pack(config: &OsmetPackConfig) -> Result<()> {

// generate the primary OSTree object <--> disk block mappings, and also try to match up boot
// files with OSTree objects
let (root_partition, mapped_boot_files) = scan_root_partition(&root, boot_files)?;
let (root_partition, mapped_boot_files) = scan_root_partition(&root, config.rootdev.as_ref(), boot_files)?;

let boot_partition = scan_boot_partition(&boot, mapped_boot_files)?;

Expand Down Expand Up @@ -188,10 +188,19 @@ pub fn find_matching_osmet_in_dir(

fn scan_root_partition(
root: &Mount,
mapping: Option<&OsmetRootBlkDevReal>,
mut boot_files: HashMap<u64, PathBuf>,
) -> Result<(OsmetPartition, HashMap<PathBuf, Sha256Digest>)> {
// query the trivial stuff first
let (start_offset, end_offset) = root.get_partition_offsets()?;
let ((start_offset, end_offset), offset) = if let Some(mapping) = mapping {
let bdev = BlkDev { path: mapping.underlying_device.clone(), ..Default::default() };
let (start_offset, end_offset) = bdev.get_partition_offsets()?;
let offset = mapping.offset_bytes.checked_mul(512)
.chain_err(|| format!("Overflow calculating bytes for offset {}", mapping.offset_bytes))?;
((start_offset, end_offset), Some(offset))
} else {
(root.get_partition_offsets()?, None)
};

// we only hash boot files if there's a potential match with an OSTree object, so we keep a
// cache to avoid recomputing it multiple times
Expand Down Expand Up @@ -225,7 +234,12 @@ fn scan_root_partition(
let object = object_path_to_checksum(entry.path())
.chain_err(|| format!("invalid object path {:?}", entry.path()))?;

for extent in extents {
for mut extent in extents {
if let Some(offset) = offset {
extent.physical = extent.physical.checked_add(offset.into())
.chain_err(|| format!("Overflow for extent {:?} with offset {}", extent, offset))?;
}

mappings.push(Mapping {
extent,
object: object.clone(),
Expand Down

0 comments on commit ae787b5

Please sign in to comment.