diff --git a/debian/control b/debian/control index b5b382f2..74a1316a 100644 --- a/debian/control +++ b/debian/control @@ -27,6 +27,7 @@ Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, libjs-extjs (>= 6.0.1), fonts-font-awesome, + proxmox-mini-journalreader, proxmox-widget-toolkit, libzstd1 (>= 1.3.8), Description: Proxmox Backup Server daemon with tools and GUI diff --git a/src/api2/node.rs b/src/api2/node.rs index 778deaf1..5d5a9af3 100644 --- a/src/api2/node.rs +++ b/src/api2/node.rs @@ -6,10 +6,12 @@ mod time; mod network; mod dns; mod syslog; +mod journal; mod services; pub const SUBDIRS: SubdirMap = &[ ("dns", &dns::ROUTER), + ("journal", &journal::ROUTER), ("network", &network::ROUTER), ("services", &services::ROUTER), ("syslog", &syslog::ROUTER), diff --git a/src/api2/node/journal.rs b/src/api2/node/journal.rs new file mode 100644 index 00000000..aef67f18 --- /dev/null +++ b/src/api2/node/journal.rs @@ -0,0 +1,122 @@ +use std::process::{Command, Stdio}; + +use failure::*; +use serde_json::{json, Value}; +use std::io::{BufRead,BufReader}; + +use proxmox::api::{api, ApiMethod, Router, RpcEnvironment}; + +use crate::api2::types::*; + +#[api( + protected: true, + input: { + properties: { + node: { + schema: NODE_SCHEMA, + }, + since: { + type: Integer, + optional: true, + description: "Display all log since this UNIX epoch. Conflicts with 'startcursor'.", + minimum: 0, + }, + until: { + type: Integer, + optional: true, + description: "Display all log until this UNIX epoch. Conflicts with 'endcursor'.", + minimum: 0, + }, + lastentries: { + type: Integer, + optional: true, + description: "Limit to the last X lines. Conflicts with a range.", + minimum: 0, + }, + startcursor: { + type: String, + description: "Start after the given Cursor. Conflicts with 'since'.", + optional: true, + }, + endcursor: { + type: String, + description: "End before the given Cursor. Conflicts with 'until'", + optional: true, + }, + }, + }, + returns: { + type: Array, + description: "Returns a list of journal entries.", + items: { + type: String, + description: "Line text.", + }, + }, +)] +/// Read syslog entries. +fn get_journal( + param: Value, + _info: &ApiMethod, + _rpcenv: &mut dyn RpcEnvironment, +) -> Result { + + let mut args = vec![]; + + if let Some(lastentries) = param["lastentries"].as_u64() { + args.push(String::from("-n")); + args.push(format!("{}", lastentries)); + } + + if let Some(since) = param["since"].as_str() { + args.push(String::from("-b")); + args.push(since.to_owned()); + } + + if let Some(until) = param["until"].as_str() { + args.push(String::from("-e")); + args.push(until.to_owned()); + } + + if let Some(startcursor) = param["startcursor"].as_str() { + args.push(String::from("-f")); + args.push(startcursor.to_owned()); + } + + if let Some(endcursor) = param["endcursor"].as_str() { + args.push(String::from("-t")); + args.push(endcursor.to_owned()); + } + + let mut lines: Vec = vec![]; + + let mut child = Command::new("/usr/bin/mini-journalreader") + .args(&args) + .stdout(Stdio::piped()) + .spawn()?; + + if let Some(ref mut stdout) = child.stdout { + for line in BufReader::new(stdout).lines() { + match line { + Ok(line) => { + lines.push(line); + } + Err(err) => { + log::error!("reading journal failed: {}", err); + let _ = child.kill(); + break; + } + } + } + } + + let status = child.wait().unwrap(); + if !status.success() { + log::error!("journalctl failed with {}", status); + } + + Ok(json!(lines)) +} + +pub const ROUTER: Router = Router::new() + .get(&API_METHOD_GET_JOURNAL); diff --git a/www/ServerAdministration.js b/www/ServerAdministration.js index 24c0acf2..de3522d7 100644 --- a/www/ServerAdministration.js +++ b/www/ServerAdministration.js @@ -49,11 +49,10 @@ Ext.define('PBS.ServerAdministration', { nodename: 'localhost' }, { - xtype: 'proxmoxLogView', + xtype: 'proxmoxJournalView', itemId: 'logs', title: gettext('Syslog'), - url: "/api2/extjs/nodes/localhost/syslog", - log_select_timespan: 1 + url: "/api2/extjs/nodes/localhost/journal", }, { xtype: 'proxmoxNodeTasks',