]> git.proxmox.com Git - proxmox-backup.git/commitdiff
src/api2/config/network.rs: improve network api
authorDietmar Maurer <dietmar@proxmox.com>
Wed, 22 Apr 2020 08:54:07 +0000 (10:54 +0200)
committerDietmar Maurer <dietmar@proxmox.com>
Wed, 22 Apr 2020 08:54:07 +0000 (10:54 +0200)
src/api2/config/network.rs
src/bin/proxmox-backup-manager.rs
src/config/network.rs

index 6f6de282b10289f29e42b9b23e8e7e4ac72fa180..69df0670fe85c902d6649455ec0367b091aaea6c 100644 (file)
@@ -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);
index 0f8164d3d8347091dd6a1acef99a374ba64f1da4..4a2904b3d64f81c55d85a161c0f5b67cb18423cb 100644 (file)
@@ -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()
 }
index c493a26f3a0b59a782b859201e27e50ed5b80cf1..bb5ef30ea6d7ed9f0b4eb14c17c2f69e607f718c 100644 (file)
@@ -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![],
+    }
+}