From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [45.144.208.40]) by lore.proxmox.com (Postfix) with ESMTPS id B04FD1FF09C for ; Mon, 21 Sep 2026 09:55:03 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 1E912215BC; Mon, 21 Sep 2026 09:54:53 +0200 (CEST) X-ICL-RepId: 01a0b568-9b56-7efb-b748-f0d3d7c10aee X-ICL-Out-Info: HUtFAUMHWwJACUgATUQeDx5WFlZNRAJCTQBKHV8HUhxCC0kdXAdcEhVdRV8YVApyBlYKXQVSD1cCFxtfAkIPEhZdRUUCRQVaFV0dQUNUB10FXVhBDgpZEhhcFFxQWB5GElYNXQkZGkFeUBtfAkIPHBNWFRMdQxkPKwhKBEMHRQJeCyUTCVNWRB9LFlsIUw5AXloUXBhTS18ZXUUPXwdZBEAASQtcAV8HQABWB1sDXQpdC1VfGFQKcgZWCl0FUg9XAhcbXwJCDwxQTQFDCAoIRwNNF14yUwRfEVAW Dkim-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=vornheder.cloud; s=sig1; t=1789749927; x=1792341927; bh=ziNR/NreruypB/v2vbZcuVFWRVLH7RLXQA6tTPTpyxU=; h=From:To:Subject:Date:Message-ID:MIME-Version:x-icloud-hme; b=lvU6hmMYL9dE8ZaOckjfBCspif7nG4UuFP0NPcx0T2jgd4HXLgzAW7ahfGu17t2BzHg6n3aBFGcTk/Fm4jIEpKHFHSq5gr5SpizfXwa5HmmGT8mAMUfGFB4K29guRSJ5vbEM6bUm4o7sESd9DmV/q0cKv0xV5uUdX7FtotFnKxCC0u5dENQsn2fo04IyiMJzFqHy08WlQRucvTloUjmncnUhZkkTRuW2p/+SeEJk2MYjdAonJ8bzMqCCLzC4Tuv0j59w+8cu5rQt1407KR3tjzNzBK5Kmkc/WuBqKTGmOn7ZWe+Qy3LM0n9KiwdqY+U0wuSLZnfOTLk/u2haxoqMwg== mail-alias-created-date: 1637499663896 From: Luca Vornheder To: pve-devel@lists.proxmox.com 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 Message-ID: <20260918164509.46468-2-luca@vornheder.cloud> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260918164509.46468-1-luca@vornheder.cloud> References: <20260918164509.46468-1-luca@vornheder.cloud> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTE4MDI0MCBTYWx0ZWRfXwk5CsbyHdwsy Nc7E3rTwU9stBKQVt9VRZtvKHdwS++/DfUGxVIOWURYtIXyhsZ2l08MPvvO6p/KmqaqQezblFOl fpfKEm+XngI1DxvEOR5tm7tvgm/E8d0VZJlzFTkMVwMpFIcfWSdYYkPScLpYKLH5QuB0C2A39sF xmJtrVTVyxgcgU0Ep2DE3hWFWX80FC3x9C7Vij8l0qUr14cKmC1D1+cN8qgCEVwKlbdDz5zhuTx ud8ac0VUlF445d2ejHdHrdQu5UIVuWJSp/Amdr640DGtd3rB7SdKXQ5GceI5p5zwTtYuOyf8QdB FwwaxLzNWBQyaPuU8d0a3qsp94KoH57ye0ehw7QfIpk9nCfdgWQKcK78ghZ25A= X-Proofpoint-ORIG-GUID: NMPpD5fb7wjq-dS82cvgjj_BhNIgnYJ3 X-Authority-Info-Out: v=2.4 cv=I61ohdgg c=1 sm=1 tr=0 ts=6aad6aa6 cx=c_apl:c_pps:t_out a=bsP7O+dXZ5uKcj+dsLqiMw==:117 a=bsP7O+dXZ5uKcj+dsLqiMw==:17 a=MKtGQD3n3ToA:10 a=1oJP67jkp3AA:10 a=VdqzKS8jKosA:10 a=VkNPw1HP01LnGYTKEx00:22 a=jKt99cEZkSMgmKn8HNwA:9 X-Proofpoint-GUID: NMPpD5fb7wjq-dS82cvgjj_BhNIgnYJ3 X-JNJ: AAAAAAABp2uLr9E57YEe0k93SuSSd3nchCwiZ2SyxaEwgITWhAY6a6P8v/a6nGEkPPvdiTmZwa4AFPdEClV6CcEdAa2tQPFujuLe/sdCfdX5V5xYEOh4O7j/AqmleOXo3F4J2TFOnKjMKpMkW9PrfD0wyKNJmf14MGgLan5iLS92GxXTlPYfjF0LdYBgLRKrSKSK8akgl5inIGb1OE3/Cz1Vp6Ov0yAunVz0xTR+Nkr3e7iROJcKEisH02zxbGefZSq3C+iM1Tut69Q4FBZzVxlJkyTMI4fppnwqEVtJdiNTNTfL+8A0w3Z4CI7u48fR09NB9ha8adIRWiSd9bEVhBXef9sPRK0TgzPgjARTM/iInqIbtL+MyBK5jS9g+xO2GFJXroqf3J6gyTZ3IOr3LTrFfMKckbw+Far16Pgd1omf8xiMPRYDwpJ/nXEzvsDnrf2S/v9QKWGqzjg1yjtnQybgjJuKH7+Q0/4WXNfIMOEUhbPph6FimqDJOQgn512YlCvlBxtKIQX+WKUmrrJapR2d69RRJfvjGdzgrKVCIKBwb6zP6Tu64FZl6VTK0ODxDhq3p7JcDWpvZRBj1rOBXqfV4AwOS9xow2D/KIr3zSZMTcXWrFsh1PDb24sZ/whVOPJkkRZQCrTz7wqw8c7toCBzgm7JaNuDcOvIPyOqAoSRLwQSgA4LyCMEae4TZcdZFAyAIFDhCub3EvVR8bOVkMekE0+y/IGAu5cdP79MCBDX5fWS0nSAlePkAKYrSSeW7vviJwJbgR/gzbGkAaY= X-SPAM-LEVEL: Spam detection results: 0 AWL -0.150 Adjusted score from AWL reputation of From: address DKIM_INVALID 0.1 DKIM or DK signature exists, but is not valid DKIM_SIGNED 0.1 Message has a DKIM or DK signature, not necessarily valid DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment (newer systems) POISEN_SPAM_PILL 0.1 Meta: its spam POISEN_SPAM_PILL_1 0.1 random spam to be learned in bayes POISEN_SPAM_PILL_3 0.1 random spam to be learned in bayes SPF_HELO_PASS -0.001 SPF: HELO matches SPF record SPF_PASS -0.001 SPF: sender matches SPF record X-MailFrom: luca@vornheder.cloud X-Mailman-Rule-Hits: nonmember-moderation X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation Message-ID-Hash: ARNFLO2AIKHQDT4OUCKUAF5EU3B7SRQM X-Message-ID-Hash: ARNFLO2AIKHQDT4OUCKUAF5EU3B7SRQM X-Mailman-Approved-At: Mon, 21 Sep 2026 09:54:43 +0200 CC: Luca Vornheder X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: 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 --- 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 ' | |