pve首页查看功耗拓展脚本

作者:TP唉 https://www.bilibili.com/read/cv26924314/?jump_opus=1 出处:bilibili

在这里插入图片描述

如图所示想要这全方位信息很难吗?不,很简单只需要在shell里粘贴两串代码轻松搞定!

命令1:(curl -Lf -o /tmp/temp.sh https://raw.githubusercontent.com/a904055262/PVE-manager-status/main/showtempcpufreq.sh || curl -Lf -o /tmp/temp.sh https://ghproxy.com/https://raw.githubusercontent.com/a904055262/PVE-manager-status/main/showtempcpufreq.sh) && chmod +x /tmp/temp.sh && /tmp/temp.sh remod

命令2:apt update ; apt install linux-cpupower && modprobe msr && echo msr > /etc/modules-load.d/turbostat-msr.conf && chmod +s /usr/sbin/turbostat && echo 成功!

完成之后记得到主页shift+F5刷新一下页面就可以显示了!

无法访问github

保存下面脚本到文件

然后就执行 bash xxx.sh remod

bash xxx.sh restore 回滚

#!/usr/bin/env bash

# version: 2023.9.5
#添加硬盘信息的控制变量,如果你想不显示硬盘信息就设置为false
#NVME硬盘
sNVMEInfo=true
#固态和机械硬盘
sODisksInfo=true
#debug,显示修改后的内容,用于调试
dmode=false

#脚本路径
sdir=$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd)
cd "$sdir"

sname=$(basename "${BASH_SOURCE[0]}")
sap=$sdir/$sname
echo 脚本路径:"$sap"

#需要修改的文件
np=/usr/share/perl5/PVE/API2/Nodes.pm
pvejs=/usr/share/pve-manager/js/pvemanagerlib.js
plibjs=/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js

if ! command -v sensors > /dev/null; then
	echo 你需要先安装 lm-sensors 和 linux-cpupower,脚本尝试给你自动安装
	if apt update ; apt install -y lm-sensors; then 
		echo lm-sensors 安装成功
		
		echo 尝试继续安装linux-cpupower获取功耗信息
		if apt install -y linux-cpupower;then
			echo linux-cpupower安装成功
		else
			echo -e "linux-cpupower安装失败,可能无法正常获取功耗信息,你可以使用\033[34mapt update ; apt install linux-cpupower && modprobe msr && echo msr > /etc/modules-load.d/turbostat-msr.conf && chmod +s /usr/sbin/turbostat && echo 成功!\033[0m 手动安装"
		fi
	else
		echo 脚本自动安装所需依赖失败
		echo -e "请使用蓝色命令:\033[34mapt update ; apt install -y lm-sensors linux-cpupower && chmod +s /usr/sbin/turbostat && echo 成功! \033[0m 手动安装后重新运行本脚本"
		echo 脚本退出
		exit 1
	fi
fi


#获取版本号
pvever=$(pveversion | awk -F"/" '{print $2}')
echo "你的PVE版本号:$pvever"

restore() {
	[ -e $np.$pvever.bak ]     && mv $np.$pvever.bak $np
	[ -e $pvejs.$pvever.bak ]  && mv $pvejs.$pvever.bak $pvejs
	[ -e $plibjs.$pvever.bak ] && mv $plibjs.$pvever.bak $plibjs
}

fail() {
	echo "修改失败,可能不兼容你的pve版本:$pvever,开始还原"
	restore
	echo 还原完成
	exit 1
}

#还原修改
case $1 in 
	restore)
		restore
		echo 已还原修改
		
		if [ "$2" != 'remod' ];then 
			echo -e "请刷新浏览器缓存:\033[31mShift+F5\033[0m"
			systemctl restart pveproxy
		else 
			echo -----
		fi
		
		exit 0
	;;
	remod)
		echo 强制重新修改
		echo -----------
		"$sap" restore remod > /dev/null 
		"$sap"
		exit 0
	;;
esac

#检测是否已经修改过
[ $(grep 'modbyshowtempfreq' $np $pvejs $plibjs | wc -l) -eq 3 ]  && {
	echo -e "
已经修改过,请勿重复修改
如果没有生效,或者页面一直转圈圈
请使用 \033[31mShift+F5\033[0m 刷新浏览器缓存
如果一直异常,请执行:\033[31m\"$sap\" restore\033[0m 命令,可以还原修改
如果想强制重新修改,请执行:\033[31m\"$sap\" remod\033[0m 命令,可以还原修改
"
	exit 1
}


contentfornp=/tmp/.contentfornp.tmp

[ -e /usr/sbin/turbostat ] && {
	modprobe msr
	chmod +s /usr/sbin/turbostat
}
echo msr > /etc/modules-load.d/turbostat-msr.conf

cat > $contentfornp << 'EOF'

#modbyshowtempfreq

$res->{thermalstate} = `sensors -A`;
$res->{cpuFreq} = `
	goverf=/sys/devices/system/cpu/cpufreq/policy0/scaling_governor
	maxf=/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_max_freq
	minf=/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_min_freq
	
	cat /proc/cpuinfo | grep -i  "cpu mhz"
	echo -n 'gov:'
	[ -f \$goverf ] && cat \$goverf || echo none
	echo -n 'min:'
	[ -f \$minf ] && cat \$minf || echo none
	echo -n 'max:'
	[ -f \$maxf ] && cat \$maxf || echo none
	echo -n 'pkgwatt:'
	[ -e /usr/sbin/turbostat ] && turbostat --quiet --cpu package --show "PkgWatt" -S sleep 0.25 2>&1 | tail -n1 

`;
EOF



contentforpvejs=/tmp/.contentforpvejs.tmp

cat > $contentforpvejs << 'EOF'
//modbyshowtempfreq
	{
		itemId: 'thermal',
		colspan: 2,
		printBar: false,
		title: gettext('温度(°C)'),
		textField: 'thermalstate',
		renderer:function(value){
			//value进来的值是有换行符的
			console.log(value)
			let b = value.trim().split(/\s+(?=^\w+-)/m).sort();
			let c = b.map(function (v){
				// 风扇转速数据,直接返回
				let fandata = v.match(/(?<=:\s+)[1-9]\d*(?=\s+RPM\s+)/ig)
				if ( fandata ) {
					return '风扇: ' + fandata.join(';')
				}
			
				let name = v.match(/^[^-]+/)[0].toUpperCase();
				
				let temp = v.match(/(?<=:\s+)[+-][\d.]+(?=.?°C)/g);
				// 某些没有数据的传感器,不是温度的传感器
				if ( temp ) {
					temp = temp.map(v => Number(v).toFixed(0))
					
					if (/coretemp/i.test(name)) {
						name = 'CPU';
						temp = temp[0] + ( temp.length > 1 ? ' ( ' +   temp.slice(1).join(' | ') + ' )' : '');
					} else {
						temp = temp[0];
					}
					
					let crit = v.match(/(?<=\bcrit\b[^+]+\+)\d+/);
					
					
					return name + ': ' + temp + ( crit? ` ,crit: ${crit[0]}` : '');
					
				} else {
					return 'null'
				}
				

			});
			console.log(c);
			// 排除null值的
			c=c.filter( v => ! /^null$/.test(v) )
			//console.log(c);
			//排序,把cpu温度放最前
			let cpuIdx = c.findIndex(v => /CPU/i.test(v) );
			if (cpuIdx > 0) {
				c.unshift(c.splice(cpuIdx, 1)[0]);
			}
			
			console.log(c)
			c = c.join(' | ');
			return c;
		 }
	},
	{
		  itemId: 'cpumhz',
		  colspan: 2,
		  printBar: false,
		  title: gettext('CPU频率(GHz)'),
		  textField: 'cpuFreq',
		  renderer:function(v){
			//return v;
			console.log(v);
			let m = v.match(/(?<=^cpu[^\d]+)\d+/img);
			let m2 = m.map( e => ( e / 1000 ).toFixed(1) );
			m2 = m2.join(' | ');
			
			let gov = v.match(/(?<=^gov:).+/im)[0].toUpperCase();
			
			let min = (v.match(/(?<=^min:).+/im)[0]);
			if ( min !== 'none' ) {
				min=(min/1000000).toFixed(1);
			}
			
			let max = (v.match(/(?<=^max:).+/im)[0])
			if ( max !== 'none' ) {
				max=(max/1000000).toFixed(1);
			}
			
			let watt= v.match(/(?<=^pkgwatt:)[\d.]+$/im);
			watt = watt? " | 功耗: " + (watt[0]/1).toFixed(1) + 'W' : '';
			
			return `${m2} | MAX: ${max} | MIN: ${min}${watt} | 调速器: ${gov}`
		 }
	},
EOF


#检测nvme硬盘
echo 检测系统中的NVME硬盘
nvi=0
if $sNVMEInfo;then
	for nvme in $(ls /dev/nvme[0-9] 2> /dev/null); do
		chmod +s /usr/sbin/smartctl

		cat >> $contentfornp << EOF
	\$res->{nvme$nvi} = \`smartctl $nvme -a -j\`;
EOF
		
		
		cat >> $contentforpvejs << EOF
		{
			  itemId: 'nvme${nvi}0',
			  colspan: 2,
			  printBar: false,
			  title: gettext('NVME${nvi}'),
			  textField: 'nvme${nvi}',
			  renderer:function(value){
				//return value;
				try{
					let  v = JSON.parse(value);
					//名字
					let model = v.model_name;
					if (! model) {
						return '找不到硬盘,直通或已被卸载';
					}
					// 温度
					let temp = v.temperature?.current;
					temp = ( temp !== undefined ) ? " | " + temp + '°C' : '' ;
					
					// 通电时间
					let pot = v.power_on_time?.hours;
					let poth = v.power_cycle_count;
					
					pot = ( pot !== undefined ) ? (" | 通电: " + pot + '时' + ( poth ? ',次: '+ poth : '' )) : '';
					
					// 读写
					let log = v.nvme_smart_health_information_log;
					let rw=''
					let health=''
					if (log) {
						let read = log.data_units_read;
						let write = log.data_units_written;
						read = read ? (log.data_units_read / 1956882).toFixed(1) + 'T' : '';
						write = write ? (log.data_units_written / 1956882).toFixed(1) + 'T' : '';
						if (read && write) {
							rw = ' | R/W: ' + read + '/' + write;
						}
						let pu = log.percentage_used;
						let me = log.media_errors;
						if ( pu !== undefined ) {
							health = ' | 健康: ' + ( 100 - pu ) + '%'
							if ( me !== undefined ) {
								health += ',0E: ' + me
							}
						}
					}

					// smart状态
					let smart = v.smart_status?.passed;
					if (smart === undefined ) {
						smart = '';
					} else {
						smart = ' | SMART: ' + (smart ? '正常' : '警告!');
					}
					
					
					let t = model  + temp + health + pot + rw + smart;
					//console.log(t);
					return t;
				}catch(e){
					return '无法获得有效消息';
				};

			 }
		},
EOF
		let nvi++
	done
fi
echo "已添加 $nvi 块NVME硬盘"



#检测机械键盘
echo 检测系统中的SATA固态和机械硬盘
sdi=0
if $sODisksInfo;then
	for sd in $(ls /dev/sd[a-z] 2> /dev/null);do
		chmod +s /usr/sbin/smartctl
		chmod +s /usr/sbin/hdparm
		#检测是否是真的机械键盘
		sdsn=$(awk -F '/' '{print $NF}' <<< $sd)
		sdcr=/sys/block/$sdsn/queue/rotational
		[ -f $sdcr ] || continue
		
		if [ "$(cat $sdcr)" = "0" ];then
			hddisk=false
			sdtype="固态硬盘$sdi"
		else
			hddisk=true
			sdtype="机械硬盘$sdi"
		fi
		
		#[] && 型条件判断,嵌套的条件判断的非 || 后面一定要写动作,否则会穿透到上一层的非条件
		#机械/固态硬盘输出信息逻辑,
		#如果硬盘不存在就输出空JSON

		cat >> $contentfornp << EOF
	\$res->{sd$sdi} = \`
		if [ -b $sd ];then
			if $hddisk && hdparm -C $sd | grep -iq 'standby';then
				echo '{"standy": true}'
			else
				smartctl $sd -a -j
			fi
		else
			echo '{}'
		fi
	\`;
EOF

		cat >> $contentforpvejs << EOF
		{
			  itemId: 'sd${sdi}0',
			  colspan: 2,
			  printBar: false,
			  title: gettext('${sdtype}'),
			  textField: 'sd${sdi}',
			  renderer:function(value){
				//return value;
				try{
					let  v = JSON.parse(value);
					console.log(v)
					if (v.standy === true) {
						return '休眠中'
					}
					
					//名字
					let model = v.model_name;
					if (! model) {
						return '找不到硬盘,直通或已被卸载';
					}
					// 温度
					let temp = v.temperature?.current;
					temp = ( temp !== undefined ) ? " | 温度: " + temp + '°C' : '' ;
					
					// 通电时间
					let pot = v.power_on_time?.hours;
					let poth = v.power_cycle_count;
					
					pot = ( pot !== undefined ) ? (" | 通电: " + pot + '时' + ( poth ? ',次: '+ poth : '' )) : '';
					
					// smart状态
					let smart = v.smart_status?.passed;
					if (smart === undefined ) {
						smart = '';
					} else {
						smart = ' | SMART: ' + (smart ? '正常' : '警告!');
					}
					
					
					let t = model + temp  + pot + smart;
					//console.log(t);
					return t;
				}catch(e){
					return '无法获得有效消息';
				};
			 }
		},
EOF
		let sdi++
	done
fi
echo "已添加 $sdi 块SATA固态和机械硬盘"

echo 开始修改nodes.pm文件
if ! grep -q 'modbyshowtempfreq' $np ;then
	[ ! -e $np.$pvever.bak ] && cp $np $np.$pvever.bak
	
	if [ "$(sed -n "/PVE::pvecfg::version_text()/{=;p;q}" "$np")" ];then #确认修改点
		#r追加文本后面必须跟回车,否则r 后面的文字都会被当成文件名,导致脚本出错
		sed -i "/PVE::pvecfg::version_text()/{
			r $contentfornp
		}" $np
		$dmode && sed -n "/PVE::pvecfg::version_text()/,+5p" $np
	else
		echo '找不到nodes.pm文件的修改点'
		
		fail
	fi
else
	echo 已经修改过
fi

echo 开始修改pvemanagerlib.js文件
if ! grep -q 'modbyshowtempfreq' $pvejs ;then
	[ ! -e $pvejs.$pvever.bak ]  && cp $pvejs $pvejs.$pvever.bak
	
	if [ "$(sed -n '/pveversion/,+3{
			/},/{=;p;q}
		}' $pvejs)" ];then 
		
		sed -i "/pveversion/,+3{
			/},/r $contentforpvejs
		}" $pvejs
		
		$dmode && sed -n "/pveversion/,+8p" $pvejs
	else
		echo '找不到pvemanagerlib.js文件的修改点'
		fail
	fi


	echo 修改页面高度
	#统计加了几条
	addRs=$(grep -c '\$res' $contentfornp)
	addHei=$(( 28 * addRs))
	$dmode && echo "添加了$addRs条内容,增加高度为:${addHei}px"


	#原高度300
	echo 修改左栏高度
	if [ "$(sed -n '/widget.pveNodeStatus/,+4{
			/height:/{=;p;q}
		}' $pvejs)" ]; then 
		
		#获取原高度
		wph=$(sed -n -E "/widget\.pveNodeStatus/,+4{
			/height:/{s/[^0-9]*([0-9]+).*/\1/p;q}
		}" $pvejs)
		
		sed -i -E "/widget\.pveNodeStatus/,+4{
			/height:/{
				s#[0-9]+#$(( wph + addHei))#
			}
		}" $pvejs
		
		$dmode && sed -n '/widget.pveNodeStatus/,+4{
			/height/{
				p;q
			}
		}' $pvejs

		#修改右边栏高度,让它和左边一样高,双栏的时候否则导致浮动出问题
		#原高度325
		echo 修改右栏高度和左栏一致,解决浮动错位
		if [ "$(sed -n '/nodeStatus:\s*nodeStatus/,+10{
				/minHeight:/{=;p;q}
			}' $pvejs)" ]; then 
			#获取原高度
			nph=$(sed -n -E '/nodeStatus:\s*nodeStatus/,+10{
				/minHeight:/{s/[^0-9]*([0-9]+).*/\1/p;q}
			}' "$pvejs")
			
			sed -i -E "/nodeStatus:\s*nodeStatus/,+10{
				/minHeight:/{
					s#[0-9]+#$(( nph + addHei - (nph - wph) ))#
				}
			}" $pvejs
			
			$dmode && sed -n '/nodeStatus:\s*nodeStatus/,+10{
				/minHeight/{
					p;q
				}
			}' $pvejs

		else
			echo 右边栏高度找不到修改点,修改失败
			
		fi

	else
		echo 找不到修改高度的修改点
		fail
	fi

else
	echo 已经修改过
fi


echo 温度,频率,硬盘信息相关修改已完成
echo ------------------------
echo ------------------------
echo 开始修改proxmoxlib.js文件
echo 去除订阅弹窗

if ! grep -q 'modbyshowtempfreq' $plibjs ;then

	[ ! -e $plibjs.$pvever.bak ] && cp $plibjs $plibjs.$pvever.bak
	
	if [ "$(sed -n '/\/nodes\/localhost\/subscription/{=;p;q}' $plibjs)" ];then 
		sed -i '/\/nodes\/localhost\/subscription/,+10{
			/res === null/{
				N
				s/(.*)/(false)/
				a //modbyshowtempfreq
			}
		}' $plibjs
		
		$dmode && sed -n "/\/nodes\/localhost\/subscription/,+10p" $plibjs
	else 
		echo 找不到修改点,放弃修改这个
	fi
else
	echo 已经修改过
fi
echo -e "------------------------
修改完成
请刷新浏览器缓存:\033[31mShift+F5\033[0m
如果你看到主页面提示连接错误或者没看到温度和频率,请按:\033[31mShift+F5\033[0m,刷新浏览器缓存!
如果你对效果不满意,请执行:\033[31m\"$sap\" restore\033[0m 命令,可以还原修改
"
systemctl restart pveproxy
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值