Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] providers/vmware: add an experimental rd-net-kargs #379

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
276 changes: 102 additions & 174 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ path = "src/main.rs"
lto = true

[dependencies]
anyhow = "^1.0"
base64 = "^0.12"
byteorder = "^1.3"
clap = "^2.33"
Expand All @@ -48,6 +49,7 @@ slog-term = "^2.5"
tempfile = "^3.1"
update-ssh-keys = { version = "^0.5", optional = true }
users = "^0.9"
vmw_backdoor = "^0.1"

[dependencies.slog]
version = "^2.5"
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ install-units: $(units)

.PHONY: install
install: install-units
install -D -t ${DESTDIR}$(PREFIX)/lib/dracut/modules.d/30afterburn dracut/30afterburn/*
install -D -t ${DESTDIR}$(PREFIX)/bin target/release/afterburn
install -D -m 0444 -t ${DESTDIR}$(PREFIX)/lib/dracut/modules.d/30afterburn dracut/30afterburn/*
install -D -t ${DESTDIR}$(PREFIX)/bin target/debug/afterburn
13 changes: 13 additions & 0 deletions dracut/30afterburn/afterburn-net-bootstrap.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[Unit]
Description=Afterburn network bootstrapping
# IBM Cloud (Classic) has no DHCP.
ConditionKernelCommandLine=|ignition.platform.id=ibmcloud-classic

Before=ignition-fetch.service

OnFailure=emergency.target
OnFailureJobMode=isolate

[Service]
ExecStart=/usr/bin/afterburn exp rd-net-bootstrap --cmdline
Type=oneshot
17 changes: 17 additions & 0 deletions dracut/30afterburn/afterburn-net-kargs.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[Unit]
Description=Afterburn network kargs augmenting
# VMware: extra network kargs provided via guestinfo.
ConditionKernelCommandLine=|ignition.platform.id=vmware
DefaultDependencies=no
# This service may produce additional kargs fragments,
# which are then consumed by dracut-cmdline(8).
Before=dracut-cmdline.service
After=systemd-journald.socket

OnFailure=emergency.target
OnFailureJobMode=isolate

[Service]
Environment=AFTERBURN_OPT_PROVIDER=--cmdline
ExecStart=/usr/bin/afterburn exp rd-net-kargs ${AFTERBURN_OPT_PROVIDER}
Type=oneshot
10 changes: 9 additions & 1 deletion dracut/30afterburn/module-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,17 @@ install() {
inst_simple "$moddir/afterburn-hostname.service" \
"$systemdutildir/system/afterburn-hostname.service"

inst_simple "$moddir/afterburn-net-bootstrap.service" \
"$systemdutildir/system/afterburn-net-bootstrap.service"

inst_simple "$moddir/afterburn-net-kargs.service" \
"$systemdutildir/system/afterburn-net-kargs.service"

# We want the afterburn-hostname to be firstboot only, so Ignition-provided
# hostname changes do not get overwritten on subsequent boots

mkdir -p "$initdir/$systemdsystemunitdir/ignition-complete.target.requires"
ln -s "../afterburn-hostname.service" "$initdir/$systemdsystemunitdir/ignition-complete.target.requires/afterburn-hostname.service"

ln -s "../afterburn-net-boostrap.service" "$initdir/$systemdsystemunitdir/ignition-complete.target.requires/afterburn-net-bootstrap.service"
ln -s "../afterburn-net-kargs.service" "$initdir/$systemdsystemunitdir/ignition-complete.target.requires/afterburn-net-kargs.service"
}
84 changes: 84 additions & 0 deletions src/cli/exp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//! `exp` CLI sub-command.

use crate::errors::*;
use crate::metadata;
use clap::ArgMatches;
use error_chain::bail;

#[derive(Debug)]
pub enum CliExp {
NetBootstrap(CliNetBootstrap),
NetKargs(CliNetKargs),
}

impl CliExp {
/// Parse sub-command into configuration.
pub(crate) fn parse(app_matches: &ArgMatches) -> Result<super::CliConfig> {
if app_matches.subcommand_name().is_none() {
bail!("missing exp subcommand");
}

let cfg = match app_matches.subcommand() {
("rd-net-bootstrap", Some(matches)) => CliNetBootstrap::parse(matches)?,
("rd-net-kargs", Some(matches)) => CliNetKargs::parse(matches)?,
(x, _) => unreachable!("unrecognized exp subcommand '{}'", x),
};

Ok(super::CliConfig::Exp(cfg))
}

// Run sub-command.
pub(crate) fn run(&self) -> Result<()> {
match self {
CliExp::NetBootstrap(cmd) => cmd.run()?,
CliExp::NetKargs(cmd) => cmd.run()?,
};
Ok(())
}
}

/// Sub-command for network bootstrap.
#[derive(Debug)]
pub struct CliNetBootstrap {
platform: String,
}

impl CliNetBootstrap {
/// Parse sub-command into configuration.
pub(crate) fn parse(matches: &ArgMatches) -> Result<CliExp> {
let platform = super::parse_provider(matches)?;

let cfg = Self { platform };
Ok(CliExp::NetBootstrap(cfg))
}

/// Run the sub-command.
pub(crate) fn run(&self) -> Result<()> {
let provider = metadata::fetch_metadata(&self.platform)?;
provider.rd_net_bootstrap()?;
Ok(())
}
}

/// Sub-command for network bootstrap.
#[derive(Debug)]
pub struct CliNetKargs {
platform: String,
}

impl CliNetKargs {
/// Parse sub-command into configuration.
pub(crate) fn parse(matches: &ArgMatches) -> Result<CliExp> {
let platform = super::parse_provider(matches)?;

let cfg = Self { platform };
Ok(CliExp::NetKargs(cfg))
}

/// Run the sub-command.
pub(crate) fn run(&self) -> Result<()> {
let provider = metadata::fetch_metadata(&self.platform)?;
provider.rd_net_kargs()?;
Ok(())
}
}
163 changes: 109 additions & 54 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

use crate::errors::*;
use clap::{crate_version, App, Arg, ArgMatches, SubCommand};
use error_chain::bail;
use slog_scope::trace;

mod exp;
mod multi;

/// Path to kernel command-line (requires procfs mount).
Expand All @@ -13,13 +15,15 @@ const CMDLINE_PATH: &str = "/proc/cmdline";
#[derive(Debug)]
pub(crate) enum CliConfig {
Multi(multi::CliMulti),
Exp(exp::CliExp),
}

impl CliConfig {
/// Parse CLI sub-commands into configuration.
pub fn parse_subcommands(app_matches: ArgMatches) -> Result<Self> {
let cfg = match app_matches.subcommand() {
("multi", Some(matches)) => multi::CliMulti::parse(matches)?,
("exp", Some(matches)) => exp::CliExp::parse(matches)?,
(x, _) => unreachable!("unrecognized subcommand '{}'", x),
};

Expand All @@ -30,6 +34,7 @@ impl CliConfig {
pub fn run(self) -> Result<()> {
match self {
CliConfig::Multi(cmd) => cmd.run(),
CliConfig::Exp(cmd) => cmd.run(),
}
}
}
Expand All @@ -44,62 +49,114 @@ pub(crate) fn parse_args(argv: impl IntoIterator<Item = String>) -> Result<CliCo
Ok(cfg)
}

/// Parse provider ID from flag or kargs.
fn parse_provider(matches: &clap::ArgMatches) -> Result<String> {
let provider = match (matches.value_of("provider"), matches.is_present("cmdline")) {
(Some(provider), false) => String::from(provider),
(None, true) => crate::util::get_platform(CMDLINE_PATH)?,
(None, false) => bail!("must set either --provider or --cmdline"),
(Some(_), true) => bail!("cannot process both --provider and --cmdline"),
};

Ok(provider)
}

/// CLI setup, covering all sub-commands and arguments.
fn cli_setup<'a, 'b>() -> App<'a, 'b> {
// NOTE(lucab): due to legacy translation there can't be global arguments
// here, i.e. a sub-command is always expected first.
App::new("Afterburn").version(crate_version!()).subcommand(
SubCommand::with_name("multi")
.about("Perform multiple tasks in a single call")
.arg(
Arg::with_name("legacy-cli")
.long("legacy-cli")
.help("Whether this command was translated from legacy CLI args")
.hidden(true),
)
.arg(
Arg::with_name("provider")
.long("provider")
.help("The name of the cloud provider")
.global(true)
.takes_value(true),
)
.arg(
Arg::with_name("cmdline")
.long("cmdline")
.global(true)
.help("Read the cloud provider from the kernel cmdline"),
)
.arg(
Arg::with_name("attributes")
.long("attributes")
.help("The file into which the metadata attributes are written")
.takes_value(true),
)
.arg(
Arg::with_name("check-in")
.long("check-in")
.help("Check-in this instance boot with the cloud provider"),
)
.arg(
Arg::with_name("hostname")
.long("hostname")
.help("The file into which the hostname should be written")
.takes_value(true),
)
.arg(
Arg::with_name("network-units")
.long("network-units")
.help("The directory into which network units are written")
.takes_value(true),
)
.arg(
Arg::with_name("ssh-keys")
.long("ssh-keys")
.help("Update SSH keys for the given user")
.takes_value(true),
),
)
App::new("Afterburn")
.version(crate_version!())
.subcommand(
SubCommand::with_name("multi")
.about("Perform multiple tasks in a single call")
.arg(
Arg::with_name("legacy-cli")
.long("legacy-cli")
.help("Whether this command was translated from legacy CLI args")
.hidden(true),
)
.arg(
Arg::with_name("provider")
.long("provider")
.help("The name of the cloud provider")
.global(true)
.takes_value(true),
)
.arg(
Arg::with_name("cmdline")
.long("cmdline")
.global(true)
.help("Read the cloud provider from the kernel cmdline"),
)
.arg(
Arg::with_name("attributes")
.long("attributes")
.help("The file into which the metadata attributes are written")
.takes_value(true),
)
.arg(
Arg::with_name("check-in")
.long("check-in")
.help("Check-in this instance boot with the cloud provider"),
)
.arg(
Arg::with_name("hostname")
.long("hostname")
.help("The file into which the hostname should be written")
.takes_value(true),
)
.arg(
Arg::with_name("network-units")
.long("network-units")
.help("The directory into which network units are written")
.takes_value(true),
)
.arg(
Arg::with_name("ssh-keys")
.long("ssh-keys")
.help("Update SSH keys for the given user")
.takes_value(true),
),
)
.subcommand(
SubCommand::with_name("exp")
.about("experimental commands")
.subcommand(
SubCommand::with_name("rd-net-bootstrap")
.about("Bootstrap network in initrd")
.arg(
Arg::with_name("provider")
.long("provider")
.help("The name of the cloud provider")
.global(true)
.takes_value(true),
)
.arg(
Arg::with_name("cmdline")
.long("cmdline")
.global(true)
.help("Read the cloud provider from the kernel cmdline"),
),
)
.subcommand(
SubCommand::with_name("rd-net-kargs")
.about("Propagate network kargs in initrd")
.arg(
Arg::with_name("provider")
.long("provider")
.help("The name of the cloud provider")
.global(true)
.takes_value(true),
)
.arg(
Arg::with_name("cmdline")
.long("cmdline")
.global(true)
.help("Read the cloud provider from the kernel cmdline"),
),
),
)
}

/// Translate command-line arguments from legacy mode.
Expand Down Expand Up @@ -139,8 +196,6 @@ fn translate_legacy_args(cli: impl IntoIterator<Item = String>) -> impl Iterator
})
}

impl CliConfig {}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
Loading