From: Luca Vornheder <luca@vornheder.cloud>
To: pve-devel@lists.proxmox.com
Cc: Luca Vornheder <luca@vornheder.cloud>
Subject: [PATCH manager 1/3] api: nodes: add opt-in endpoint to read the local IPMI SEL
Date: Fri, 18 Sep 2026 18:45:07 +0200 [thread overview]
Message-ID: <20260918164509.46468-2-luca@vornheder.cloud> (raw)
In-Reply-To: <20260918164509.46468-1-luca@vornheder.cloud>
Add a per-node 'ipmi-sel' option to the node config and a new
GET /nodes/{node}/ipmi-sel endpoint, which returns the System Event Log
of the node's local BMC as parsed entries, read via 'ipmitool sel
elist'.
The feature is opt-in. As long as the option is not set, the endpoint
fails with 501 (Not Implemented), so clients can tell a disabled
feature apart from a real error. Access requires Sys.Syslog on the
node, like the other log endpoints.
With the 'download' parameter the raw ipmitool output is streamed as a
file instead, analogous to the task log download.
Signed-off-by: Luca Vornheder <luca@vornheder.cloud>
---
PVE/API2/Nodes.pm | 111 ++++++++++++++++++++++++++++++++++++++++++++++
PVE/NodeConfig.pm | 8 ++++
2 files changed, 119 insertions(+)
diff --git a/PVE/API2/Nodes.pm b/PVE/API2/Nodes.pm
index 2ca3244..bc3008a 100644
--- a/PVE/API2/Nodes.pm
+++ b/PVE/API2/Nodes.pm
@@ -239,6 +239,7 @@ __PACKAGE__->register_method({
{ name => 'firewall' },
{ name => 'hardware' },
{ name => 'hosts' },
+ { name => 'ipmi-sel' },
{ name => 'journal' },
{ name => 'lxc' },
{ name => 'migrateall' },
@@ -1124,6 +1125,116 @@ __PACKAGE__->register_method({
},
});
+my $ipmitool_bin = '/usr/bin/ipmitool';
+
+__PACKAGE__->register_method({
+ name => 'ipmi_sel',
+ path => 'ipmi-sel',
+ method => 'GET',
+ description =>
+ "Read this node's local IPMI System Event Log (SEL), as reported by its BMC."
+ . " Requires 'ipmitool' to be installed and a local IPMI interface to be present,"
+ . " and must be enabled first via the node's 'ipmi-sel' option.",
+ proxyto => 'node',
+ permissions => {
+ check => ['perm', '/nodes/{node}', ['Sys.Syslog']],
+ },
+ protected => 1,
+ download_allowed => 1,
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ node => get_standard_option('pve-node'),
+ download => {
+ type => 'boolean',
+ optional => 1,
+ description => "Whether to return the raw 'ipmitool sel elist' output as a"
+ . " downloadable file, instead of parsed JSON entries.",
+ },
+ },
+ },
+ returns => {
+ type => 'array',
+ items => {
+ type => 'object',
+ properties => {
+ id => { type => 'string' },
+ timestamp => { type => 'string', optional => 1 },
+ sensor => { type => 'string' },
+ description => { type => 'string' },
+ direction => { type => 'string', optional => 1 },
+ },
+ },
+ },
+ code => sub {
+ my ($param) = @_;
+
+ my $node = $param->{node};
+
+ my $conf = PVE::NodeConfig::load_config($node);
+ raise(
+ "IPMI SEL log is not enabled for this node, enable it in the node's"
+ . " 'Options' first.\n",
+ code => HTTP_NOT_IMPLEMENTED,
+ ) if !$conf->{'ipmi-sel'};
+
+ die "'ipmitool' is not installed\n" if !-x $ipmitool_bin;
+
+ if ($param->{download}) {
+ # needs a real pipe (fd), not an in-memory filehandle: the async
+ # streaming code in pve-http-server needs to select()/poll() on it
+ open(my $fh, '-|', $ipmitool_bin, 'sel', 'elist')
+ or die "could not run 'ipmitool sel elist' for download - $!\n";
+
+ return {
+ download => {
+ fh => $fh,
+ stream => 1,
+ 'content-type' => 'text/plain',
+ 'content-disposition' => "attachment; filename=\"ipmi-sel-${node}.log\"",
+ },
+ };
+ }
+
+ my $raw = '';
+ PVE::Tools::run_command(
+ [$ipmitool_bin, 'sel', 'elist'],
+ outfunc => sub {
+ my ($line) = @_;
+ $raw .= "$line\n";
+ },
+ );
+
+ my $entries = [];
+ for my $line (split(/\n/, $raw)) {
+ my @fields = map { s/^\s+|\s+$//gr } split(/\|/, $line);
+ my $id = shift @fields;
+ next if !defined($id) || $id !~ /^[0-9a-fA-F]+$/;
+
+ my $entry = { id => $id };
+
+ # normal format is '<id> | <date> | <time> | <sensor> | <description>
+ # [| <direction>]'; right after a BMC reset entries can lack a resolvable
+ # date and print a single 'Pre-Init Time-stamp' field instead.
+ if (@fields >= 2 && $fields[1] =~ m/^\d{2}:\d{2}:\d{2}$/) {
+ $entry->{timestamp} = (shift @fields) . ' ' . (shift @fields);
+ } elsif (@fields) {
+ $entry->{timestamp} = shift @fields;
+ }
+
+ $entry->{direction} = pop(@fields)
+ if @fields > 1 && $fields[-1] =~ m/^(?:Asserted|Deasserted)$/;
+
+ $entry->{sensor} = shift(@fields) // '';
+ $entry->{description} = join(' | ', @fields);
+
+ push @$entries, $entry;
+ }
+
+ return $entries;
+ },
+});
+
my $sslcert;
my $shell_cmd_map = {
diff --git a/PVE/NodeConfig.pm b/PVE/NodeConfig.pm
index cc1a2a2..d99a3fd 100644
--- a/PVE/NodeConfig.pm
+++ b/PVE/NodeConfig.pm
@@ -108,6 +108,14 @@ my $confdesc = {
default => 80,
optional => 1,
},
+ 'ipmi-sel' => {
+ description => "Enable the IPMI System Event Log (SEL) view for this node in the"
+ . " web interface. Reads the SEL of this node's local BMC via 'ipmitool', so"
+ . " that binary and a local IPMI interface need to be available on the node.",
+ type => 'boolean',
+ default => 0,
+ optional => 1,
+ },
};
my $wakeonlan_desc = {
--
2.50.1 (Apple Git-155)
next prev parent reply other threads:[~2026-09-21 7:55 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-18 16:45 [PATCH manager 0/3] add opt-in IPMI SEL log tab for nodes Luca Vornheder
2026-09-18 16:45 ` Luca Vornheder [this message]
2026-09-18 16:45 ` [PATCH manager 2/3] fix #7656: ui: node: add opt-in IPMI SEL log tab Luca Vornheder
2026-09-18 16:45 ` [PATCH manager 3/3] d/control: recommend ipmitool Luca Vornheder
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260918164509.46468-2-luca@vornheder.cloud \
--to=luca@vornheder.cloud \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox