]> git.proxmox.com Git - proxmox-backup.git/blob - src/bin/proxmox-backup-manager.rs
src/bin/proxmox-backup-manager.rs: add task management cli
[proxmox-backup.git] / src / bin / proxmox-backup-manager.rs
1 use failure::*;
2 use serde_json::{json, Value};
3
4 use proxmox::api::{api, cli::*};
5
6 use proxmox_backup::tools;
7 use proxmox_backup::config;
8 use proxmox_backup::api2::types::*;
9 use proxmox_backup::client::*;
10 use proxmox_backup::tools::ticket::*;
11 use proxmox_backup::auth_helpers::*;
12
13
14 async fn view_task_result(
15 client: HttpClient,
16 result: Value,
17 output_format: &str,
18 ) -> Result<(), Error> {
19 let data = &result["data"];
20 if output_format == "text" {
21 if let Some(upid) = data.as_str() {
22 display_task_log(client, upid, true).await?;
23 }
24 } else {
25 format_and_print_result(&data, &output_format);
26 }
27
28 Ok(())
29 }
30
31 fn connect() -> Result<HttpClient, Error> {
32
33 let uid = nix::unistd::Uid::current();
34
35 let client = if uid.is_root() {
36 let ticket = assemble_rsa_ticket(private_auth_key(), "PBS", Some("root@pam"), None)?;
37 HttpClient::new("localhost", "root@pam", Some(ticket))?
38 } else {
39 HttpClient::new("localhost", "root@pam", None)?
40 };
41
42 Ok(client)
43 }
44
45 fn datastore_commands() -> CommandLineInterface {
46
47 use proxmox_backup::api2;
48
49 let cmd_def = CliCommandMap::new()
50 .insert("list", CliCommand::new(&api2::config::datastore::GET))
51 .insert("create",
52 CliCommand::new(&api2::config::datastore::POST)
53 .arg_param(&["name", "path"])
54 )
55 .insert("remove",
56 CliCommand::new(&api2::config::datastore::DELETE)
57 .arg_param(&["name"])
58 .completion_cb("name", config::datastore::complete_datastore_name)
59 );
60
61 cmd_def.into()
62 }
63
64
65 #[api(
66 input: {
67 properties: {
68 store: {
69 schema: DATASTORE_SCHEMA,
70 },
71 "output-format": {
72 schema: OUTPUT_FORMAT,
73 optional: true,
74 },
75 }
76 }
77 )]
78 /// Start garbage collection for a specific datastore.
79 async fn start_garbage_collection(param: Value) -> Result<Value, Error> {
80
81 let output_format = param["output-format"].as_str().unwrap_or("text").to_owned();
82
83 let store = tools::required_string_param(&param, "store")?;
84
85 let mut client = connect()?;
86
87 let path = format!("api2/json/admin/datastore/{}/gc", store);
88
89 let result = client.post(&path, None).await?;
90
91 view_task_result(client, result, &output_format).await?;
92
93 Ok(Value::Null)
94 }
95
96 #[api(
97 input: {
98 properties: {
99 store: {
100 schema: DATASTORE_SCHEMA,
101 },
102 "output-format": {
103 schema: OUTPUT_FORMAT,
104 optional: true,
105 },
106 }
107 }
108 )]
109 /// Show garbage collection status for a specific datastore.
110 async fn garbage_collection_status(param: Value) -> Result<Value, Error> {
111
112 let output_format = param["output-format"].as_str().unwrap_or("text").to_owned();
113
114 let store = tools::required_string_param(&param, "store")?;
115
116 let client = connect()?;
117
118 let path = format!("api2/json/admin/datastore/{}/gc", store);
119
120 let result = client.get(&path, None).await?;
121 let data = &result["data"];
122 if output_format == "text" {
123 format_and_print_result(&data, "json-pretty");
124 } else {
125 format_and_print_result(&data, &output_format);
126 }
127
128 Ok(Value::Null)
129 }
130
131 fn garbage_collection_commands() -> CommandLineInterface {
132
133 let cmd_def = CliCommandMap::new()
134 .insert("status",
135 CliCommand::new(&API_METHOD_GARBAGE_COLLECTION_STATUS)
136 .arg_param(&["store"])
137 .completion_cb("store", config::datastore::complete_datastore_name)
138 )
139 .insert("start",
140 CliCommand::new(&API_METHOD_START_GARBAGE_COLLECTION)
141 .arg_param(&["store"])
142 .completion_cb("store", config::datastore::complete_datastore_name)
143 );
144
145 cmd_def.into()
146 }
147
148 #[api(
149 input: {
150 properties: {
151 limit: {
152 description: "The maximal number of tasks to list.",
153 type: Integer,
154 optional: true,
155 minimum: 1,
156 maximum: 1000,
157 default: 50,
158 },
159 "output-format": {
160 schema: OUTPUT_FORMAT,
161 optional: true,
162 },
163 all: {
164 type: Boolean,
165 description: "Also list stopped tasks.",
166 optional: true,
167 }
168 }
169 }
170 )]
171 /// List running server tasks.
172 async fn task_list(param: Value) -> Result<Value, Error> {
173
174 let output_format = param["output-format"].as_str().unwrap_or("text").to_owned();
175
176 let client = connect()?;
177
178 let limit = param["limit"].as_u64().unwrap_or(50) as usize;
179 let running = !param["all"].as_bool().unwrap_or(false);
180 let args = json!({
181 "running": running,
182 "start": 0,
183 "limit": limit,
184 });
185 let result = client.get("api2/json/nodes/localhost/tasks", Some(args)).await?;
186
187 let data = &result["data"];
188
189 if output_format == "text" {
190 for item in data.as_array().unwrap() {
191 println!(
192 "{} {}",
193 item["upid"].as_str().unwrap(),
194 item["status"].as_str().unwrap_or("running"),
195 );
196 }
197 } else {
198 format_and_print_result(data, &output_format);
199 }
200
201 Ok(Value::Null)
202 }
203
204 #[api(
205 input: {
206 properties: {
207 upid: {
208 schema: UPID_SCHEMA,
209 },
210 }
211 }
212 )]
213 /// Display the task log.
214 async fn task_log(param: Value) -> Result<Value, Error> {
215
216 let upid = tools::required_string_param(&param, "upid")?;
217
218 let client = connect()?;
219
220 display_task_log(client, upid, true).await?;
221
222 Ok(Value::Null)
223 }
224
225 #[api(
226 input: {
227 properties: {
228 upid: {
229 schema: UPID_SCHEMA,
230 },
231 }
232 }
233 )]
234 /// Try to stop a specific task.
235 async fn task_stop(param: Value) -> Result<Value, Error> {
236
237 let upid_str = tools::required_string_param(&param, "upid")?;
238
239 let mut client = connect()?;
240
241 let path = format!("api2/json/nodes/localhost/tasks/{}", upid_str);
242 let _ = client.delete(&path, None).await?;
243
244 Ok(Value::Null)
245 }
246
247 fn task_mgmt_cli() -> CommandLineInterface {
248
249 let task_log_cmd_def = CliCommand::new(&API_METHOD_TASK_LOG)
250 .arg_param(&["upid"]);
251
252 let task_stop_cmd_def = CliCommand::new(&API_METHOD_TASK_STOP)
253 .arg_param(&["upid"]);
254
255 let cmd_def = CliCommandMap::new()
256 .insert("list", CliCommand::new(&API_METHOD_TASK_LIST))
257 .insert("log", task_log_cmd_def)
258 .insert("stop", task_stop_cmd_def);
259
260 cmd_def.into()
261 }
262
263 fn main() {
264
265 let cmd_def = CliCommandMap::new()
266 .insert("datastore", datastore_commands())
267 .insert("garbage-collection", garbage_collection_commands())
268 .insert("task", task_mgmt_cli());
269
270 run_cli_command(cmd_def);
271 }