src/api2/config/network.rs: improve network api
This commit is contained in:
parent
e2d940b949
commit
df6bb03d0e
|
@ -5,8 +5,8 @@ use proxmox::api::{api, ApiMethod, Router, RpcEnvironment, Permission};
|
|||
|
||||
//use crate::api2::types::*;
|
||||
use crate::config::network;
|
||||
use crate::config::acl::{PRIV_SYS_AUDIT};
|
||||
use crate::api2::types::Interface;
|
||||
use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
|
||||
use crate::api2::types::*;
|
||||
|
||||
#[api(
|
||||
input: {
|
||||
|
@ -44,5 +44,145 @@ pub fn list_network_devices(
|
|||
Ok(list.into())
|
||||
}
|
||||
|
||||
#[api(
|
||||
input: {
|
||||
properties: {
|
||||
name: {
|
||||
schema: NETWORK_INTERFACE_NAME_SCHEMA,
|
||||
},
|
||||
},
|
||||
},
|
||||
returns: {
|
||||
description: "The network interface configuration (with config digest).",
|
||||
type: Interface,
|
||||
},
|
||||
access: {
|
||||
permission: &Permission::Privilege(&[], PRIV_SYS_AUDIT, false),
|
||||
},
|
||||
)]
|
||||
/// Read a network interface configuration.
|
||||
pub fn read_interface(name: String) -> Result<Value, Error> {
|
||||
|
||||
let (config, digest) = network::config()?;
|
||||
|
||||
let interface = config.lookup(&name)?;
|
||||
|
||||
let mut data: Value = to_value(interface)?;
|
||||
data["digest"] = proxmox::tools::digest_to_hex(&digest).into();
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
#[api(
|
||||
protected: true,
|
||||
input: {
|
||||
properties: {
|
||||
name: {
|
||||
schema: NETWORK_INTERFACE_NAME_SCHEMA,
|
||||
},
|
||||
address: {
|
||||
schema: CIDR_SCHEMA,
|
||||
optional: true,
|
||||
},
|
||||
gateway: {
|
||||
schema: IP_SCHEMA,
|
||||
optional: true,
|
||||
},
|
||||
digest: {
|
||||
optional: true,
|
||||
schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
|
||||
},
|
||||
},
|
||||
},
|
||||
access: {
|
||||
permission: &Permission::Privilege(&[], PRIV_SYS_MODIFY, false),
|
||||
},
|
||||
)]
|
||||
/// Update network interface config.
|
||||
pub fn update_interface(
|
||||
name: String,
|
||||
address: Option<String>,
|
||||
gateway: Option<String>,
|
||||
digest: Option<String>,
|
||||
) -> Result<(), Error> {
|
||||
|
||||
let _lock = crate::tools::open_file_locked(network::NETWORK_LOCKFILE, std::time::Duration::new(10, 0))?;
|
||||
|
||||
let (mut config, expected_digest) = network::config()?;
|
||||
|
||||
if let Some(ref digest) = digest {
|
||||
let digest = proxmox::tools::hex_to_digest(digest)?;
|
||||
crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
|
||||
}
|
||||
|
||||
let interface = config.lookup_mut(&name)?;
|
||||
|
||||
if let Some(address) = address {
|
||||
let (_, _, is_v6) = network::parse_cidr(&address)?;
|
||||
if is_v6 {
|
||||
interface.cidr_v6 = Some(address);
|
||||
} else {
|
||||
interface.cidr_v4 = Some(address);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(gateway) = gateway {
|
||||
let is_v6 = gateway.contains(':');
|
||||
if is_v6 {
|
||||
interface.gateway_v6 = Some(gateway);
|
||||
} else {
|
||||
interface.gateway_v4 = Some(gateway);
|
||||
}
|
||||
}
|
||||
|
||||
network::save_config(&config)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[api(
|
||||
protected: true,
|
||||
input: {
|
||||
properties: {
|
||||
name: {
|
||||
schema: NETWORK_INTERFACE_NAME_SCHEMA,
|
||||
},
|
||||
digest: {
|
||||
optional: true,
|
||||
schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
|
||||
},
|
||||
},
|
||||
},
|
||||
access: {
|
||||
permission: &Permission::Privilege(&[], PRIV_SYS_MODIFY, false),
|
||||
},
|
||||
)]
|
||||
/// Remove network interface configuration.
|
||||
pub fn delete_interface(name: String, digest: Option<String>) -> Result<(), Error> {
|
||||
|
||||
let _lock = crate::tools::open_file_locked(network::NETWORK_LOCKFILE, std::time::Duration::new(10, 0))?;
|
||||
|
||||
let (mut config, expected_digest) = network::config()?;
|
||||
|
||||
if let Some(ref digest) = digest {
|
||||
let digest = proxmox::tools::hex_to_digest(digest)?;
|
||||
crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
|
||||
}
|
||||
|
||||
let _interface = config.lookup(&name)?; // check if interface exists
|
||||
|
||||
config.interfaces.remove(&name);
|
||||
|
||||
network::save_config(&config)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
const ITEM_ROUTER: Router = Router::new()
|
||||
.get(&API_METHOD_READ_INTERFACE)
|
||||
.put(&API_METHOD_UPDATE_INTERFACE)
|
||||
.delete(&API_METHOD_DELETE_INTERFACE);
|
||||
|
||||
pub const ROUTER: Router = Router::new()
|
||||
.get(&API_METHOD_LIST_NETWORK_DEVICES);
|
||||
.get(&API_METHOD_LIST_NETWORK_DEVICES)
|
||||
.match_all("name", &ITEM_ROUTER);
|
||||
|
|
|
@ -236,7 +236,17 @@ fn acl_commands() -> CommandLineInterface {
|
|||
fn network_commands() -> CommandLineInterface {
|
||||
|
||||
let cmd_def = CliCommandMap::new()
|
||||
.insert("list", CliCommand::new(&api2::config::network::API_METHOD_LIST_NETWORK_DEVICES));
|
||||
.insert("list", CliCommand::new(&api2::config::network::API_METHOD_LIST_NETWORK_DEVICES))
|
||||
.insert("update",
|
||||
CliCommand::new(&api2::config::network::API_METHOD_UPDATE_INTERFACE)
|
||||
.arg_param(&["name"])
|
||||
.completion_cb("name", config::network::complete_interface_name)
|
||||
)
|
||||
.insert("remove",
|
||||
CliCommand::new(&api2::config::network::API_METHOD_DELETE_INTERFACE)
|
||||
.arg_param(&["name"])
|
||||
.completion_cb("name", config::network::complete_interface_name)
|
||||
);
|
||||
|
||||
cmd_def.into()
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::io::{Write};
|
||||
use std::collections::{HashSet, HashMap};
|
||||
|
||||
use anyhow::{Error, bail};
|
||||
use anyhow::{Error, format_err, bail};
|
||||
|
||||
use proxmox::tools::{fs::replace_file, fs::CreateOptions};
|
||||
|
||||
|
@ -184,6 +184,20 @@ impl NetworkConfig {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn lookup(&self, name: &str) -> Result<&Interface, Error> {
|
||||
let interface = self.interfaces.get(name).ok_or_else(|| {
|
||||
format_err!("interface '{}' does not exist.", name)
|
||||
})?;
|
||||
Ok(interface)
|
||||
}
|
||||
|
||||
pub fn lookup_mut(&mut self, name: &str) -> Result<&mut Interface, Error> {
|
||||
let interface = self.interfaces.get_mut(name).ok_or_else(|| {
|
||||
format_err!("interface '{}' does not exist.", name)
|
||||
})?;
|
||||
Ok(interface)
|
||||
}
|
||||
|
||||
pub fn write_config(&self, w: &mut dyn Write) -> Result<(), Error> {
|
||||
|
||||
let mut done = HashSet::new();
|
||||
|
@ -267,3 +281,11 @@ pub fn save_config(config: &NetworkConfig) -> Result<(), Error> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// shell completion helper
|
||||
pub fn complete_interface_name(_arg: &str, _param: &HashMap<String, String>) -> Vec<String> {
|
||||
match config() {
|
||||
Ok((data, _digest)) => data.interfaces.keys().map(|id| id.to_string()).collect(),
|
||||
Err(_) => return vec![],
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue