client: add opts for non-interactive network installs
parent
6d28e7f4ab
commit
b92ad65b17
|
@ -3,9 +3,9 @@ use dialoguer::{Confirm, Input};
|
||||||
use hostsfile::HostsBuilder;
|
use hostsfile::HostsBuilder;
|
||||||
use indoc::printdoc;
|
use indoc::printdoc;
|
||||||
use shared::{
|
use shared::{
|
||||||
interface_config::InterfaceConfig, prompts, AddCidrContents, AddPeerContents, Association,
|
interface_config::InterfaceConfig, prompts, AddCidrOpts, AddPeerOpts, Association,
|
||||||
AssociationContents, Cidr, CidrTree, EndpointContents, Interface, IoErrorContext, Peer,
|
AssociationContents, Cidr, CidrTree, EndpointContents, InstallOpts, Interface, IoErrorContext,
|
||||||
RedeemContents, State, CLIENT_CONFIG_PATH, REDEEM_TRANSITION_WAIT,
|
Peer, RedeemContents, State, CLIENT_CONFIG_PATH, REDEEM_TRANSITION_WAIT,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
fmt,
|
fmt,
|
||||||
|
@ -56,6 +56,9 @@ enum Command {
|
||||||
|
|
||||||
#[structopt(flatten)]
|
#[structopt(flatten)]
|
||||||
hosts: HostsOpt,
|
hosts: HostsOpt,
|
||||||
|
|
||||||
|
#[structopt(flatten)]
|
||||||
|
opts: InstallOpts,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Enumerate all innernet connections.
|
/// Enumerate all innernet connections.
|
||||||
|
@ -107,7 +110,7 @@ enum Command {
|
||||||
interface: Interface,
|
interface: Interface,
|
||||||
|
|
||||||
#[structopt(flatten)]
|
#[structopt(flatten)]
|
||||||
args: AddPeerContents,
|
opts: AddPeerOpts,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Add a new CIDR.
|
/// Add a new CIDR.
|
||||||
|
@ -115,7 +118,7 @@ enum Command {
|
||||||
interface: Interface,
|
interface: Interface,
|
||||||
|
|
||||||
#[structopt(flatten)]
|
#[structopt(flatten)]
|
||||||
args: AddCidrContents,
|
opts: AddCidrOpts,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Disable an enabled peer.
|
/// Disable an enabled peer.
|
||||||
|
@ -191,14 +194,20 @@ fn update_hosts_file(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn install(invite: &Path, hosts_file: Option<PathBuf>) -> Result<(), Error> {
|
fn install(invite: &Path, hosts_file: Option<PathBuf>, opts: InstallOpts) -> Result<(), Error> {
|
||||||
shared::ensure_dirs_exist(&[*CLIENT_CONFIG_PATH])?;
|
shared::ensure_dirs_exist(&[*CLIENT_CONFIG_PATH])?;
|
||||||
let config = InterfaceConfig::from_file(invite)?;
|
let config = InterfaceConfig::from_file(invite)?;
|
||||||
|
|
||||||
let iface = Input::with_theme(&*prompts::THEME)
|
let iface = if opts.default_name {
|
||||||
.with_prompt("Interface name")
|
config.interface.network_name.clone()
|
||||||
.default(config.interface.network_name.clone())
|
} else if let Some(ref iface) = opts.name {
|
||||||
.interact()?;
|
iface.clone()
|
||||||
|
} else {
|
||||||
|
Input::with_theme(&*prompts::THEME)
|
||||||
|
.with_prompt("Interface name")
|
||||||
|
.default(config.interface.network_name.clone())
|
||||||
|
.interact()?
|
||||||
|
};
|
||||||
|
|
||||||
let target_conf = CLIENT_CONFIG_PATH.join(&iface).with_extension("conf");
|
let target_conf = CLIENT_CONFIG_PATH.join(&iface).with_extension("conf");
|
||||||
if target_conf.exists() {
|
if target_conf.exists() {
|
||||||
|
@ -217,13 +226,14 @@ fn install(invite: &Path, hosts_file: Option<PathBuf>) -> Result<(), Error> {
|
||||||
|
|
||||||
fetch(&iface, false, hosts_file)?;
|
fetch(&iface, false, hosts_file)?;
|
||||||
|
|
||||||
if Confirm::with_theme(&*prompts::THEME)
|
if opts.delete_invite
|
||||||
.with_prompt(&format!(
|
|| Confirm::with_theme(&*prompts::THEME)
|
||||||
"Delete invitation file \"{}\" now? (It's no longer needed)",
|
.with_prompt(&format!(
|
||||||
invite.to_string_lossy().yellow()
|
"Delete invitation file \"{}\" now? (It's no longer needed)",
|
||||||
))
|
invite.to_string_lossy().yellow()
|
||||||
.default(true)
|
))
|
||||||
.interact()?
|
.default(true)
|
||||||
|
.interact()?
|
||||||
{
|
{
|
||||||
std::fs::remove_file(invite).with_path(invite)?;
|
std::fs::remove_file(invite).with_path(invite)?;
|
||||||
}
|
}
|
||||||
|
@ -473,13 +483,13 @@ fn uninstall(interface: &InterfaceName) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_cidr(interface: &InterfaceName, args: AddCidrContents) -> Result<(), Error> {
|
fn add_cidr(interface: &InterfaceName, opts: AddCidrOpts) -> Result<(), Error> {
|
||||||
let InterfaceConfig { server, .. } = InterfaceConfig::from_interface(interface)?;
|
let InterfaceConfig { server, .. } = InterfaceConfig::from_interface(interface)?;
|
||||||
println!("Fetching CIDRs");
|
println!("Fetching CIDRs");
|
||||||
let api = Api::new(&server);
|
let api = Api::new(&server);
|
||||||
let cidrs: Vec<Cidr> = api.http("GET", "/admin/cidrs")?;
|
let cidrs: Vec<Cidr> = api.http("GET", "/admin/cidrs")?;
|
||||||
|
|
||||||
let cidr_request = prompts::add_cidr(&cidrs, &args)?;
|
let cidr_request = prompts::add_cidr(&cidrs, &opts)?;
|
||||||
|
|
||||||
println!("Creating CIDR...");
|
println!("Creating CIDR...");
|
||||||
let cidr: Cidr = api.http_form("POST", "/admin/cidrs", cidr_request)?;
|
let cidr: Cidr = api.http_form("POST", "/admin/cidrs", cidr_request)?;
|
||||||
|
@ -499,7 +509,7 @@ fn add_cidr(interface: &InterfaceName, args: AddCidrContents) -> Result<(), Erro
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_peer(interface: &InterfaceName, args: AddPeerContents) -> Result<(), Error> {
|
fn add_peer(interface: &InterfaceName, opts: AddPeerOpts) -> Result<(), Error> {
|
||||||
let InterfaceConfig { server, .. } = InterfaceConfig::from_interface(interface)?;
|
let InterfaceConfig { server, .. } = InterfaceConfig::from_interface(interface)?;
|
||||||
let api = Api::new(&server);
|
let api = Api::new(&server);
|
||||||
|
|
||||||
|
@ -509,7 +519,7 @@ fn add_peer(interface: &InterfaceName, args: AddPeerContents) -> Result<(), Erro
|
||||||
let peers: Vec<Peer> = api.http("GET", "/admin/peers")?;
|
let peers: Vec<Peer> = api.http("GET", "/admin/peers")?;
|
||||||
let cidr_tree = CidrTree::new(&cidrs[..]);
|
let cidr_tree = CidrTree::new(&cidrs[..]);
|
||||||
|
|
||||||
if let Some((peer_request, keypair)) = prompts::add_peer(&peers, &cidr_tree, &args)? {
|
if let Some((peer_request, keypair)) = prompts::add_peer(&peers, &cidr_tree, &opts)? {
|
||||||
println!("Creating peer...");
|
println!("Creating peer...");
|
||||||
let peer: Peer = api.http_form("POST", "/admin/peers", peer_request)?;
|
let peer: Peer = api.http_form("POST", "/admin/peers", peer_request)?;
|
||||||
let server_peer = peers.iter().find(|p| p.id == 1).unwrap();
|
let server_peer = peers.iter().find(|p| p.id == 1).unwrap();
|
||||||
|
@ -520,7 +530,7 @@ fn add_peer(interface: &InterfaceName, args: AddPeerContents) -> Result<(), Erro
|
||||||
&cidr_tree,
|
&cidr_tree,
|
||||||
keypair,
|
keypair,
|
||||||
&server.internal_endpoint,
|
&server.internal_endpoint,
|
||||||
&args.save_config,
|
&opts.save_config,
|
||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
println!("exited without creating peer.");
|
println!("exited without creating peer.");
|
||||||
|
@ -830,7 +840,11 @@ fn run(opt: Opt) -> Result<(), Error> {
|
||||||
});
|
});
|
||||||
|
|
||||||
match command {
|
match command {
|
||||||
Command::Install { config, hosts } => install(&config, hosts.into())?,
|
Command::Install {
|
||||||
|
config,
|
||||||
|
hosts,
|
||||||
|
opts,
|
||||||
|
} => install(&config, hosts.into(), opts)?,
|
||||||
Command::Show {
|
Command::Show {
|
||||||
short,
|
short,
|
||||||
tree,
|
tree,
|
||||||
|
@ -849,8 +863,8 @@ fn run(opt: Opt) -> Result<(), Error> {
|
||||||
)?,
|
)?,
|
||||||
Command::Down { interface } => wg::down(&interface)?,
|
Command::Down { interface } => wg::down(&interface)?,
|
||||||
Command::Uninstall { interface } => uninstall(&interface)?,
|
Command::Uninstall { interface } => uninstall(&interface)?,
|
||||||
Command::AddPeer { interface, args } => add_peer(&interface, args)?,
|
Command::AddPeer { interface, opts } => add_peer(&interface, opts)?,
|
||||||
Command::AddCidr { interface, args } => add_cidr(&interface, args)?,
|
Command::AddCidr { interface, opts } => add_cidr(&interface, opts)?,
|
||||||
Command::DisablePeer { interface } => enable_or_disable_peer(&interface, false)?,
|
Command::DisablePeer { interface } => enable_or_disable_peer(&interface, false)?,
|
||||||
Command::EnablePeer { interface } => enable_or_disable_peer(&interface, true)?,
|
Command::EnablePeer { interface } => enable_or_disable_peer(&interface, true)?,
|
||||||
Command::AddAssociation { interface } => add_association(&interface)?,
|
Command::AddAssociation { interface } => add_association(&interface)?,
|
||||||
|
|
|
@ -7,7 +7,7 @@ use ipnetwork::IpNetwork;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||||
use shared::{AddCidrContents, AddPeerContents, IoErrorContext, INNERNET_PUBKEY_HEADER};
|
use shared::{AddCidrOpts, AddPeerOpts, IoErrorContext, INNERNET_PUBKEY_HEADER};
|
||||||
use std::{
|
use std::{
|
||||||
convert::Infallible,
|
convert::Infallible,
|
||||||
env,
|
env,
|
||||||
|
@ -64,7 +64,7 @@ enum Command {
|
||||||
interface: Interface,
|
interface: Interface,
|
||||||
|
|
||||||
#[structopt(flatten)]
|
#[structopt(flatten)]
|
||||||
args: AddPeerContents,
|
args: AddPeerOpts,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Add a new CIDR to an existing network.
|
/// Add a new CIDR to an existing network.
|
||||||
|
@ -72,7 +72,7 @@ enum Command {
|
||||||
interface: Interface,
|
interface: Interface,
|
||||||
|
|
||||||
#[structopt(flatten)]
|
#[structopt(flatten)]
|
||||||
args: AddCidrContents,
|
args: AddCidrOpts,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,7 +237,7 @@ fn open_database_connection(
|
||||||
fn add_peer(
|
fn add_peer(
|
||||||
interface: &InterfaceName,
|
interface: &InterfaceName,
|
||||||
conf: &ServerConfig,
|
conf: &ServerConfig,
|
||||||
args: AddPeerContents,
|
args: AddPeerOpts,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let config = ConfigFile::from_file(conf.config_path(interface))?;
|
let config = ConfigFile::from_file(conf.config_path(interface))?;
|
||||||
let conn = open_database_connection(interface, conf)?;
|
let conn = open_database_connection(interface, conf)?;
|
||||||
|
@ -280,7 +280,7 @@ fn add_peer(
|
||||||
fn add_cidr(
|
fn add_cidr(
|
||||||
interface: &InterfaceName,
|
interface: &InterfaceName,
|
||||||
conf: &ServerConfig,
|
conf: &ServerConfig,
|
||||||
args: AddCidrContents,
|
args: AddCidrOpts,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let conn = open_database_connection(interface, conf)?;
|
let conn = open_database_connection(interface, conf)?;
|
||||||
let cidrs = DatabaseCidr::list(&conn)?;
|
let cidrs = DatabaseCidr::list(&conn)?;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
interface_config::{InterfaceConfig, InterfaceInfo, ServerInfo},
|
interface_config::{InterfaceConfig, InterfaceInfo, ServerInfo},
|
||||||
AddCidrContents, AddPeerContents, Association, Cidr, CidrContents, CidrTree, Error, Peer,
|
AddCidrOpts, AddPeerOpts, Association, Cidr, CidrContents, CidrTree, Error, Peer, PeerContents,
|
||||||
PeerContents, PERSISTENT_KEEPALIVE_INTERVAL_SECS,
|
PERSISTENT_KEEPALIVE_INTERVAL_SECS,
|
||||||
};
|
};
|
||||||
use colored::*;
|
use colored::*;
|
||||||
use dialoguer::{theme::ColorfulTheme, Confirm, Input, Select};
|
use dialoguer::{theme::ColorfulTheme, Confirm, Input, Select};
|
||||||
|
@ -32,7 +32,7 @@ pub fn hostname_validator(name: &String) -> Result<(), &'static str> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bring up a prompt to create a new CIDR. Returns the peer request.
|
/// Bring up a prompt to create a new CIDR. Returns the peer request.
|
||||||
pub fn add_cidr(cidrs: &[Cidr], request: &AddCidrContents) -> Result<Option<CidrContents>, Error> {
|
pub fn add_cidr(cidrs: &[Cidr], request: &AddCidrOpts) -> Result<Option<CidrContents>, Error> {
|
||||||
let parent_cidr = if let Some(ref parent_name) = request.parent {
|
let parent_cidr = if let Some(ref parent_name) = request.parent {
|
||||||
cidrs
|
cidrs
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -161,7 +161,7 @@ pub fn delete_association<'a>(
|
||||||
pub fn add_peer(
|
pub fn add_peer(
|
||||||
peers: &[Peer],
|
peers: &[Peer],
|
||||||
cidr_tree: &CidrTree,
|
cidr_tree: &CidrTree,
|
||||||
args: &AddPeerContents,
|
args: &AddPeerOpts,
|
||||||
) -> Result<Option<(PeerContents, KeyPair)>, Error> {
|
) -> Result<Option<(PeerContents, KeyPair)>, Error> {
|
||||||
let leaves = cidr_tree.leaves();
|
let leaves = cidr_tree.leaves();
|
||||||
|
|
||||||
|
|
|
@ -167,7 +167,22 @@ pub struct RedeemContents {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, StructOpt)]
|
#[derive(Debug, Clone, PartialEq, StructOpt)]
|
||||||
pub struct AddPeerContents {
|
pub struct InstallOpts {
|
||||||
|
/// Set a specific interface name
|
||||||
|
#[structopt(long, conflicts_with = "default-name")]
|
||||||
|
pub name: Option<String>,
|
||||||
|
|
||||||
|
/// Use the network name inside the invitation as the interface name
|
||||||
|
#[structopt(long = "default-name")]
|
||||||
|
pub default_name: bool,
|
||||||
|
|
||||||
|
/// Delete the invitation after a successful install
|
||||||
|
#[structopt(short, long)]
|
||||||
|
pub delete_invite: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, StructOpt)]
|
||||||
|
pub struct AddPeerOpts {
|
||||||
/// Name of new peer
|
/// Name of new peer
|
||||||
#[structopt(long)]
|
#[structopt(long)]
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
|
@ -197,7 +212,7 @@ pub struct AddPeerContents {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, StructOpt)]
|
#[derive(Debug, Clone, PartialEq, StructOpt)]
|
||||||
pub struct AddCidrContents {
|
pub struct AddCidrOpts {
|
||||||
#[structopt(long)]
|
#[structopt(long)]
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue