]>
Commit | Line | Data |
---|---|---|
81cc71c0 DM |
1 | use std::process::{Command, Stdio}; |
2 | ||
f7d4e4b5 | 3 | use anyhow::{Error}; |
81cc71c0 DM |
4 | use serde_json::{json, Value}; |
5 | use std::io::{BufRead,BufReader}; | |
6 | ||
68ed0c62 | 7 | use proxmox::api::{api, ApiMethod, Router, RpcEnvironment, Permission}; |
81cc71c0 DM |
8 | |
9 | use crate::api2::types::*; | |
68ed0c62 | 10 | use crate::config::acl::PRIV_SYS_AUDIT; |
81cc71c0 DM |
11 | |
12 | #[api( | |
13 | protected: true, | |
14 | input: { | |
15 | properties: { | |
16 | node: { | |
17 | schema: NODE_SCHEMA, | |
18 | }, | |
19 | since: { | |
20 | type: Integer, | |
21 | optional: true, | |
22 | description: "Display all log since this UNIX epoch. Conflicts with 'startcursor'.", | |
23 | minimum: 0, | |
24 | }, | |
25 | until: { | |
26 | type: Integer, | |
27 | optional: true, | |
28 | description: "Display all log until this UNIX epoch. Conflicts with 'endcursor'.", | |
29 | minimum: 0, | |
30 | }, | |
31 | lastentries: { | |
32 | type: Integer, | |
33 | optional: true, | |
34 | description: "Limit to the last X lines. Conflicts with a range.", | |
35 | minimum: 0, | |
36 | }, | |
37 | startcursor: { | |
38 | type: String, | |
39 | description: "Start after the given Cursor. Conflicts with 'since'.", | |
40 | optional: true, | |
41 | }, | |
42 | endcursor: { | |
43 | type: String, | |
44 | description: "End before the given Cursor. Conflicts with 'until'", | |
45 | optional: true, | |
46 | }, | |
47 | }, | |
48 | }, | |
49 | returns: { | |
50 | type: Array, | |
51 | description: "Returns a list of journal entries.", | |
52 | items: { | |
53 | type: String, | |
54 | description: "Line text.", | |
55 | }, | |
56 | }, | |
68ed0c62 DM |
57 | access: { |
58 | permission: &Permission::Privilege(&[], PRIV_SYS_AUDIT, false), | |
59 | }, | |
81cc71c0 DM |
60 | )] |
61 | /// Read syslog entries. | |
62 | fn get_journal( | |
63 | param: Value, | |
64 | _info: &ApiMethod, | |
65 | _rpcenv: &mut dyn RpcEnvironment, | |
66 | ) -> Result<Value, Error> { | |
67 | ||
68 | let mut args = vec![]; | |
69 | ||
70 | if let Some(lastentries) = param["lastentries"].as_u64() { | |
71 | args.push(String::from("-n")); | |
72 | args.push(format!("{}", lastentries)); | |
73 | } | |
74 | ||
75 | if let Some(since) = param["since"].as_str() { | |
76 | args.push(String::from("-b")); | |
77 | args.push(since.to_owned()); | |
78 | } | |
79 | ||
80 | if let Some(until) = param["until"].as_str() { | |
81 | args.push(String::from("-e")); | |
82 | args.push(until.to_owned()); | |
83 | } | |
84 | ||
85 | if let Some(startcursor) = param["startcursor"].as_str() { | |
86 | args.push(String::from("-f")); | |
87 | args.push(startcursor.to_owned()); | |
88 | } | |
89 | ||
90 | if let Some(endcursor) = param["endcursor"].as_str() { | |
91 | args.push(String::from("-t")); | |
92 | args.push(endcursor.to_owned()); | |
93 | } | |
94 | ||
95 | let mut lines: Vec<String> = vec![]; | |
96 | ||
97 | let mut child = Command::new("/usr/bin/mini-journalreader") | |
98 | .args(&args) | |
99 | .stdout(Stdio::piped()) | |
100 | .spawn()?; | |
101 | ||
102 | if let Some(ref mut stdout) = child.stdout { | |
103 | for line in BufReader::new(stdout).lines() { | |
104 | match line { | |
105 | Ok(line) => { | |
106 | lines.push(line); | |
107 | } | |
108 | Err(err) => { | |
109 | log::error!("reading journal failed: {}", err); | |
110 | let _ = child.kill(); | |
111 | break; | |
112 | } | |
113 | } | |
114 | } | |
115 | } | |
116 | ||
117 | let status = child.wait().unwrap(); | |
118 | if !status.success() { | |
119 | log::error!("journalctl failed with {}", status); | |
120 | } | |
121 | ||
122 | Ok(json!(lines)) | |
123 | } | |
124 | ||
125 | pub const ROUTER: Router = Router::new() | |
126 | .get(&API_METHOD_GET_JOURNAL); |