]> git.proxmox.com Git - proxmox-backup.git/blame - pbs-client/src/task_log.rs
tree-wide: fix needless borrows
[proxmox-backup.git] / pbs-client / src / task_log.rs
CommitLineData
52f7a730
DM
1use std::sync::{Arc, atomic::{AtomicUsize, Ordering}};
2
f7d4e4b5 3use anyhow::{bail, Error};
4470eba5 4use serde_json::{json, Value};
52f7a730
DM
5use tokio::signal::unix::{signal, SignalKind};
6use futures::*;
5a0b484b 7
6ef1b649 8use proxmox_router::cli::format_and_print_result;
4470eba5 9
577095e2 10use pbs_api_types::percent_encoding::percent_encode_component;
4470eba5 11
4805edc4 12use super::HttpClient;
5a0b484b 13
52f7a730
DM
14/// Display task log on console
15///
16/// This polls the task API and prints the log to the console. It also
17/// catches interrupt signals, and sends a abort request to the task if
18/// the user presses CTRL-C. Two interrupts cause an immediate end of
19/// the loop. The task may still run in that case.
5a0b484b 20pub async fn display_task_log(
d4877712 21 client: &HttpClient,
5a0b484b
DM
22 upid_str: &str,
23 strip_date: bool,
24) -> Result<(), Error> {
25
52f7a730
DM
26 let mut signal_stream = signal(SignalKind::interrupt())?;
27 let abort_count = Arc::new(AtomicUsize::new(0));
28 let abort_count2 = Arc::clone(&abort_count);
5a0b484b 29
52f7a730
DM
30 let abort_future = async move {
31 while signal_stream.recv().await.is_some() {
32 println!("got shutdown request (SIGINT)");
33 let prev_count = abort_count2.fetch_add(1, Ordering::SeqCst);
34 if prev_count >= 1 {
35 println!("forced exit (task still running)");
36 break;
37 }
38 }
39 Ok::<_, Error>(())
40 };
5a0b484b 41
52f7a730 42 let request_future = async move {
5a0b484b 43
52f7a730
DM
44 let mut start = 1;
45 let limit = 500;
5a0b484b 46
52f7a730 47 loop {
5a0b484b 48
52f7a730
DM
49 let abort = abort_count.load(Ordering::Relaxed);
50 if abort > 0 {
4805edc4 51 let path = format!("api2/json/nodes/localhost/tasks/{}", percent_encode_component(upid_str));
52f7a730 52 let _ = client.delete(&path, None).await?;
5a0b484b 53 }
5a0b484b 54
52f7a730
DM
55 let param = json!({ "start": start, "limit": limit, "test-status": true });
56
4805edc4 57 let path = format!("api2/json/nodes/localhost/tasks/{}/log", percent_encode_component(upid_str));
52f7a730
DM
58 let result = client.get(&path, Some(param)).await?;
59
60 let active = result["active"].as_bool().unwrap();
61 let total = result["total"].as_u64().unwrap();
62 let data = result["data"].as_array().unwrap();
63
64 let lines = data.len();
65
66 for item in data {
67 let n = item["n"].as_u64().unwrap();
68 let t = item["t"].as_str().unwrap();
69 if n != start { bail!("got wrong line number in response data ({} != {}", n, start); }
70 if strip_date && t.len() > 27 && &t[25..27] == ": " {
71 let line = &t[27..];
72 println!("{}", line);
73 } else {
74 println!("{}", t);
75 }
76 start += 1;
77 }
78
79 if start > total {
80 if active {
81 tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await;
82 } else {
83 break;
84 }
85 } else if lines != limit {
86 bail!("got wrong number of lines from server ({} != {})", lines, limit);
5a0b484b 87 }
5a0b484b 88 }
52f7a730
DM
89
90 Ok(())
91 };
92
93 futures::select!{
94 request = request_future.fuse() => request?,
95 abort = abort_future.fuse() => abort?,
96 };
5a0b484b
DM
97
98 Ok(())
99}
4470eba5
DM
100
101/// Display task result (upid), or view task log - depending on output format
102pub async fn view_task_result(
d4877712 103 client: &HttpClient,
4470eba5
DM
104 result: Value,
105 output_format: &str,
106) -> Result<(), Error> {
107 let data = &result["data"];
108 if output_format == "text" {
109 if let Some(upid) = data.as_str() {
110 display_task_log(client, upid, true).await?;
111 }
112 } else {
9a37bd6c 113 format_and_print_result(data, output_format);
4470eba5
DM
114 }
115
116 Ok(())
117}