client, server: adds ability to rename peers (#92)
This commit adds a subcommand to both the client and server to allow changing the name of a peer. The peer retains all the same attributes as before (public keys, IPs, admin/disabled status, etc.). Closes #87pull/96/head
parent
4226278e5a
commit
ec210f9468
|
@ -5,8 +5,8 @@ use indoc::eprintdoc;
|
||||||
use shared::{
|
use shared::{
|
||||||
interface_config::InterfaceConfig, prompts, AddAssociationOpts, AddCidrOpts, AddPeerOpts,
|
interface_config::InterfaceConfig, prompts, AddAssociationOpts, AddCidrOpts, AddPeerOpts,
|
||||||
Association, AssociationContents, Cidr, CidrTree, DeleteCidrOpts, EndpointContents,
|
Association, AssociationContents, Cidr, CidrTree, DeleteCidrOpts, EndpointContents,
|
||||||
InstallOpts, Interface, IoErrorContext, NetworkOpt, Peer, RedeemContents, State,
|
InstallOpts, Interface, IoErrorContext, NetworkOpt, Peer, RedeemContents, RenamePeerOpts,
|
||||||
CLIENT_CONFIG_DIR, REDEEM_TRANSITION_WAIT,
|
State, CLIENT_CONFIG_DIR, REDEEM_TRANSITION_WAIT,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
fmt,
|
fmt,
|
||||||
|
@ -140,6 +140,19 @@ enum Command {
|
||||||
opts: AddPeerOpts,
|
opts: AddPeerOpts,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Rename a peer.
|
||||||
|
///
|
||||||
|
/// By default, you'll be prompted interactively to select a peer, but you can
|
||||||
|
/// also specify all the options in the command, eg:
|
||||||
|
///
|
||||||
|
/// --name "person" --new-name "human"
|
||||||
|
RenamePeer {
|
||||||
|
interface: Interface,
|
||||||
|
|
||||||
|
#[structopt(flatten)]
|
||||||
|
opts: RenamePeerOpts,
|
||||||
|
},
|
||||||
|
|
||||||
/// Add a new CIDR.
|
/// Add a new CIDR.
|
||||||
AddCidr {
|
AddCidr {
|
||||||
interface: Interface,
|
interface: Interface,
|
||||||
|
@ -618,6 +631,32 @@ fn add_peer(interface: &InterfaceName, opts: AddPeerOpts) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rename_peer(interface: &InterfaceName, opts: RenamePeerOpts) -> Result<(), Error> {
|
||||||
|
let InterfaceConfig { server, .. } = InterfaceConfig::from_interface(interface)?;
|
||||||
|
let api = Api::new(&server);
|
||||||
|
|
||||||
|
log::info!("Fetching peers");
|
||||||
|
let peers: Vec<Peer> = api.http("GET", "/admin/peers")?;
|
||||||
|
|
||||||
|
if let Some((peer_request, old_name)) = prompts::rename_peer(&peers, &opts)? {
|
||||||
|
log::info!("Renaming peer...");
|
||||||
|
|
||||||
|
let id = peers
|
||||||
|
.iter()
|
||||||
|
.filter(|p| p.name == old_name)
|
||||||
|
.map(|p| p.id)
|
||||||
|
.next()
|
||||||
|
.ok_or_else(|| "Peer not found.")?;
|
||||||
|
|
||||||
|
let _ = api.http_form("PUT", &format!("/admin/peers/{}", id), peer_request)?;
|
||||||
|
log::info!("Peer renamed.");
|
||||||
|
} else {
|
||||||
|
log::info!("exited without renaming peer.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn enable_or_disable_peer(interface: &InterfaceName, enable: bool) -> Result<(), Error> {
|
fn enable_or_disable_peer(interface: &InterfaceName, enable: bool) -> 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);
|
||||||
|
@ -988,6 +1027,7 @@ fn run(opt: Opts) -> Result<(), Error> {
|
||||||
Command::Down { interface } => wg::down(&interface, opt.network.backend)?,
|
Command::Down { interface } => wg::down(&interface, opt.network.backend)?,
|
||||||
Command::Uninstall { interface } => uninstall(&interface, opt.network)?,
|
Command::Uninstall { interface } => uninstall(&interface, opt.network)?,
|
||||||
Command::AddPeer { interface, opts } => add_peer(&interface, opts)?,
|
Command::AddPeer { interface, opts } => add_peer(&interface, opts)?,
|
||||||
|
Command::RenamePeer { interface, opts } => rename_peer(&interface, opts)?,
|
||||||
Command::AddCidr { interface, opts } => add_cidr(&interface, opts)?,
|
Command::AddCidr { interface, opts } => add_cidr(&interface, opts)?,
|
||||||
Command::DeleteCidr { interface, opts } => delete_cidr(&interface, opts)?,
|
Command::DeleteCidr { interface, opts } => delete_cidr(&interface, opts)?,
|
||||||
Command::DisablePeer { interface } => enable_or_disable_peer(&interface, false)?,
|
Command::DisablePeer { interface } => enable_or_disable_peer(&interface, false)?,
|
||||||
|
|
|
@ -7,7 +7,8 @@ use parking_lot::{Mutex, RwLock};
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use shared::{
|
use shared::{
|
||||||
AddCidrOpts, AddPeerOpts, DeleteCidrOpts, IoErrorContext, NetworkOpt, INNERNET_PUBKEY_HEADER,
|
AddCidrOpts, AddPeerOpts, DeleteCidrOpts, IoErrorContext, NetworkOpt, RenamePeerOpts,
|
||||||
|
INNERNET_PUBKEY_HEADER,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, VecDeque},
|
collections::{HashMap, VecDeque},
|
||||||
|
@ -80,6 +81,14 @@ enum Command {
|
||||||
args: AddPeerOpts,
|
args: AddPeerOpts,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Rename an existing peer.
|
||||||
|
RenamePeer {
|
||||||
|
interface: Interface,
|
||||||
|
|
||||||
|
#[structopt(flatten)]
|
||||||
|
args: RenamePeerOpts,
|
||||||
|
},
|
||||||
|
|
||||||
/// Add a new CIDR to an existing network.
|
/// Add a new CIDR to an existing network.
|
||||||
AddCidr {
|
AddCidr {
|
||||||
interface: Interface,
|
interface: Interface,
|
||||||
|
@ -236,6 +245,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
network: routing,
|
network: routing,
|
||||||
} => serve(*interface, &conf, routing).await?,
|
} => serve(*interface, &conf, routing).await?,
|
||||||
Command::AddPeer { interface, args } => add_peer(&interface, &conf, args, opt.network)?,
|
Command::AddPeer { interface, args } => add_peer(&interface, &conf, args, opt.network)?,
|
||||||
|
Command::RenamePeer { interface, args } => rename_peer(&interface, &conf, args)?,
|
||||||
Command::AddCidr { interface, args } => add_cidr(&interface, &conf, args)?,
|
Command::AddCidr { interface, args } => add_cidr(&interface, &conf, args)?,
|
||||||
Command::DeleteCidr { interface, args } => delete_cidr(&interface, &conf, args)?,
|
Command::DeleteCidr { interface, args } => delete_cidr(&interface, &conf, args)?,
|
||||||
Command::Completions { shell } => {
|
Command::Completions { shell } => {
|
||||||
|
@ -311,6 +321,30 @@ fn add_peer(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rename_peer(
|
||||||
|
interface: &InterfaceName,
|
||||||
|
conf: &ServerConfig,
|
||||||
|
opts: RenamePeerOpts,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let conn = open_database_connection(interface, conf)?;
|
||||||
|
let peers = DatabasePeer::list(&conn)?
|
||||||
|
.into_iter()
|
||||||
|
.map(|dp| dp.inner)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
if let Some((peer_request, old_name)) = shared::prompts::rename_peer(&peers, &opts)? {
|
||||||
|
let mut db_peer = DatabasePeer::list(&conn)?
|
||||||
|
.into_iter()
|
||||||
|
.find(|p| p.name == old_name)
|
||||||
|
.ok_or_else(|| "Peer not found.")?;
|
||||||
|
let _peer = db_peer.update(&conn, peer_request)?;
|
||||||
|
} else {
|
||||||
|
println!("exited without creating peer.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn add_cidr(
|
fn add_cidr(
|
||||||
interface: &InterfaceName,
|
interface: &InterfaceName,
|
||||||
conf: &ServerConfig,
|
conf: &ServerConfig,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
interface_config::{InterfaceConfig, InterfaceInfo, ServerInfo},
|
interface_config::{InterfaceConfig, InterfaceInfo, ServerInfo},
|
||||||
AddCidrOpts, AddPeerOpts, Association, Cidr, CidrContents, CidrTree, DeleteCidrOpts, Endpoint,
|
AddCidrOpts, AddPeerOpts, Association, Cidr, CidrContents, CidrTree, DeleteCidrOpts, Endpoint,
|
||||||
Error, Peer, PeerContents, PERSISTENT_KEEPALIVE_INTERVAL_SECS,
|
Error, Hostname, Peer, PeerContents, RenamePeerOpts, PERSISTENT_KEEPALIVE_INTERVAL_SECS,
|
||||||
};
|
};
|
||||||
use colored::*;
|
use colored::*;
|
||||||
use dialoguer::{theme::ColorfulTheme, Confirm, Input, Select};
|
use dialoguer::{theme::ColorfulTheme, Confirm, Input, Select};
|
||||||
|
@ -274,6 +274,63 @@ pub fn add_peer(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Bring up a prompt to create a new peer. Returns the peer request.
|
||||||
|
pub fn rename_peer(
|
||||||
|
peers: &[Peer],
|
||||||
|
args: &RenamePeerOpts,
|
||||||
|
) -> Result<Option<(PeerContents, Hostname)>, Error> {
|
||||||
|
let eligible_peers = peers
|
||||||
|
.iter()
|
||||||
|
.filter(|p| &*p.name != "innernet-server")
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let old_peer = if let Some(ref name) = args.name {
|
||||||
|
eligible_peers
|
||||||
|
.into_iter()
|
||||||
|
.find(|p| &p.name == name)
|
||||||
|
.ok_or_else(|| format!("Peer '{}' does not exist", name))?
|
||||||
|
.clone()
|
||||||
|
} else {
|
||||||
|
let peer_index = Select::with_theme(&*THEME)
|
||||||
|
.with_prompt("Peer to rename")
|
||||||
|
.items(
|
||||||
|
&eligible_peers
|
||||||
|
.iter()
|
||||||
|
.map(|ep| ep.name.clone())
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
)
|
||||||
|
.interact()?;
|
||||||
|
eligible_peers[peer_index].clone()
|
||||||
|
};
|
||||||
|
let old_name = old_peer.name.clone();
|
||||||
|
let new_name = if let Some(ref name) = args.new_name {
|
||||||
|
name.clone()
|
||||||
|
} else {
|
||||||
|
Input::with_theme(&*THEME)
|
||||||
|
.with_prompt("New Name")
|
||||||
|
.interact()?
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut new_peer = old_peer;
|
||||||
|
new_peer.contents.name = new_name.clone();
|
||||||
|
|
||||||
|
Ok(
|
||||||
|
if args.yes
|
||||||
|
|| Confirm::with_theme(&*THEME)
|
||||||
|
.with_prompt(&format!(
|
||||||
|
"Rename peer {} to {}?",
|
||||||
|
old_name.yellow(),
|
||||||
|
new_name.yellow()
|
||||||
|
))
|
||||||
|
.default(false)
|
||||||
|
.interact()?
|
||||||
|
{
|
||||||
|
Some((new_peer.contents, old_name))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Presents a selection and confirmation of eligible peers for either disabling or enabling,
|
/// Presents a selection and confirmation of eligible peers for either disabling or enabling,
|
||||||
/// and returns back the ID of the selected peer.
|
/// and returns back the ID of the selected peer.
|
||||||
pub fn enable_or_disable_peer(peers: &[Peer], enable: bool) -> Result<Option<Peer>, Error> {
|
pub fn enable_or_disable_peer(peers: &[Peer], enable: bool) -> Result<Option<Peer>, Error> {
|
||||||
|
|
|
@ -318,6 +318,21 @@ pub struct AddPeerOpts {
|
||||||
pub invite_expires: Option<Timestring>,
|
pub invite_expires: Option<Timestring>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, StructOpt)]
|
||||||
|
pub struct RenamePeerOpts {
|
||||||
|
/// Name of peer to rename
|
||||||
|
#[structopt(long)]
|
||||||
|
pub name: Option<Hostname>,
|
||||||
|
|
||||||
|
/// The new name of the peer
|
||||||
|
#[structopt(long)]
|
||||||
|
pub new_name: Option<Hostname>,
|
||||||
|
|
||||||
|
/// Bypass confirmation
|
||||||
|
#[structopt(long)]
|
||||||
|
pub yes: bool,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, StructOpt)]
|
#[derive(Debug, Clone, PartialEq, StructOpt)]
|
||||||
pub struct AddCidrOpts {
|
pub struct AddCidrOpts {
|
||||||
/// The CIDR name (eg. "engineers")
|
/// The CIDR name (eg. "engineers")
|
||||||
|
|
Loading…
Reference in New Issue