]> git.proxmox.com Git - proxmox-backup.git/blame - src/api2/node/syslog.rs
update to first proxmox crate split
[proxmox-backup.git] / src / api2 / node / syslog.rs
CommitLineData
a2479cfa
WB
1use std::process::{Command, Stdio};
2
f7d4e4b5 3use anyhow::{Error};
a2479cfa 4use serde_json::{json, Value};
4f9a7268 5
6ef1b649
WB
6use proxmox_router::{ApiMethod, Router, RpcEnvironment, Permission};
7use proxmox_schema::api;
552c2259 8
8cc3760e 9use pbs_api_types::{NODE_SCHEMA, SYSTEMD_DATETIME_FORMAT, PRIV_SYS_AUDIT};
4ebf0eab 10
04418868
DM
11fn dump_journal(
12 start: Option<u64>,
13 limit: Option<u64>,
14 since: Option<&str>,
15 until: Option<&str>,
16 service: Option<&str>,
17) -> Result<(u64, Vec<Value>), Error> {
18
d96d8273 19 let mut args = vec!["-o", "short", "--no-pager"];
04418868 20
e182ab4a
DM
21 if let Some(service) = service { args.extend(&["--unit", service]); }
22 if let Some(since) = since { args.extend(&["--since", since]); }
23 if let Some(until) = until { args.extend(&["--until", until]); }
04418868
DM
24
25 let mut lines: Vec<Value> = vec![];
26 let mut limit = limit.unwrap_or(50);
27 let start = start.unwrap_or(0);
28 let mut count: u64 = 0;
29
cbef49bf 30 let mut child = Command::new("journalctl")
04418868
DM
31 .args(&args)
32 .stdout(Stdio::piped())
33 .spawn()?;
34
35 use std::io::{BufRead,BufReader};
36
37 if let Some(ref mut stdout) = child.stdout {
38 for line in BufReader::new(stdout).lines() {
e182ab4a
DM
39 match line {
40 Ok(line) => {
41 count += 1;
42 if count < start { continue };
11377a47 43 if limit == 0 { continue };
e182ab4a
DM
44
45 lines.push(json!({ "n": count, "t": line }));
46
47 limit -= 1;
48 }
49 Err(err) => {
d96d8273 50 log::error!("reading journal failed: {}", err);
e182ab4a
DM
51 let _ = child.kill();
52 break;
53 }
54 }
04418868
DM
55 }
56 }
57
e182ab4a
DM
58 let status = child.wait().unwrap();
59 if !status.success() {
d96d8273 60 log::error!("journalctl failed with {}", status);
e182ab4a 61 }
04418868
DM
62
63 // HACK: ExtJS store.guaranteeRange() does not like empty array
64 // so we add a line
65 if count == 0 {
66 count += 1;
67 lines.push(json!({ "n": count, "t": "no content"}));
68 }
69
70 Ok((count, lines))
71}
4f9a7268 72
20197f7c
DM
73#[api(
74 protected: true,
75 input: {
76 properties: {
77 node: {
78 schema: NODE_SCHEMA,
79 },
80 start: {
81 type: Integer,
82 description: "Start line number.",
83 minimum: 0,
84 optional: true,
85 },
86 limit: {
87 type: Integer,
88 description: "Max. number of lines.",
89 optional: true,
90 minimum: 0,
91 },
92 since: {
93 type: String,
94 optional: true,
95 description: "Display all log since this date-time string.",
96 format: &SYSTEMD_DATETIME_FORMAT,
97 },
98 until: {
99 type: String,
100 optional: true,
101 description: "Display all log until this date-time string.",
102 format: &SYSTEMD_DATETIME_FORMAT,
103 },
104 service: {
105 type: String,
106 optional: true,
107 description: "Service ID.",
108 max_length: 128,
109 },
110 },
111 },
112 returns: {
113 type: Object,
114 description: "Returns a list of syslog entries.",
115 properties: {
116 n: {
117 type: Integer,
118 description: "Line number.",
119 },
120 t: {
121 type: String,
122 description: "Line text.",
123 }
124 },
125 },
e4681f9f 126 access: {
74c08a57 127 permission: &Permission::Privilege(&["system", "log"], PRIV_SYS_AUDIT, false),
e4681f9f 128 },
20197f7c
DM
129)]
130/// Read syslog entries.
6049b71f
DM
131fn get_syslog(
132 param: Value,
133 _info: &ApiMethod,
e8d1da6a 134 mut rpcenv: &mut dyn RpcEnvironment,
6049b71f 135) -> Result<Value, Error> {
4f9a7268 136
1d8f8494
DC
137 let service = if let Some(service) = param["service"].as_str() {
138 Some(crate::api2::node::services::real_service_name(service))
139 } else {
140 None
141 };
142
04418868
DM
143 let (count, lines) = dump_journal(
144 param["start"].as_u64(),
145 param["limit"].as_u64(),
146 param["since"].as_str(),
147 param["until"].as_str(),
1d8f8494 148 service)?;
04418868 149
e8d1da6a 150 rpcenv["total"] = Value::from(count);
4f9a7268 151
04418868 152 Ok(json!(lines))
4f9a7268
DM
153}
154
255f378a 155pub const ROUTER: Router = Router::new()
20197f7c 156 .get(&API_METHOD_GET_SYSLOG);
4f9a7268 157