]> git.proxmox.com Git - proxmox-backup.git/blob - src/bin/proxmox_backup_manager/network.rs
001c905dda09bf0ba1eda2c6d3fb56aec7deb375
[proxmox-backup.git] / src / bin / proxmox_backup_manager / network.rs
1 use anyhow::Error;
2 use serde_json::Value;
3
4 use proxmox::api::{api, cli::*, RpcEnvironment, ApiHandler};
5
6 use proxmox_backup::api2;
7
8 #[api(
9 input: {
10 properties: {
11 "output-format": {
12 schema: OUTPUT_FORMAT,
13 optional: true,
14 },
15 }
16 }
17 )]
18 /// Network device list.
19 fn list_network_devices(mut param: Value, rpcenv: &mut dyn RpcEnvironment) -> Result<Value, Error> {
20
21 let output_format = get_output_format(&param);
22
23 param["node"] = "localhost".into();
24
25 let info = &api2::node::network::API_METHOD_LIST_NETWORK_DEVICES;
26 let mut data = match info.handler {
27 ApiHandler::Sync(handler) => (handler)(param, info, rpcenv)?,
28 _ => unreachable!(),
29 };
30
31 if let Value::String(ref diff) = rpcenv["changes"] {
32 if output_format == "text" {
33 eprintln!("pending changes:\n{}\n", diff);
34 }
35 }
36
37 fn render_address(_value: &Value, record: &Value) -> Result<String, Error> {
38 let mut text = String::new();
39
40 if let Some(cidr) = record["cidr"].as_str() {
41 text.push_str(cidr);
42 }
43 if let Some(cidr) = record["cidr6"].as_str() {
44 if !text.is_empty() { text.push('\n'); }
45 text.push_str(cidr);
46 }
47
48 Ok(text)
49 }
50
51 fn render_ports(_value: &Value, record: &Value) -> Result<String, Error> {
52 let mut text = String::new();
53
54 if let Some(ports) = record["bridge_ports"].as_array() {
55 let list: Vec<&str> = ports.iter().filter_map(|v| v.as_str()).collect();
56 text.push_str(&list.join(" "));
57 }
58 if let Some(slaves) = record["slaves"].as_array() {
59 let list: Vec<&str> = slaves.iter().filter_map(|v| v.as_str()).collect();
60 text.push_str(&list.join(" "));
61 }
62
63 Ok(text)
64 }
65
66 fn render_gateway(_value: &Value, record: &Value) -> Result<String, Error> {
67 let mut text = String::new();
68
69 if let Some(gateway) = record["gateway"].as_str() {
70 text.push_str(gateway);
71 }
72 if let Some(gateway) = record["gateway6"].as_str() {
73 if !text.is_empty() { text.push('\n'); }
74 text.push_str(gateway);
75 }
76
77 Ok(text)
78 }
79
80 let options = default_table_format_options()
81 .column(ColumnConfig::new("name"))
82 .column(ColumnConfig::new("type").header("type"))
83 .column(ColumnConfig::new("autostart"))
84 .column(ColumnConfig::new("method"))
85 .column(ColumnConfig::new("method6"))
86 .column(ColumnConfig::new("cidr").header("address").renderer(render_address))
87 .column(ColumnConfig::new("gateway").header("gateway").renderer(render_gateway))
88 .column(ColumnConfig::new("bridge_ports").header("ports/slaves").renderer(render_ports));
89
90 format_and_print_result_full(&mut data, &info.returns, &output_format, &options);
91
92 Ok(Value::Null)
93 }
94
95 #[api()]
96 /// Show pending configuration changes (diff)
97 fn pending_network_changes(mut param: Value, rpcenv: &mut dyn RpcEnvironment) -> Result<Value, Error> {
98 param["node"] = "localhost".into();
99
100 let info = &api2::node::network::API_METHOD_LIST_NETWORK_DEVICES;
101 let _data = match info.handler {
102 ApiHandler::Sync(handler) => (handler)(param, info, rpcenv)?,
103 _ => unreachable!(),
104 };
105
106 if let Value::String(ref diff) = rpcenv["changes"] {
107 println!("{}", diff);
108 }
109
110 Ok(Value::Null)
111 }
112
113 pub fn network_commands() -> CommandLineInterface {
114
115 let cmd_def = CliCommandMap::new()
116 .insert(
117 "list",
118 CliCommand::new(&API_METHOD_LIST_NETWORK_DEVICES)
119 )
120 .insert(
121 "changes",
122 CliCommand::new(&API_METHOD_PENDING_NETWORK_CHANGES)
123 )
124 .insert(
125 "create",
126 CliCommand::new(&api2::node::network::API_METHOD_CREATE_INTERFACE)
127 .fixed_param("node", String::from("localhost"))
128 .arg_param(&["iface"])
129 .completion_cb("iface", pbs_config::network::complete_interface_name)
130 .completion_cb("bridge_ports", pbs_config::network::complete_port_list)
131 .completion_cb("slaves", pbs_config::network::complete_port_list)
132 )
133 .insert(
134 "update",
135 CliCommand::new(&api2::node::network::API_METHOD_UPDATE_INTERFACE)
136 .fixed_param("node", String::from("localhost"))
137 .arg_param(&["iface"])
138 .completion_cb("iface", pbs_config::network::complete_interface_name)
139 .completion_cb("bridge_ports", pbs_config::network::complete_port_list)
140 .completion_cb("slaves", pbs_config::network::complete_port_list)
141 )
142 .insert(
143 "remove",
144 CliCommand::new(&api2::node::network::API_METHOD_DELETE_INTERFACE)
145 .fixed_param("node", String::from("localhost"))
146 .arg_param(&["iface"])
147 .completion_cb("iface", pbs_config::network::complete_interface_name)
148 )
149 .insert(
150 "revert",
151 CliCommand::new(&api2::node::network::API_METHOD_REVERT_NETWORK_CONFIG)
152 .fixed_param("node", String::from("localhost"))
153 )
154 .insert(
155 "reload",
156 CliCommand::new(&api2::node::network::API_METHOD_RELOAD_NETWORK_CONFIG)
157 .fixed_param("node", String::from("localhost"))
158 );
159
160 cmd_def.into()
161 }