1 use anyhow
::{Error, bail}
;
2 use serde_json
::{Value, to_value}
;
3 use ::serde
::{Deserialize, Serialize}
;
5 use proxmox
::api
::{api, ApiMethod, Router, RpcEnvironment, Permission}
;
7 use crate::config
::network
;
8 use crate::config
::acl
::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY}
;
9 use crate::api2
::types
::*;
16 description
: "List network devices (with config digest).",
23 permission
: &Permission
::Privilege(&[], PRIV_SYS_AUDIT
, false),
26 /// List all datastores
27 pub fn list_network_devices(
30 _rpcenv
: &mut dyn RpcEnvironment
,
31 ) -> Result
<Value
, Error
> {
33 let (config
, digest
) = network
::config()?
;
34 let digest
= proxmox
::tools
::digest_to_hex(&digest
);
36 let mut list
= Vec
::new();
38 for interface
in config
.interfaces
.values() {
39 let mut item
: Value
= to_value(interface
)?
;
40 item
["digest"] = digest
.clone().into();
51 schema
: NETWORK_INTERFACE_NAME_SCHEMA
,
56 description
: "The network interface configuration (with config digest).",
60 permission
: &Permission
::Privilege(&[], PRIV_SYS_AUDIT
, false),
63 /// Read a network interface configuration.
64 pub fn read_interface(name
: String
) -> Result
<Value
, Error
> {
66 let (config
, digest
) = network
::config()?
;
68 let interface
= config
.lookup(&name
)?
;
70 let mut data
: Value
= to_value(interface
)?
;
71 data
["digest"] = proxmox
::tools
::digest_to_hex(&digest
).into();
77 #[derive(Serialize, Deserialize)]
78 #[allow(non_camel_case_types)]
79 /// Deletable property name
80 pub enum DeletableProperty
{
81 /// Delete the IPv4 address property.
83 /// Delete the IPv6 address property.
85 /// Delete the IPv4 gateway property.
87 /// Delete the IPv6 gateway property.
89 /// Delete the whole IPv4 configuration entry.
91 /// Delete the whole IPv6 configuration entry.
93 /// Delete IPv4 comments
95 /// Delete IPv6 comments
101 /// Delete bridge ports (set to 'none')
103 /// Delete bond-slaves (set to 'none')
113 schema
: NETWORK_INTERFACE_NAME_SCHEMA
,
116 description
: "Autostart interface.",
121 type: NetworkConfigMethod
,
125 type: NetworkConfigMethod
,
129 description
: "Comments (inet)",
134 description
: "Comments (inet6)",
147 description
: "Maximum Transmission Unit.",
154 schema
: NETWORK_INTERFACE_LIST_SCHEMA
,
158 schema
: NETWORK_INTERFACE_LIST_SCHEMA
,
162 description
: "List of properties to delete.",
166 type: DeletableProperty
,
171 schema
: PROXMOX_CONFIG_DIGEST_SCHEMA
,
176 permission
: &Permission
::Privilege(&[], PRIV_SYS_MODIFY
, false),
179 /// Update network interface config.
180 pub fn update_interface(
183 method_v4
: Option
<NetworkConfigMethod
>,
184 method_v6
: Option
<NetworkConfigMethod
>,
185 comments_v4
: Option
<String
>,
186 comments_v6
: Option
<String
>,
187 address
: Option
<String
>,
188 gateway
: Option
<String
>,
190 bridge_ports
: Option
<Vec
<String
>>,
191 bond_slaves
: Option
<Vec
<String
>>,
192 delete
: Option
<Vec
<DeletableProperty
>>,
193 digest
: Option
<String
>,
194 ) -> Result
<(), Error
> {
196 let _lock
= crate::tools
::open_file_locked(network
::NETWORK_LOCKFILE
, std
::time
::Duration
::new(10, 0))?
;
198 let (mut config
, expected_digest
) = network
::config()?
;
200 if let Some(ref digest
) = digest
{
201 let digest
= proxmox
::tools
::hex_to_digest(digest
)?
;
202 crate::tools
::detect_modified_configuration_file(&digest
, &expected_digest
)?
;
205 let current_gateway_v4
= config
.interfaces
.iter()
206 .find(|(_
, interface
)| interface
.gateway_v4
.is_some())
207 .map(|(name
, _
)| name
.to_string());
209 let current_gateway_v6
= config
.interfaces
.iter()
210 .find(|(_
, interface
)| interface
.gateway_v4
.is_some())
211 .map(|(name
, _
)| name
.to_string());
213 let interface
= config
.lookup_mut(&name
)?
;
215 if let Some(delete
) = delete
{
216 for delete_prop
in delete
{
218 DeletableProperty
::address_v4
=> { interface.cidr_v4 = None; }
,
219 DeletableProperty
::address_v6
=> { interface.cidr_v6 = None; }
,
220 DeletableProperty
::gateway_v4
=> { interface.gateway_v4 = None; }
,
221 DeletableProperty
::gateway_v6
=> { interface.gateway_v6 = None; }
,
222 DeletableProperty
::method_v4
=> { interface.method_v4 = None; }
,
223 DeletableProperty
::method_v6
=> { interface.method_v6 = None; }
,
224 DeletableProperty
::comments_v4
=> { interface.comments_v4 = Vec::new(); }
,
225 DeletableProperty
::comments_v6
=> { interface.comments_v6 = Vec::new(); }
,
226 DeletableProperty
::mtu
=> { interface.mtu = None; }
,
227 DeletableProperty
::auto => { interface.auto = false; }
,
228 DeletableProperty
::bridge_ports
=> { interface.set_bridge_ports(Vec::new())?; }
229 DeletableProperty
::bond_slaves
=> { interface.set_bond_slaves(Vec::new())?; }
234 if let Some(auto) = auto { interface.auto = auto; }
235 if method_v4
.is_some() { interface.method_v4 = method_v4; }
236 if method_v6
.is_some() { interface.method_v6 = method_v6; }
237 if mtu
.is_some() { interface.mtu = mtu; }
238 if let Some(ports
) = bridge_ports { interface.set_bridge_ports(ports)?; }
239 if let Some(slaves
) = bond_slaves { interface.set_bond_slaves(slaves)?; }
241 if let Some(address
) = address
{
242 let (_
, _
, is_v6
) = network
::parse_cidr(&address
)?
;
244 interface
.cidr_v6
= Some(address
);
246 interface
.cidr_v4
= Some(address
);
250 if let Some(gateway
) = gateway
{
251 let is_v6
= gateway
.contains('
:'
);
253 if let Some(current_gateway_v6
) = current_gateway_v6
{
254 if current_gateway_v6
!= name
{
255 bail
!("Default IPv6 gateway already exists on interface '{}'", current_gateway_v6
);
258 interface
.gateway_v6
= Some(gateway
);
260 if let Some(current_gateway_v4
) = current_gateway_v4
{
261 if current_gateway_v4
!= name
{
262 bail
!("Default IPv4 gateway already exists on interface '{}'", current_gateway_v4
);
265 interface
.gateway_v4
= Some(gateway
);
269 if let Some(comments
) = comments_v4
{
270 interface
.comments_v4
= comments
.lines().map(String
::from
).collect();
273 if let Some(comments
) = comments_v6
{
274 interface
.comments_v6
= comments
.lines().map(String
::from
).collect();
277 network
::save_config(&config
)?
;
287 schema
: NETWORK_INTERFACE_NAME_SCHEMA
,
291 schema
: PROXMOX_CONFIG_DIGEST_SCHEMA
,
296 permission
: &Permission
::Privilege(&[], PRIV_SYS_MODIFY
, false),
299 /// Remove network interface configuration.
300 pub fn delete_interface(name
: String
, digest
: Option
<String
>) -> Result
<(), Error
> {
302 let _lock
= crate::tools
::open_file_locked(network
::NETWORK_LOCKFILE
, std
::time
::Duration
::new(10, 0))?
;
304 let (mut config
, expected_digest
) = network
::config()?
;
306 if let Some(ref digest
) = digest
{
307 let digest
= proxmox
::tools
::hex_to_digest(digest
)?
;
308 crate::tools
::detect_modified_configuration_file(&digest
, &expected_digest
)?
;
311 let _interface
= config
.lookup(&name
)?
; // check if interface exists
313 config
.interfaces
.remove(&name
);
315 network
::save_config(&config
)?
;
320 const ITEM_ROUTER
: Router
= Router
::new()
321 .get(&API_METHOD_READ_INTERFACE
)
322 .put(&API_METHOD_UPDATE_INTERFACE
)
323 .delete(&API_METHOD_DELETE_INTERFACE
);
325 pub const ROUTER
: Router
= Router
::new()
326 .get(&API_METHOD_LIST_NETWORK_DEVICES
)
327 .match_all("name", &ITEM_ROUTER
);