# -*- coding:utf-8 -*- ############################################################################# # Copyright (c) 2020 Huawei Technologies Co.,Ltd. # # openGauss is licensed under Mulan PSL v2. # You can use this software according to the terms # and conditions of the Mulan PSL v2. # You may obtain a copy of Mulan PSL v2 at: # # http://license.coscl.org.cn/MulanPSL2 # # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, # WITHOUT WARRANTIES OF ANY KIND, # EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, # MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. # See the Mulan PSL v2 for more details. # ---------------------------------------------------------------------------- # Description : ############################################################################# import os import subprocess import sys import psutil import math sys.path.append(sys.path[0] + "/../../") from base_utils.os.cmd_util import CmdUtil from gspylib.common.ErrorCode import ErrorCode class DiskUtil(object): """ function: Init the DiskUsage options """ MTAB_FILE = "/etc/mtab" @staticmethod def getMountInfo(all_info=False): """ get mount disk information: device mountpoint fstype opts input: bool (physical devices and all others) output: list """ return psutil.disk_partitions(all_info) @staticmethod def getUsageSize(directory): """ get directory or file real size. Unit is byte """ cmd = "" try: cmd = "%s -l -R %s | %s ^- | %s '{t+=$5;} END {print t}'" % ( CmdUtil.getListCmd(), directory, CmdUtil.getGrepCmd(), CmdUtil.getAwkCmd()) (status, output) = subprocess.getstatusoutput(cmd) if status == 0: return output.split('\t')[0].strip() else: raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + " Error: \n%s" % str(output)) except Exception: raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd) # Mtab always keeps the partition information already mounted in the # current system. # For programs like fdisk and df, # you must read the mtab file to get the partition mounting status in # the current system. @staticmethod def getMountPathByDataDir(data_dir): """ function : Get the disk by the file path input : datadir the file path output : device disk """ device = "" mount_disk = {} if not os.path.exists(data_dir): raise Exception(ErrorCode.GAUSS_502["GAUSS_50228"] % data_dir) try: datadir = os.path.realpath(data_dir) with open(DiskUtil.MTAB_FILE, "r") as fp: for line in fp.readlines(): if line.startswith('none'): continue i_fields = line.split() if len(i_fields) < 3: continue i_device = i_fields[0].strip() i_mountpoint = i_fields[1].strip() mount_disk[i_mountpoint] = [i_device, i_mountpoint] mountList = list(mount_disk.keys()) mountList.sort(reverse=True) for mount in mountList: i_mountpoint = mount_disk[mount][1] if i_mountpoint == '/': i_mount_dirlst = [''] else: i_mount_dirlst = i_mountpoint.split('/') data_dirlst = datadir.split('/') if len(i_mount_dirlst) > len(data_dirlst): continue if i_mount_dirlst == data_dirlst[:len(i_mount_dirlst)]: device = mount_disk[mount][0] break except Exception as excep: raise Exception(ErrorCode.GAUSS_530["GAUSS_53011"] % " disk mount." + "Error: %s" % str(excep)) return device # Mtab always keeps the partition information already mounted in the # current system. # For programs like fdisk and df, # you must read the mtab file to get the partition mounting status in # the current system. @staticmethod def getMountPathAvailSize(device, sizeUnit='MB'): """ function : Get the disk size by the file path input : device the file path : sizeUnit byte, GB, MB, KB output : total disk size """ total = 0 if not os.path.exists(device): raise Exception(ErrorCode.GAUSS_502["GAUSS_50228"] % device) try: dev_info = os.statvfs(device) if sizeUnit == 'GB': total = dev_info.f_bavail * dev_info.f_frsize // ( 1024 * 1024 * 1024) elif sizeUnit == 'MB': total = dev_info.f_bavail * dev_info.f_frsize // (1024 * 1024) elif sizeUnit == 'KB': total = dev_info.f_bavail * dev_info.f_frsize // 1024 else: total = dev_info.f_bavail * dev_info.f_frsize except Exception as excep: raise Exception(ErrorCode.GAUSS_530["GAUSS_53011"] % " disk size." + "Error: %s" % str(excep)) return total # Mtab always keeps the partition information already mounted in the # current system. # For programs like fdisk and df, # you must read the mtab file to get the partition mounting status in # the current system. @staticmethod def getDiskSpaceUsage(path): """ function : Get the disk usage by the file path method of calculation: Total capacity (KB)=f_bsize*f_blocks/1024 [1k-blocks] Usage (KB)= f_bsize*(f_blocks-f_bfree)/1024 [Used] Valid capacity (KB) = f_bsize*f_bavail/1024 [Available] Usage (%) = Usage/(Usage + Valid capacity) *100 [Use%] input : path the file path output : percent """ percent = 0 if not os.path.exists(path): raise Exception(ErrorCode.GAUSS_502["GAUSS_50228"] % path) try: dev_info = os.statvfs(path) used = dev_info.f_blocks - dev_info.f_bfree valueable = dev_info.f_bavail + used percent = math.ceil((float(used) / valueable) * 100) except Exception as excep: raise Exception(ErrorCode.GAUSS_530["GAUSS_53011"] % " disk space." + "Error: %s" % str(excep)) return float(percent) @staticmethod def getDiskSpaceForShrink(path, delta): """ function : Get the disk usage by the file path for Shrink input : path the file path and deltasize output : percent """ percent = 0 if not os.path.exists(path): raise Exception(ErrorCode.GAUSS_502["GAUSS_50228"] % path) try: dev_info = os.statvfs(path) used = (dev_info.f_blocks - dev_info.f_bfree) * dev_info.f_bsize valueable = dev_info.f_bavail * dev_info.f_bsize + used + delta percent = math.ceil((float(used) / valueable) * 100) except Exception as excep: raise Exception(ErrorCode.GAUSS_530["GAUSS_53011"] % " disk space." + "Error: %s" % str(excep)) return float(percent) @staticmethod def getDiskInodeUsage(Path): """ function : Get the inode by the file path input : Path the file path output : percent """ percent = 0 if not os.path.exists(Path): raise Exception(ErrorCode.GAUSS_502["GAUSS_50228"] % Path) try: dev_info = os.statvfs(Path) used = dev_info.f_files - dev_info.f_ffree valueable = dev_info.f_favail + used percent = math.ceil((float(used) / valueable) * 100) except Exception as excep: raise Exception(ErrorCode.GAUSS_530["GAUSS_53011"] % " disk Inode." + "Error: %s" % str(excep)) return float(percent) @staticmethod def getDiskMountType(device): """ function : Get the mount type by device input : device eg:/dev/pts output : fstype device type """ fstype = "" try: with open(DiskUtil.MTAB_FILE, "r") as fp: for line in fp.readlines(): if line.startswith('#'): continue i_fields = line.split() if len(i_fields) < 3: continue i_device = i_fields[0].strip() i_fstype = i_fields[2].strip() if i_device == device: fstype = i_fstype break except Exception as excep: raise Exception(ErrorCode.GAUSS_530["GAUSS_53011"] % " disk mount type." + "Error: %s" % str(excep)) return fstype @staticmethod def getDevices(): """ functino: get device input: NA output: NA """ cmd = "fdisk -l 2>/dev/null | grep \"Disk /dev/\" | " \ "grep -Ev \"/dev/mapper/|loop\" | awk '{ print $2 }' | " \ "awk -F'/' '{ print $NF }' | sed s/:$//g" (status, output) = subprocess.getstatusoutput(cmd) if status != 0: raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + " Error: \n%s" % output) return output.split('\n') @staticmethod def get_disk_dev_id(dev_name): cmd = 'udevadm info -q symlink {}'.format(dev_name) sts, out = CmdUtil.getstatusoutput_by_fast_popen(cmd) if sts not in [0]: raise Exception(ErrorCode.GAUSS_504["GAUSS_50422"] % str(out).strip()) if out.find('disk/by-id/scsi-') != -1: strtmp = out[out.index('disk/by-id/scsi-') + len('disk/by-id/scsi-'):] if out.find(' ') != -1: strtmp = strtmp.split()[0] return strtmp.strip() if out.find('disk/by-id/ultrapath') != -1: strtmp = out[out.index('disk/by-id/ultrapath') + len('disk/by-id/ultrapath'):] if out.find(' ') != -1: strtmp = strtmp.split()[0] strtmp = strtmp.split('-', 1)[1] return strtmp.strip() if out.find('disk/by-id/wwn-') != -1: strtmp = out[out.index('disk/by-id/wwn-') + len('disk/by-id/wwn-'):] if out.find(' ') != -1: strtmp = strtmp.split()[0] return strtmp.strip() if out.find('disk/by-id/ata-') != -1: strtmp = out[out.index('disk/by-id/ata-') + len('disk/by-id/ata-'):] if out.find(' ') != -1: strtmp = strtmp.split()[0] return strtmp.strip() if out.find('disk/by-id/dm-uuid-') != -1: strtmp = out[out.index('disk/by-id/dm-uuid-') + len('disk/by-id/dm-uuid-'):] if out.find(' ') != -1: strtmp = strtmp.split()[0] return strtmp.strip() return out.strip() @staticmethod def get_disk_dev_name(dev_name): cmd = 'udevadm info -q name {}'.format(dev_name) sts, out = CmdUtil.getstatusoutput_by_fast_popen(cmd) if sts not in [0]: raise Exception(ErrorCode.GAUSS_504["GAUSS_50422"] % str(out).strip()) return out.strip() @staticmethod def active_udev(): cmd = 'udevadm control --reload-rules; ' cmd += 'udevadm trigger --type=devices --action=change; ' cmd += 'udevadm trigger --type=devices --action=add; ' cmd += 'udevadm trigger; ' sts, out = CmdUtil.getstatusoutput_by_fast_popen(cmd) if sts not in [0]: raise Exception(ErrorCode.GAUSS_504["GAUSS_50423"] % str(out).strip())