1 use std
::sync
::{Arc, atomic::{AtomicUsize, Ordering}
};
3 use anyhow
::{bail, Error}
;
4 use serde_json
::{json, Value}
;
5 use tokio
::signal
::unix
::{signal, SignalKind}
;
8 use proxmox_router
::cli
::format_and_print_result
;
10 use pbs_api_types
::percent_encoding
::percent_encode_component
;
12 use super::HttpClient
;
14 /// Display task log on console
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.
20 pub async
fn display_task_log(
24 ) -> Result
<(), Error
> {
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
);
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
);
35 println
!("forced exit (task still running)");
42 let request_future
= async
move {
49 let abort
= abort_count
.load(Ordering
::Relaxed
);
51 let path
= format
!("api2/json/nodes/localhost/tasks/{}", percent_encode_component(upid_str
));
52 let _
= client
.delete(&path
, None
).await?
;
55 let param
= json
!({ "start": start, "limit": limit, "test-status": true }
);
57 let path
= format
!("api2/json/nodes/localhost/tasks/{}/log", percent_encode_component(upid_str
));
58 let result
= client
.get(&path
, Some(param
)).await?
;
60 let active
= result
["active"].as_bool().unwrap();
61 let total
= result
["total"].as_u64().unwrap();
62 let data
= result
["data"].as_array().unwrap();
64 let lines
= data
.len();
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] == ": " {
81 tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await;
85 } else if lines != limit {
86 bail!("got wrong number of lines from
server ({}
!= {}
)", lines, limit);
94 request = request_future.fuse() => request?,
95 abort = abort_future.fuse() => abort?,
101 /// Display task result (upid), or view task log - depending on output format
102 pub async fn view_task_result(
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?;
113 format_and_print_result(data, output_format);