ivanhao / pvetools

proxmox ve tools script(debian9+ can use it).Including email, samba, NFS set zfs max ram, nested virtualization ,docker , pci passthrough etc. for english user,please look the end of readme.
GNU General Public License v3.0
4.1k stars 501 forks source link

【功能增强】改善Web界面的数据显示,加上IPMI风扇信息 #67

Open lurenJBD opened 1 year ago

lurenJBD commented 1 year ago

非常抱歉没有按格式汇报,但这并非bug,只是我个人折腾后发一下,看看大家是否也有这样类似的需求。

一、改进CPU温度&频率 在Web端的显示效果

参考:Proxmox VE 顯示 CPU 當下的溫度 | BUBU 知識庫 & 秉迅資訊.Studio (freedomstu.com)

温度数据是通过lm-sensors获取,pvetools脚本会创建/usr/bin/s.sh 把获取的数据json化,然后再由PVE 的Node.js进行处理。

但Node.js也能用正则表达式来处理lm-sensors的数据。这也是我在看完上面那篇参考后才知道,所以就提及一下

使用的PVE版本:7.3-4

如果没使用过脚本进行配置显示频率温度的,先看这个部分,如果有用脚本配过,可以直接跳到第4步

第1步:安装 lm-sensors

apt install -y lm-sensors

第2步:加载相关的传感器模块

sensors-etect --auto

第3步:查看当前传感器的信息

sensors

正常情况下会有温度信息显示 image

第4步:创建显示频率的脚本,这里是直接用了pvetools里的脚本内容,非原创,感谢!

nano /usr/bin/GetCpuFrequency.sh

将以下内容复制进去

#!/usr/bin/bash
echo '{'$(lscpu|grep MHz|sed 's/CPU\ /CPU-/g'|sed 's/\ MHz/-MHz/g'|sed 's/\ //g'|sed 's/^/"/g'|sed 's/$/"\,/g'|sed 's/\:/\"\:\"/g'|awk 'BEGIN{ORS=""}{print $0}'|sed 's/\,$//g')'}'

其实我尝试过使用脚本的方式,直接把命令写到Nodes.pm之中,结果就是 Web界面会一直卡在加载中

第5步:编辑 /usr/share/perl5/PVE/API2/Nodes.pm

 nano /usr/share/perl5/PVE/API2/Nodes.pm 

在 第404行 后面添加内容,如果查找麻烦可以先把文件下载到本地用VSCode等文本编辑软件查找 PVE::pvecfg::version_text();

    $res->{pveversion} = PVE::pvecfg::package() . "/" .
        PVE::pvecfg::version_text();

    $res->{thermalstate} = `sensors`; # 添加这一行
        $res->{cpufrequency} = `/usr/bin/GetCpuFrequency.sh`; # 添加这一行

    my $dinfo = df('/', 1);     # output is bytes

    $res->{rootfs} = {
        total => $dinfo->{blocks},
        avail => $dinfo->{bavail},
        used => $dinfo->{used},
        free => $dinfo->{blocks} - $dinfo->{used},
    };

第6步:编辑/usr/share/pve-manager/js/pvemanagerlib.js

nano /usr/share/pve-manager/js/pvemanagerlib.js

在 第38526行 修改内容,可以通过查找alias: 'widget.pveNodeStatus' 快速定位。【记得清理注释内容,会报错】

修改这个内容是为了让状态框架能宽一点,显示更多的信息

Ext.define('PVE.node.StatusView', {
    extend: 'PVE.panel.StatusView',
    alias: 'widget.pveNodeStatus',

    height: 320, # 将这个预设的 300 改为 320
    bodyPadding: '20 15 20 15',

    layout: {
    type: 'table',
    columns: 2,
    tableAttrs: {
        style: {
        width: '100%'
        }
    }

在 第38637行 修改内容 可以通过查找textField: 'pveversion' 快速定位。【记得清理注释内容,会报错】

  {
        itemId: 'version',
        colspan: 2,
        printBar: false,
        title: gettext('PVE Manager Version'),
        textField: 'pveversion',
        value: ''
  }, # 这里需要补充一个 , 号不然会出问题
# 增加以下内容
    {
        itemId: 'frequency',
        colspan: 2,
        printBar: false,
        title: gettext('CPU 频率'),
        textField: 'cpufrequency',
        renderer:function(value){
            var d = JSON.parse(value);
            f0 = d['CPU-MHz'];
            f1 = d['CPU-min-MHz'];
            f2 = d['CPU-max-MHz'];
            return  `实时(Cur): ${f0} MHz | 最小(min): ${f1} MHz | 最大(max): ${f2} MHz `;
        }
    },
    {
        itemId: 'thermal',
        colspan: 2,
        printBar: false,
        title: gettext('CPU 温度'),
        textField: 'thermalstate',
        renderer:function(value){
            const p0 = value.match(/Package id 0.*?\+([\d\.]+)Â/)[1];
            const c0 = value.match(/Core 0.*?\+([\d\.]+)Â/)[1];
            const c1 = value.match(/Core 1.*?\+([\d\.]+)Â/)[1];
            const c2 = value.match(/Core 2.*?\+([\d\.]+)Â/)[1];
            const c3 = value.match(/Core 3.*?\+([\d\.]+)Â/)[1];
            return `Package: ${p0} ℃ | Core 0: ${c0} ℃ | Core 1: ${c1} ℃ | Core 2: ${c2} ℃ | Core 3: ${c3} ℃`
        }
    }

第7步:重启 pveproxy 服务

systemctl restart pveproxy

实际效果一览:

如果没生效,记得先清除网页缓存,或者使用Edge的InPrivate模式。

image 将宽度设置320可以把存储库状态给挡住,并且不像之前那样会有一大块的留白。

二、通过IPMI获取风扇转速 并 添加到Web界面上

首先需要主板支持IPMI才能实现这一功能,如果没有,那可以直接跳过。

第1步:安装 ipmitool

apt install -y ipmitool

验证一下能否获取风扇信息

ipmitool sdr type Fan

image

第2步:创建脚本,参考了前面的脚本,实现了输出json格式的数据

nano /usr/bin/GetFanSpeed.sh

粘贴以下内容到脚本中,记得要去修改为自己的BMC信息!!!【注意!此操作存在一定的安全风险,请熟知!!!】

#!/usr/bin/bash
echo '{'$(ipmitool -H <BMC IP地址> -U <BMC 用户名> -P <BMC 用户密码> sdr type Fan | grep RPM | awk -F"|" '{gsub(/ /,"",$1); gsub(/ /,"",$5); gsub(/RPM/,"",$5); print "\""$1"\":\""$5"\","}' | tr -d '\n' | sed '$ s/.$//')'}'

这里必须说一下,为什么需要使用参数去指定BMC信息。 因发现面板 www-date 账号权限不够,不能通过本地来访问IPMI,所以必须要指定BMC信息的才能实现正常的访问

原本在Shell里以root账户执行以下命令是没问题的

 echo '{'$(ipmitool sdr type Fan | grep RPM | awk -F"|" '{gsub(/ /,"",$1); gsub(/ /,"",$5); gsub(/RPM/,"",$5); print "\""$1"\":\""$5"\","}' | tr -d '\n' | sed '$ s/.$//')'}'

可以获得正确的信息反馈 image 但实际的界面是无内容显示 image

虽然这样做解决了问题,但存在一定的安全隐患,毕竟明文记录了 IPMI 的管理员信息!【超微的IPMI非管理员账户获取不了风扇信息】

接着我考虑去使用加密shell,避免密码泄露。

参考:Shell脚本加密与解密 - 腾讯云开发者社区-腾讯云 (tencent.com)

直接说结论吧。 结果就是

使用gzexe 能加密成功并且脚本可以正常运行,但这样会导致PVE的web页面刷新变得非常慢! 而且gzexe的加密很弱,几步操作就能解密【本质就是压缩】

使用shc 加密后的文件无法运行

后面想到,如果有人都拿到PVE的root权限了,那这个IPMI密码似乎也阻挡不了什么,毕竟在root账号下,ipmitool直接就能免密码进行操作了。

虽然尚不清楚PVE的Web页面中是否会有bug能让攻击者获取到这个脚本的内容,但我也没打算把PVE的Web页面开放到公网上去。毕竟是最底层的系统,想要远程访问还是有很多安全办法的。

接着的操作就很简单了,基本上就是照搬上面。

第3步:编辑 /usr/share/perl5/PVE/API2/Nodes.pm

在 第404行 后面添加内容,如果查找麻烦可以先把文件下载到本地用VSCode等文本编辑软件查找 PVE::pvecfg::version_text(); 【记得清理注释内容,会报错】

    $res->{pveversion} = PVE::pvecfg::package() . "/" .
        PVE::pvecfg::version_text();

    $res->{thermalstate} = `sensors`; # 获取CPU温度信息
        $res->{cpufrequency} = `/usr/bin/GetCpuFrequency.sh`; # 获取CPU频率信息
        $res->{getfanspeed} = `/usr/bin/GetFanSpeed.sh`; # 新添加一行,获取风扇信息

    my $dinfo = df('/', 1);     # output is bytes

    $res->{rootfs} = {
        total => $dinfo->{blocks},
        avail => $dinfo->{bavail},
        used => $dinfo->{used},
        free => $dinfo->{blocks} - $dinfo->{used},
    };

第4步:编辑 /usr/share/pve-manager/js/pvemanagerlib.js 在 第38637行 修改内容 可以通过查找textField: 'pveversion' 快速定位。【记得清理注释内容,会报错!】

  {
        itemId: 'version',
        colspan: 2,
        printBar: false,
        title: gettext('PVE Manager Version'),
        textField: 'pveversion',
        value: ''
  }, 
    {
        itemId: 'frequency',
        colspan: 2,
        printBar: false,
        title: gettext('CPU 频率'),
        textField: 'cpufrequency',
        renderer:function(value){
            var d = JSON.parse(value);
            f0 = d['CPU-MHz'];
            f1 = d['CPU-min-MHz'];
            f2 = d['CPU-max-MHz'];
            return  `实时(Cur): ${f0} MHz | 最小(min): ${f1} MHz | 最大(max): ${f2} MHz `;
        }
    },
    {
        itemId: 'thermal',
        colspan: 2,
        printBar: false,
        title: gettext('CPU 温度'),
        textField: 'thermalstate',
        renderer:function(value){
            const p0 = value.match(/Package id 0.*?\+([\d\.]+)Â/)[1];
            const c0 = value.match(/Core 0.*?\+([\d\.]+)Â/)[1];
            const c1 = value.match(/Core 1.*?\+([\d\.]+)Â/)[1];
            const c2 = value.match(/Core 2.*?\+([\d\.]+)Â/)[1];
            const c3 = value.match(/Core 3.*?\+([\d\.]+)Â/)[1];
            return `Package: ${p0} ℃ | Core 0: ${c0} ℃ | Core 1: ${c1} ℃ | Core 2: ${c2} ℃ | Core 3: ${c3} ℃`
        }
    },# 这里需要补充一个 , 号不然会出问题
# 增加以下内容
    {
        itemId: 'speed',
        colspan: 2,
        printBar: false,
        title: gettext('FAN 转速'),
        textField: 'getfanspeed',
        renderer:function(value){
            var d = JSON.parse(value);
            f0 = d['FAN1'];
            f1 = d['FAN2'];
            f2 = d['FAN3'];
            return  `FAN1: ${f0} RPM | FAN2: ${f1} RPM | FAN3: ${f2} RPM `;
        }
    }

第5步:重启 pveproxy 服务

systemctl restart pveproxy

实际效果一览:

如果没生效,记得先清除网页缓存,或者使用Edge的InPrivate模式。

image

当然如果你不想有留白的区域,想关掉一些信息显示,可以将/usr/share/pve-manager/js/pvemanagerlib.js里的这些内容删掉 image image

最终效果

image

处理器信息我手动改了,因为是ES版,没法正确识别。

suli3 commented 1 year ago

Nice job, 效果正是我需要的效果,不过我的是台R730xd有20个核的那种,核温显示的地方得改改