427 lines
15 KiB
Python
427 lines
15 KiB
Python
#!/bin/python
|
||
# coding: utf-8
|
||
# +-------------------------------------------------------------------
|
||
# | django-vue-lyadmin
|
||
# +-------------------------------------------------------------------
|
||
# | Author: lybbn
|
||
# +-------------------------------------------------------------------
|
||
# | QQ: 1042594286
|
||
# +-------------------------------------------------------------------
|
||
|
||
# ------------------------------
|
||
# linux系统命令工具类封装
|
||
# ------------------------------
|
||
import pwd
|
||
import grp
|
||
import os, sys, re, time, json
|
||
import psutil
|
||
from django.core.cache import cache
|
||
from config import EXEC_LOG_PATH
|
||
from pathlib import Path
|
||
import subprocess
|
||
import platform
|
||
|
||
BASE_DIR = Path(__file__).resolve().parent
|
||
|
||
|
||
def md5(strings):
|
||
"""
|
||
@name 生成md5
|
||
@param strings 要被处理的字符串
|
||
@return string(32)
|
||
"""
|
||
if type(strings) != bytes:
|
||
strings = strings.encode()
|
||
import hashlib
|
||
m = hashlib.md5()
|
||
m.update(strings)
|
||
return m.hexdigest()
|
||
|
||
|
||
def WriteLog(logMsg):
|
||
"""
|
||
写日志
|
||
"""
|
||
try:
|
||
with open(EXEC_LOG_PATH, 'w+') as f:
|
||
f.write(logMsg)
|
||
f.close()
|
||
except:
|
||
pass
|
||
|
||
|
||
def GetSystemVersion():
|
||
"""
|
||
取操作系统版本
|
||
"""
|
||
key = 'lybbn_sys_version'
|
||
version = cache.get(key)
|
||
if version: return version
|
||
try:
|
||
# Python 3.8 已移除 此方法 "linux_distribution()"
|
||
platform_dist = platform.linux_distribution()
|
||
version = platform_dist[0] + " " + platform_dist[1]
|
||
except:
|
||
with os.popen("cat /etc/redhat-release", "r") as p:
|
||
release = p.read()
|
||
version = release.replace('release ', '').replace('Linux', '').replace('(Core)', '').strip()
|
||
|
||
pyv_info = sys.version_info
|
||
version = "{} {}(Py{}.{}.{})".format(version, os.uname().machine, pyv_info.major, pyv_info.minor, pyv_info.micro)
|
||
cache.set(key, version, 86400)
|
||
return version
|
||
|
||
|
||
def GetLoadAverage():
|
||
"""
|
||
取系统负载
|
||
"""
|
||
try:
|
||
c = os.getloadavg()
|
||
except:
|
||
c = [0, 0, 0]
|
||
data = {}
|
||
data['one'] = float(c[0])
|
||
data['five'] = float(c[1])
|
||
data['fifteen'] = float(c[2])
|
||
data['max'] = psutil.cpu_count() * 2
|
||
data['limit'] = data['max']
|
||
data['safe'] = data['max'] * 0.75
|
||
temppercent = round(data['one'] / data['max'] * 100)
|
||
data['percent'] = 100 if temppercent > 100 else temppercent
|
||
return data
|
||
|
||
|
||
def GetMemInfo():
|
||
"""
|
||
取内存信息
|
||
"""
|
||
mem = psutil.virtual_memory()
|
||
memInfo = {}
|
||
memInfo2 = {'memTotal': int(mem.total / 1024 / 1024), 'memFree': int(mem.free / 1024 / 1024),
|
||
'memBuffers': int(mem.buffers / 1024 / 1024), 'memCached': int(mem.cached / 1024 / 1024)}
|
||
memInfo['total'] = round(float(mem.total) / 1024 / 1024 / 1024, 2)
|
||
memInfo['free'] = round((memInfo2['memFree'] + memInfo2['memBuffers'] + memInfo2['memCached']) / 1024, 2)
|
||
memInfo['used'] = round(float(mem.used) / 1024 / 1024 / 1024, 2)
|
||
memInfo['percent'] = round((int(mem.used) / 1024 / 1024) / memInfo2['memTotal'] * 100, 1)
|
||
return memInfo
|
||
|
||
|
||
def get_disk_iostat():
|
||
"""
|
||
获取磁盘IO
|
||
"""
|
||
iokey = 'iostat'
|
||
diskio = cache.get(iokey)
|
||
mtime = int(time.time())
|
||
if not diskio:
|
||
diskio = {}
|
||
diskio['info'] = None
|
||
diskio['time'] = mtime
|
||
diskio_1 = diskio['info']
|
||
stime = mtime - diskio['time']
|
||
if not stime: stime = 1
|
||
diskInfo = {}
|
||
diskInfo['ALL'] = {}
|
||
diskInfo['ALL']['read_count'] = 0
|
||
diskInfo['ALL']['write_count'] = 0
|
||
diskInfo['ALL']['read_bytes'] = 0
|
||
diskInfo['ALL']['write_bytes'] = 0
|
||
diskInfo['ALL']['read_time'] = 0
|
||
diskInfo['ALL']['write_time'] = 0
|
||
diskInfo['ALL']['read_merged_count'] = 0
|
||
diskInfo['ALL']['write_merged_count'] = 0
|
||
try:
|
||
if os.path.exists('/proc/diskstats'):
|
||
diskio_2 = psutil.disk_io_counters(perdisk=True)
|
||
if not diskio_1:
|
||
diskio_1 = diskio_2
|
||
for disk_name in diskio_2.keys():
|
||
diskInfo[disk_name] = {}
|
||
diskInfo[disk_name]['read_count'] = int(
|
||
(diskio_2[disk_name].read_count - diskio_1[disk_name].read_count) / stime)
|
||
diskInfo[disk_name]['write_count'] = int(
|
||
(diskio_2[disk_name].write_count - diskio_1[disk_name].write_count) / stime)
|
||
diskInfo[disk_name]['read_bytes'] = int(
|
||
(diskio_2[disk_name].read_bytes - diskio_1[disk_name].read_bytes) / stime)
|
||
diskInfo[disk_name]['write_bytes'] = int(
|
||
(diskio_2[disk_name].write_bytes - diskio_1[disk_name].write_bytes) / stime)
|
||
diskInfo[disk_name]['read_time'] = int(
|
||
(diskio_2[disk_name].read_time - diskio_1[disk_name].read_time) / stime)
|
||
diskInfo[disk_name]['write_time'] = int(
|
||
(diskio_2[disk_name].write_time - diskio_1[disk_name].write_time) / stime)
|
||
diskInfo[disk_name]['read_merged_count'] = int(
|
||
(diskio_2[disk_name].read_merged_count - diskio_1[disk_name].read_merged_count) / stime)
|
||
diskInfo[disk_name]['write_merged_count'] = int(
|
||
(diskio_2[disk_name].write_merged_count - diskio_1[disk_name].write_merged_count) / stime)
|
||
|
||
diskInfo['ALL']['read_count'] += diskInfo[disk_name]['read_count']
|
||
diskInfo['ALL']['write_count'] += diskInfo[disk_name]['write_count']
|
||
diskInfo['ALL']['read_bytes'] += diskInfo[disk_name]['read_bytes']
|
||
diskInfo['ALL']['write_bytes'] += diskInfo[disk_name]['write_bytes']
|
||
if diskInfo['ALL']['read_time'] < diskInfo[disk_name]['read_time']:
|
||
diskInfo['ALL']['read_time'] = diskInfo[disk_name]['read_time']
|
||
if diskInfo['ALL']['write_time'] < diskInfo[disk_name]['write_time']:
|
||
diskInfo['ALL']['write_time'] = diskInfo[disk_name]['write_time']
|
||
diskInfo['ALL']['read_merged_count'] += diskInfo[disk_name]['read_merged_count']
|
||
diskInfo['ALL']['write_merged_count'] += diskInfo[disk_name]['write_merged_count']
|
||
|
||
cache.set(iokey, {'info': diskio_2, 'time': mtime})
|
||
except:
|
||
return diskInfo
|
||
return diskInfo
|
||
|
||
|
||
def GetNetWork():
|
||
"""
|
||
取网卡数据
|
||
"""
|
||
cache_timeout = 86400
|
||
otime = cache.get("lybbn_otime")
|
||
ntime = time.time()
|
||
networkInfo = {}
|
||
networkInfo['network'] = {}
|
||
networkInfo['upTotal'] = 0
|
||
networkInfo['downTotal'] = 0
|
||
networkInfo['up'] = 0
|
||
networkInfo['down'] = 0
|
||
networkInfo['downPackets'] = 0
|
||
networkInfo['upPackets'] = 0
|
||
networkIo_list = psutil.net_io_counters(pernic=True)
|
||
for net_key in networkIo_list.keys():
|
||
networkIo = networkIo_list[net_key][:4]
|
||
up_key = "{}_up".format(net_key)
|
||
down_key = "{}_down".format(net_key)
|
||
otime_key = "lybbn_otime"
|
||
|
||
if not otime:
|
||
otime = time.time()
|
||
|
||
cache.set(up_key, networkIo[0], cache_timeout)
|
||
cache.set(down_key, networkIo[1], cache_timeout)
|
||
cache.set(otime_key, otime, cache_timeout)
|
||
|
||
networkInfo['network'][net_key] = {}
|
||
up = cache.get(up_key)
|
||
down = cache.get(down_key)
|
||
if not up:
|
||
up = networkIo[0]
|
||
if not down:
|
||
down = networkIo[1]
|
||
networkInfo['network'][net_key]['upTotal'] = networkIo[0]
|
||
networkInfo['network'][net_key]['downTotal'] = networkIo[1]
|
||
networkInfo['network'][net_key]['up'] = round(float(networkIo[0] - up) / 1024 / (ntime - otime), 2)
|
||
networkInfo['network'][net_key]['down'] = round(float(networkIo[1] - down) / 1024 / (ntime - otime), 2)
|
||
networkInfo['network'][net_key]['downPackets'] = networkIo[3]
|
||
networkInfo['network'][net_key]['upPackets'] = networkIo[2]
|
||
|
||
networkInfo['upTotal'] += networkInfo['network'][net_key]['upTotal']
|
||
networkInfo['downTotal'] += networkInfo['network'][net_key]['downTotal']
|
||
networkInfo['up'] += networkInfo['network'][net_key]['up']
|
||
networkInfo['down'] += networkInfo['network'][net_key]['down']
|
||
networkInfo['downPackets'] += networkInfo['network'][net_key]['downPackets']
|
||
networkInfo['upPackets'] += networkInfo['network'][net_key]['upPackets']
|
||
|
||
cache.set(up_key, networkIo[0], cache_timeout)
|
||
cache.set(down_key, networkIo[1], cache_timeout)
|
||
cache.set(otime_key, time.time(), cache_timeout)
|
||
|
||
networkInfo['up'] = round(float(networkInfo['up']), 2)
|
||
networkInfo['down'] = round(float(networkInfo['down']), 2)
|
||
networkInfo['iostat'] = get_disk_iostat()
|
||
|
||
return networkInfo
|
||
|
||
|
||
def GetBootTime():
|
||
"""
|
||
取系统启动时间(天)
|
||
"""
|
||
key = 'lybbn_sys_time'
|
||
sys_time = cache.get(key)
|
||
if sys_time: return sys_time
|
||
uptime_seconds = time.mktime(time.localtime(time.time())) - psutil.boot_time()
|
||
run_days = int(uptime_seconds / 86400)
|
||
# run_hour = int((uptime_seconds % 86400) / 3600)
|
||
# run_minute = int((uptime_seconds % 3600) / 60)
|
||
# run_second = int(uptime_seconds % 60)
|
||
sys_time = "{}天".format(run_days)
|
||
cache.set(key, sys_time, 1800)
|
||
return sys_time
|
||
|
||
|
||
def getCpuInfoDict():
|
||
"""
|
||
取/proc/cpuinfo信息字典
|
||
"""
|
||
cpuinfo = {}
|
||
procinfo = {}
|
||
nprocs = 0
|
||
with open('/proc/cpuinfo') as f:
|
||
for line in f:
|
||
if not line.strip():
|
||
cpuinfo['proc%s' % nprocs] = procinfo
|
||
nprocs = nprocs + 1
|
||
procinfo = {}
|
||
else:
|
||
if len(line.split(':')) == 2:
|
||
procinfo[line.split(':')[0].strip()] = line.split(':')[1].strip()
|
||
else:
|
||
procinfo[line.split(':')[0].strip()] = ''
|
||
return cpuinfo
|
||
|
||
|
||
def GetCpuInfo(interval=1):
|
||
"""
|
||
取CPU信息
|
||
"""
|
||
|
||
cpuCount = cache.get('lybbn_cpu_cpuCount')
|
||
if not cpuCount:
|
||
cpuCount = psutil.cpu_count()
|
||
cache.set('lybbn_cpu_cpuCount', cpuCount, 86400)
|
||
cpuNum = cache.get('lybbn_cpu_cpuNum')
|
||
if not cpuNum:
|
||
cpuNum = psutil.cpu_count(logical=False)
|
||
cache.set('lybbn_cpu_cpuNum', cpuNum, 86400)
|
||
|
||
cpuW = cache.get('lybbn_cpu_cpuW')
|
||
if not cpuW:
|
||
cpuW = int(subprocess.check_output('cat /proc/cpuinfo | grep "physical id" | sort -u | wc -l', shell=True))
|
||
cache.set('lybbn_cpu_cpuW', cpuW, 86400)
|
||
|
||
used = psutil.cpu_percent(interval)
|
||
|
||
used_all = psutil.cpu_percent(percpu=True)
|
||
|
||
cpu_name = cache.get('lybbn_cpu_cpu_name')
|
||
if not cpu_name:
|
||
cpu_name = ""
|
||
try:
|
||
cpuinfo = getCpuInfoDict()
|
||
cpu_name = cpuinfo['proc0']['model name'] + " * {}".format(cpuW)
|
||
except:
|
||
pass
|
||
cache.set('lybbn_cpu_cpu_name', cpu_name, 86400)
|
||
|
||
return used, cpuCount, used_all, cpu_name, cpuNum, cpuW
|
||
|
||
|
||
def GetDiskInfo():
|
||
# 取磁盘分区信息
|
||
key = 'lybbn_sys_disk'
|
||
diskInfo = cache.get(key)
|
||
if diskInfo: return diskInfo
|
||
|
||
with os.popen("df -hT -P|grep '/'|grep -v tmpfs|grep -v 'snap/core'|grep -v udev", "r") as p:
|
||
temp = p.read()
|
||
|
||
with os.popen("df -i -P|grep '/'|grep -v tmpfs|grep -v 'snap/core'|grep -v udev", "r") as p:
|
||
tempInodes = p.read()
|
||
|
||
tempList = temp.split('\n')
|
||
tempInodesList = tempInodes.split('\n')
|
||
diskInfo = []
|
||
n = 0
|
||
cuts = ['/mnt/cdrom', '/boot', '/boot/efi', '/dev', '/dev/shm', '/run/lock', '/run', '/run/shm', '/run/user']
|
||
for tmp in tempList:
|
||
n += 1
|
||
try:
|
||
inodes = tempInodesList[n - 1].split()
|
||
disk = re.findall(r"^(.+)\s+([\w\.]+)\s+([\w\.]+)\s+([\w\.]+)\s+([\w\.]+)\s+([\d%]{2,4})\s+(/.{0,100})$",
|
||
tmp.strip())
|
||
if disk: disk = disk[0]
|
||
if len(disk) < 6: continue
|
||
if disk[2].find('M') != -1: continue
|
||
if disk[2].find('K') != -1: continue
|
||
if len(disk[6].split('/')) > 10: continue
|
||
if disk[6] in cuts: continue
|
||
if disk[6].find('docker') != -1: continue
|
||
if disk[1].strip() in ['tmpfs']: continue
|
||
arr = {}
|
||
arr['filesystem'] = disk[0].strip()
|
||
arr['type'] = disk[1].strip()
|
||
arr['path'] = disk[6]
|
||
tmp1 = [disk[2], disk[3], disk[4], disk[5].split('%')[0]]
|
||
arr['size'] = tmp1
|
||
arr['inodes'] = [inodes[1], inodes[2], inodes[3], inodes[4]]
|
||
diskInfo.append(arr)
|
||
except Exception as ex:
|
||
WriteLog('获取磁盘信息失败:%s' % str(ex))
|
||
continue
|
||
cache.set(key, diskInfo, 1000)
|
||
return diskInfo
|
||
|
||
def GetFileLastNumsLines(path,num=1000):
|
||
"""
|
||
获取指定文件的指定尾行数内容
|
||
"""
|
||
try:
|
||
if not os.path.exists(path): return ""
|
||
filesize = os.path.getsize(path)
|
||
if filesize == 0: return ""
|
||
num = int(num)
|
||
total_lines_wanted = num
|
||
BLOCK_SIZE = 4096
|
||
with open(path,"rb") as f:
|
||
f.seek(0, 2)
|
||
block_end_byte = f.tell()
|
||
lines_to_go = total_lines_wanted
|
||
block_number = -1
|
||
blocks = []
|
||
while lines_to_go > 0 and block_end_byte > 0:
|
||
if (block_end_byte - BLOCK_SIZE > 0):
|
||
f.seek(block_number*BLOCK_SIZE, 2)
|
||
blocks.append(f.read(BLOCK_SIZE))
|
||
else:
|
||
f.seek(0,0)
|
||
blocks.append(f.read(block_end_byte))
|
||
lines_found = blocks[-1].count(b'\n')
|
||
lines_to_go -= lines_found
|
||
block_end_byte -= BLOCK_SIZE
|
||
block_number -= 1
|
||
all_read_text = b''.join(reversed(blocks))
|
||
return b'\n'.join(all_read_text.splitlines()[-total_lines_wanted:])
|
||
except:
|
||
return ""
|
||
|
||
def RestartServer():
|
||
"""
|
||
重启系统
|
||
"""
|
||
try:
|
||
os.system("sync && init 6 &")
|
||
except:
|
||
pass
|
||
|
||
def GetUidName(file_path,uid=0):
|
||
"""
|
||
通过系统uid获取对应名称
|
||
"""
|
||
try:
|
||
return pwd.getpwuid(uid).pw_name
|
||
except Exception as e:
|
||
return ""
|
||
|
||
def GetGroupidName(file_path,gid=0):
|
||
"""
|
||
通过系统goup id(所属组id)获取对应名称
|
||
"""
|
||
try:
|
||
return grp.getgrgid(gid).gr_name
|
||
except Exception as e:
|
||
return ""
|
||
|
||
def ForceRemoveDir(directory):
|
||
"""
|
||
强制删除目录
|
||
"""
|
||
sys_dir = ['/root','/','/proc','/*','/root/*']
|
||
if directory in sys_dir:
|
||
raise ValueError("受保护的目录,无法删除!!!")
|
||
if os.path.exists(directory):
|
||
try:
|
||
# 执行 rm -rf 命令
|
||
subprocess.run(['rm', '-rf', directory], check=True)
|
||
except subprocess.CalledProcessError as e:
|
||
raise ValueError(f"强制删除目录错误: {e}") |