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::{
|
||||
interface_config::InterfaceConfig, prompts, AddAssociationOpts, AddCidrOpts, AddPeerOpts,
|
||||
Association, AssociationContents, Cidr, CidrTree, DeleteCidrOpts, EndpointContents,
|
||||
InstallOpts, Interface, IoErrorContext, NetworkOpt, Peer, RedeemContents, State,
|
||||
CLIENT_CONFIG_DIR, REDEEM_TRANSITION_WAIT,
|
||||
InstallOpts, Interface, IoErrorContext, NetworkOpt, Peer, RedeemContents, RenamePeerOpts,
|
||||
State, CLIENT_CONFIG_DIR, REDEEM_TRANSITION_WAIT,
|
||||
};
|
||||
use std::{
|
||||
fmt,
|
||||
|
@ -140,6 +140,19 @@ enum Command {
|
|||
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.
|
||||
AddCidr {
|
||||
interface: Interface,
|
||||
|
@ -618,6 +631,32 @@ fn add_peer(interface: &InterfaceName, opts: AddPeerOpts) -> Result<(), Error> {
|
|||
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> {
|
||||
let InterfaceConfig { server, .. } = InterfaceConfig::from_interface(interface)?;
|
||||
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::Uninstall { interface } => uninstall(&interface, opt.network)?,
|
||||
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::DeleteCidr { interface, opts } => delete_cidr(&interface, opts)?,
|
||||
Command::DisablePeer { interface } => enable_or_disable_peer(&interface, false)?,
|
||||
|
|
|
@ -7,7 +7,8 @@ use parking_lot::{Mutex, RwLock};
|
|||
use rusqlite::Connection;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use shared::{
|
||||
AddCidrOpts, AddPeerOpts, DeleteCidrOpts, IoErrorContext, NetworkOpt, INNERNET_PUBKEY_HEADER,
|
||||
AddCidrOpts, AddPeerOpts, DeleteCidrOpts, IoErrorContext, NetworkOpt, RenamePeerOpts,
|
||||
INNERNET_PUBKEY_HEADER,
|
||||
};
|
||||
use std::{
|
||||
collections::{HashMap, VecDeque},
|
||||
|
@ -80,6 +81,14 @@ enum Command {
|
|||
args: AddPeerOpts,
|
||||
},
|
||||
|
||||
/// Rename an existing peer.
|
||||
RenamePeer {
|
||||
interface: Interface,
|
||||
|
||||
#[structopt(flatten)]
|
||||
args: RenamePeerOpts,
|
||||
},
|
||||
|
||||
/// Add a new CIDR to an existing network.
|
||||
AddCidr {
|
||||
interface: Interface,
|
||||
|
@ -236,6 +245,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
network: routing,
|
||||
} => serve(*interface, &conf, routing).await?,
|
||||
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::DeleteCidr { interface, args } => delete_cidr(&interface, &conf, args)?,
|
||||
Command::Completions { shell } => {
|
||||
|
@ -311,6 +321,30 @@ fn add_peer(
|
|||
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(
|
||||
interface: &InterfaceName,
|
||||
conf: &ServerConfig,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
interface_config::{InterfaceConfig, InterfaceInfo, ServerInfo},
|
||||
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 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,
|
||||
/// and returns back the ID of the selected peer.
|
||||
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>,
|
||||
}
|
||||
|
||||
#[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)]
|
||||
pub struct AddCidrOpts {
|
||||
/// The CIDR name (eg. "engineers")
|
||||
|
|
Loading…
Reference in New Issue