diff --git a/src/cmdline.rs b/src/cmdline.rs index 4a0a2f7b3..3c1d7fe28 100644 --- a/src/cmdline.rs +++ b/src/cmdline.rs @@ -38,6 +38,7 @@ pub struct InstallConfig { pub firstboot_kargs: Option, pub insecure: bool, pub preserve_on_error: bool, + pub network_config: Option, } pub struct DownloadConfig { @@ -136,6 +137,22 @@ pub fn parse_args() -> Result { .help("Additional kernel args for the first boot") .takes_value(true), ) + .arg( + Arg::with_name("copy-network") + .short("n") + .long("copy-network") + .help("Copy network config from install environment"), + ) + .arg( + Arg::with_name("network-dir") + .long("network-dir") + .value_name("path") + .default_value("/etc/NetworkManager/system-connections/") + .takes_value(true) + .empty_values(false) + .help("For use with -n.") + .next_line_help(true), // so we can stay under 80 chars + ) // obscure options without short names .arg( Arg::with_name("insecure") @@ -400,6 +417,15 @@ fn parse_install(matches: &ArgMatches) -> Result { // and report it to the user eprintln!("{}", location); + // If the user requested us to copy networking config by passing + // -n or --copy-network then copy networking config from the + // directory defined by --network-dir. + let network_config = if matches.is_present("copy-network") { + matches.value_of("network-dir").map(String::from) + } else { + None + }; + // build configuration Ok(Config::Install(InstallConfig { device, @@ -409,6 +435,7 @@ fn parse_install(matches: &ArgMatches) -> Result { firstboot_kargs: matches.value_of("firstboot-kargs").map(String::from), insecure: matches.is_present("insecure"), preserve_on_error: matches.is_present("preserve-on-error"), + network_config, })) } diff --git a/src/install.rs b/src/install.rs index 6899402b2..d7d4de538 100644 --- a/src/install.rs +++ b/src/install.rs @@ -14,7 +14,7 @@ use error_chain::{bail, ChainedError}; use nix::mount; -use std::fs::{create_dir_all, read_dir, File, OpenOptions}; +use std::fs::{copy as fscopy, create_dir_all, read_dir, File, OpenOptions}; use std::io::{copy, Read, Seek, SeekFrom, Write}; use std::os::unix::fs::FileTypeExt; use std::path::Path; @@ -111,7 +111,11 @@ fn write_disk( udev_settle()?; // postprocess - if ignition.is_some() || config.firstboot_kargs.is_some() || config.platform.is_some() { + if ignition.is_some() + || config.firstboot_kargs.is_some() + || config.platform.is_some() + || config.network_config.is_some() + { let mount = mount_partition_by_label(&config.device, "boot", mount::MsFlags::empty())?; if let Some(ignition) = ignition { write_ignition(mount.mountpoint(), ignition)?; @@ -122,6 +126,9 @@ fn write_disk( if let Some(platform) = config.platform.as_ref() { write_platform(mount.mountpoint(), platform)?; } + if let Some(network_config) = config.network_config.as_ref() { + copy_network_config(mount.mountpoint(), network_config)?; + } } Ok(()) @@ -233,6 +240,37 @@ fn write_platform(mountpoint: &Path, platform: &str) -> Result<()> { Ok(()) } +/// Copy networking config if asked to do so +fn copy_network_config(mountpoint: &Path, net_config_src: &str) -> Result<()> { + eprintln!("Copying networking configuration from {}", net_config_src); + + // get the path to the destination directory + let net_config_dest = mountpoint.join("coreos-installer-network"); + + // make the directory if it doesn't exist + create_dir_all(&net_config_dest).chain_err(|| { + format!( + "creating destination networking config directory {}", + net_config_dest.display() + ) + })?; + + // copy files from source to destination directories + for entry in + read_dir(&net_config_src).chain_err(|| format!("reading directory {}", net_config_src))? + { + let entry = entry.chain_err(|| format!("reading directory {}", net_config_src))?; + let srcpath = entry.path(); + let destpath = net_config_dest.join(entry.file_name()); + if srcpath.is_file() { + eprintln!("Copying {} to installed system", srcpath.display()); + fscopy(&srcpath, &destpath).chain_err(|| "Copying networking config")?; + } + } + + Ok(()) +} + /// Clear the partition table. For use after a failure. fn clear_partition_table(dest: &mut File) -> Result<()> { eprintln!("Clearing partition table");