Skip to content

Commit

Permalink
Merge pull request #268 from jlebon/pr/persistent-args
Browse files Browse the repository at this point in the history
  • Loading branch information
jlebon committed Jun 26, 2020
2 parents e0a95ae + fd6be04 commit 844b7e6
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 0 deletions.
26 changes: 26 additions & 0 deletions src/cmdline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ pub struct InstallConfig {
pub ignition_hash: Option<IgnitionHash>,
pub platform: Option<String>,
pub firstboot_kargs: Option<String>,
pub append_kargs: Option<Vec<String>>,
pub delete_kargs: Option<Vec<String>>,
pub insecure: bool,
pub preserve_on_error: bool,
pub network_config: Option<String>,
Expand Down Expand Up @@ -193,6 +195,24 @@ pub fn parse_args() -> Result<Config> {
// for now though. It's used at least by `coreos-installer.service`.
.hidden(true),
)
.arg(
Arg::with_name("append-karg")
.long("append-karg")
.value_name("arg")
.help("Append default kernel arg")
.takes_value(true)
.number_of_values(1)
.multiple(true),
)
.arg(
Arg::with_name("delete-karg")
.long("delete-karg")
.value_name("arg")
.help("Delete default kernel arg")
.takes_value(true)
.number_of_values(1)
.multiple(true),
)
.arg(
Arg::with_name("copy-network")
.short("n")
Expand Down Expand Up @@ -644,6 +664,12 @@ fn parse_install(matches: &ArgMatches) -> Result<Config> {
.chain_err(|| "parsing Ignition config hash")?,
platform: matches.value_of("platform").map(String::from),
firstboot_kargs: matches.value_of("firstboot-kargs").map(String::from),
append_kargs: matches
.values_of("append-karg")
.map(|v| v.map(String::from).collect()),
delete_kargs: matches
.values_of("delete-karg")
.map(|v| v.map(String::from).collect()),
insecure: matches.is_present("insecure"),
preserve_on_error: matches.is_present("preserve-on-error"),
network_config,
Expand Down
120 changes: 120 additions & 0 deletions src/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ fn write_disk(config: &InstallConfig, source: &mut ImageSource, dest: &mut File)
// postprocess
if config.ignition.is_some()
|| config.firstboot_kargs.is_some()
|| config.append_kargs.is_some()
|| config.delete_kargs.is_some()
|| config.platform.is_some()
|| config.network_config.is_some()
{
Expand All @@ -164,6 +166,18 @@ fn write_disk(config: &InstallConfig, source: &mut ImageSource, dest: &mut File)
write_firstboot_kargs(mount.mountpoint(), firstboot_kargs)
.chain_err(|| "writing firstboot kargs")?;
}
if config.append_kargs.is_some() || config.delete_kargs.is_some() {
eprintln!("Modifying kernel arguments");

edit_bls_entries(mount.mountpoint(), |orig_contents: &str| {
bls_entry_delete_and_append_kargs(
orig_contents,
config.delete_kargs.as_ref(),
config.append_kargs.as_ref(),
)
})
.chain_err(|| "deleting and appending kargs")?;
}
if let Some(platform) = config.platform.as_ref() {
write_platform(mount.mountpoint(), platform).chain_err(|| "writing platform ID")?;
}
Expand Down Expand Up @@ -236,6 +250,56 @@ fn write_firstboot_kargs(mountpoint: &Path, args: &str) -> Result<()> {
Ok(())
}

// This is split out so that we can unit test it.
fn bls_entry_delete_and_append_kargs(
orig_contents: &str,
delete_args: Option<&Vec<String>>,
append_args: Option<&Vec<String>>,
) -> Result<String> {
let mut new_contents = String::with_capacity(orig_contents.len());
let mut found_options = false;
for line in orig_contents.lines() {
if !line.starts_with("options ") {
new_contents.push_str(line.trim_end());
} else if found_options {
bail!("Multiple 'options' lines found");
} else {
// XXX: Need a proper parser here and share it with afterburn. The approach we use here
// is to just do a dumb substring search and replace. This is naive (e.g. doesn't
// handle occurrences in quoted args) but will work for now (one thing that saves us is
// that we're acting on our baked configs, which have straight-forward kargs).
new_contents.push_str("options ");
let mut line: String = add_whitespaces(&line["options ".len()..]);
if let Some(args) = delete_args {
for arg in args {
let arg = add_whitespaces(&arg);
line = line.replace(&arg, " ");
}
}
new_contents.push_str(line.trim_start().trim_end());
if let Some(args) = append_args {
for arg in args {
new_contents.push(' ');
new_contents.push_str(&arg);
}
}
found_options = true;
}
new_contents.push('\n');
}
if !found_options {
bail!("Couldn't locate 'options' line");
}
Ok(new_contents)
}

fn add_whitespaces(s: &str) -> String {
let mut r: String = s.into();
r.insert(0, ' ');
r.push(' ');
r
}

/// Override the platform ID.
fn write_platform(mountpoint: &Path, platform: &str) -> Result<()> {
// early return if setting the platform to the default value, since
Expand Down Expand Up @@ -406,4 +470,60 @@ mod tests {
"options foo bar ignition.platform.id=openstack"
);
}

#[test]
fn test_options_edit() {
let orig_content = "options foo bar foobar";

let delete_kargs = vec!["foo".into()];
let new_content =
bls_entry_delete_and_append_kargs(orig_content, Some(&delete_kargs), None).unwrap();
assert_eq!(new_content, "options bar foobar\n");

let delete_kargs = vec!["bar".into()];
let new_content =
bls_entry_delete_and_append_kargs(orig_content, Some(&delete_kargs), None).unwrap();
assert_eq!(new_content, "options foo foobar\n");

let delete_kargs = vec!["foobar".into()];
let new_content =
bls_entry_delete_and_append_kargs(orig_content, Some(&delete_kargs), None).unwrap();
assert_eq!(new_content, "options foo bar\n");

let delete_kargs = vec!["bar".into(), "foo".into()];
let new_content =
bls_entry_delete_and_append_kargs(orig_content, Some(&delete_kargs), None).unwrap();
assert_eq!(new_content, "options foobar\n");

let orig_content = "options foo=val bar baz=val";

let delete_kargs = vec!["foo=val".into()];
let new_content =
bls_entry_delete_and_append_kargs(orig_content, Some(&delete_kargs), None).unwrap();
assert_eq!(new_content, "options bar baz=val\n");

let delete_kargs = vec!["baz=val".into()];
let new_content =
bls_entry_delete_and_append_kargs(orig_content, Some(&delete_kargs), None).unwrap();
assert_eq!(new_content, "options foo=val bar\n");

let orig_content =
"options foo mitigations=auto,nosmt console=tty0 bar console=ttyS0,115200n8 baz";

let delete_kargs = vec![
"mitigations=auto,nosmt".into(),
"console=ttyS0,115200n8".into(),
];
let append_kargs = vec!["console=ttyS1,115200n8".into()];
let new_content = bls_entry_delete_and_append_kargs(
orig_content,
Some(&delete_kargs),
Some(&append_kargs),
)
.unwrap();
assert_eq!(
new_content,
"options foo console=tty0 bar baz console=ttyS1,115200n8\n"
);
}
}

0 comments on commit 844b7e6

Please sign in to comment.