freeipmiUtil: implement IPMI reading using ipmi-sensors from FreeIPMI project (#220)

Also add an option tu use sudo non-interactively.
This commit is contained in:
Thomas Debesse
2021-11-20 07:27:18 +01:00
committed by GitHub
parent 308dfb9fbe
commit e4bc02da10
4 changed files with 166 additions and 3 deletions

View File

@@ -20,6 +20,7 @@ const liquidctlUtil = Me.imports.liquidctlUtil;
const smartctlUtil = Me.imports.smartctlUtil;
const nvmecliUtil = Me.imports.nvmecliUtil;
const BumblebeeNvidiaUtil = Me.imports.bumblebeeNvidiaUtil;
const FreeipmiUtil = Me.imports.freeipmiUtil;
const FreonItem = Me.imports.freonItem;
const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']);
@@ -67,8 +68,10 @@ const FreonMenuButton = GObject.registerClass(class Freon_FreonMenuButton extend
this._utils = {
sensors: new SensorsUtil.SensorsUtil()
};
this._initDriveUtility();
this._initGpuUtility();
this._initIpmiUtility();
this._initLiquidctlUtility();
let temperatureIcon = Gio.icon_new_for_string(Me.path + '/icons/material-icons/material-temperature-symbolic.svg');
@@ -108,6 +111,8 @@ const FreonMenuButton = GObject.registerClass(class Freon_FreonMenuButton extend
this._addSettingChangedSignal('show-voltage', this._querySensors.bind(this));
this._addSettingChangedSignal('drive-utility', this._driveUtilityChanged.bind(this));
this._addSettingChangedSignal('gpu-utility', this._gpuUtilityChanged.bind(this));
this._addSettingChangedSignal('ipmi-utility', this._ipmiUtilityChanged.bind(this));
this._addSettingChangedSignal('method-ipmi-utility', this._ipmiUtilityChanged.bind(this));
this._addSettingChangedSignal('show-liquidctl', this._liquidctlUtilityChanged.bind(this));
this._addSettingChangedSignal('position-in-panel', this._positionInPanelChanged.bind(this));
this._addSettingChangedSignal('panel-box-index', this._positionInPanelChanged.bind(this));
@@ -250,6 +255,27 @@ const FreonMenuButton = GObject.registerClass(class Freon_FreonMenuButton extend
this._querySensors();
}
_initIpmiUtility(){
switch(this._settings.get_string('ipmi-utility')){
case 'freeipmi':
this._utils.ipmi = new FreeipmiUtil.FreeipmiUtil();
break;
}
}
_destroyIpmiUtility(){
if(this._utils.ipmi){
this._utils.ipmi.destroy();
delete this._utils.ipmi;
}
}
_ipmiUtilityChanged(){
this._destroyIpmiUtility();
this._initIpmiUtility();
this._querySensors();
}
_initLiquidctlUtility() {
if (this._settings.get_boolean('show-liquidctl'))
this._utils.liquidctl = new liquidctlUtil.LiquidctlUtil();
@@ -288,6 +314,7 @@ const FreonMenuButton = GObject.registerClass(class Freon_FreonMenuButton extend
_onButtonDestroy(){
this._destroyDriveUtility();
this._destroyGpuUtility();
this._destroyIpmiUtility();
this._destroyLiquidctlUtility();
Mainloop.source_remove(this._timeoutId);
Mainloop.source_remove(this._updateUITimeoutId);
@@ -343,13 +370,12 @@ const FreonMenuButton = GObject.registerClass(class Freon_FreonMenuButton extend
}
_updateDisplay(){
let gpuTempInfo = this._utils.sensors.gpu;
let sensorsTempInfo = this._utils.sensors.temp;
let gpuTempInfo = this._utils.sensors.gpu;
if (this._utils.gpu && this._utils.gpu.available)
gpuTempInfo = gpuTempInfo.concat(this._utils.gpu.temp);
let sensorsTempInfo = this._utils.sensors.temp;
let fanInfo = [];
if (this._settings.get_boolean('show-fan-rpm'))
fanInfo = this._utils.sensors.rpm;
@@ -363,6 +389,14 @@ const FreonMenuButton = GObject.registerClass(class Freon_FreonMenuButton extend
driveTempInfo = driveTempInfo.concat(this._utils.disks.temp);
}
if (this._utils.ipmi && this._utils.ipmi.available) {
sensorsTempInfo = sensorsTempInfo.concat(this._utils.ipmi.temp);
if (this._settings.get_boolean('show-fan-rpm'))
fanInfo = fanInfo.concat(this._utils.ipmi.rpm);
if (this._settings.get_boolean('show-voltage'))
voltageInfo = voltageInfo.concat(this._utils.ipmi.volt);
}
if (this._utils.liquidctl && this._utils.liquidctl.available) {
sensorsTempInfo = sensorsTempInfo.concat(this._utils.liquidctl.temp);
if (this._settings.get_boolean('show-fan-rpm'))

View File

@@ -0,0 +1,100 @@
const GLib = imports.gi.GLib;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const CommandLineUtil = Me.imports.commandLineUtil;
var FreeipmiUtil = class extends CommandLineUtil.CommandLineUtil {
constructor() {
super();
const path = GLib.find_program_in_path('ipmi-sensors');
// --comma-separated-output: pseudo csv output format, splitting on comma may be good enough for the values we read.
this._argv = path ? [path, '--comma-separated-output'] : null;
if (this._argv) {
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
if (ExtensionUtils.getSettings().get_string('method-ipmi-utility') === 'sudo')
{
const sudo_path = GLib.find_program_in_path('sudo');
// --non-interactive: do not ask for password, return if no permission.
this._argv = sudo_path ? [sudo_path, '--non-interactive'].concat(this._argv) : null;
}
}
}
// Avoid parsing the data more than once.
execute(callback) {
super.execute(() => {
let data = [];
for (const line of this._output) {
if (!line)
continue;
const value_list = line.split(',');
if (value_list.length <= 1)
break;
const id = value_list[0];
if (id === 'ID')
continue;
const name = value_list[1];
const value = value_list[3];
const unit = value_list[4];
if (value !== 'N/A' && unit !== 'N/A') {
data[name] = {};
data[name]["value"] = value;
data[name]["unit"] = unit;
}
}
this._data = data;
callback();
});
}
get temp() {
return this._parseSensorsOutput(/^(C|C per minute)$/, 'temp');
}
get rpm() {
return this._parseSensorsOutput(/^RPM$/, 'rpm');
}
get volt() {
return this._parseSensorsOutput(/^V$/, 'volt');
}
_parseSensorsOutput(sensorFilter, sensorType) {
if(!this._data)
return [];
const data = this._data;
let sensors = [];
for (const name in data) {
if (!data.hasOwnProperty(name))
continue;
const value = data[name]["value"]
const unit = data[name]["unit"]
if (!sensorFilter.test(unit))
continue;
const feature = {
label: name,
[sensorType]: parseFloat(value)
};
sensors.push(feature);
}
return sensors;
}
};

View File

@@ -88,9 +88,26 @@ var FreonPrefsWidget = new GObject.registerClass(class Freon_FreonPrefsWidget ex
label: _('Video Card Temperature Utility')
});
this._addComboBox({
items : {
'none' : _('None'),
'freeipmi' : _('FreeIPMI') },
key: 'ipmi-utility', y : i, x : 0,
label: _('IPMI Sensors Utility')
});
this._addComboBox({
items : {
'direct' : 'Direct',
'sudo' : 'sudo' },
key: 'method-ipmi-utility', y : i, x : 1,
label: ''
});
this._addSwitch({key : 'show-liquidctl', y : i++, x : 3,
label : _('Show liquidctl Sensors'),
help : _('Show data from liquidctl v1.7.0 or later')});
}
_addSwitch(params){

View File

@@ -63,6 +63,18 @@
<description>Utility for detect video card temperature ('none', 'nvidia-settings' or 'aticonfig')</description>
</key>
<key type="s" name="ipmi-utility">
<default>'none'</default>
<summary>Utility for reading IPMI sensors</summary>
<description>Utility reading IPMI sensors ('none', 'freeipmi')</description>
</key>
<key type="s" name="method-ipmi-utility">
<default>'direct'</default>
<summary>Method to run IPMI utility</summary>
<description>Method to run IPMI utility</description>
</key>
<key type="b" name="show-liquidctl">
<default>false</default>
<summary>Show liquidctl sensors</summary>