# -*- 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 : ############################################################################# # ---------------command path-------------------- import os import subprocess import threading import time from subprocess import PIPE, Popen from datetime import datetime from datetime import timedelta import pwd from gspylib.common.ErrorCode import ErrorCode from base_utils.common.exceptions import CommandNotFoundException from base_utils.common.fast_popen import FastPopen from base_utils.security.security_checker import SecurityChecker CMD_PATH = ['/bin', '/usr/local/bin', '/usr/bin', '/sbin', '/usr/sbin'] CMD_CACHE = {} BLANK_SPACE = " " COLON = ":" class CmdUtil(object): """ Cmd util""" SOURCE_CMD = 'source' ENV_SOURCE_CMD = "source /etc/profile;source ~/.bashrc;" \ "if [ $MPPDB_ENV_SEPARATE_PATH ]; " \ "then source $MPPDB_ENV_SEPARATE_PATH; fi" @staticmethod def findCmdInPath(cmd, additional_paths=None, print_error=True): """ function: find cmd in path input: cmd, additional_paths, printError output: NA """ global CMD_CACHE if additional_paths is None: additional_paths = [] if cmd not in CMD_CACHE: # Search additional paths and don't add to cache. for p in additional_paths: f = os.path.join(p, cmd) if os.path.exists(f): return f for p in CMD_PATH: f = os.path.join(p, cmd) if os.path.exists(f): CMD_CACHE[cmd] = f return f if cmd == "killall": gphome = os.getenv("GPHOME") if gphome is None or \ not os.path.exists(os.path.join(gphome, "script/killall")): gphome = os.path.dirname(os.path.realpath(__file__)) \ + "/../../.." gphome = gphome.replace("\\", "\\\\").replace('"', '\\"\\"') SecurityChecker.check_injection_char(gphome) if gphome != "" and os.path.exists(os.path.join(gphome, "script/killall")): return os.path.join(gphome, "script/killall") else: raise Exception(ErrorCode.GAUSS_502["GAUSS_50201"] % "killall") if print_error: print('Command %s not found' % cmd) search_path = CMD_PATH[:] search_path.extend(additional_paths) raise CommandNotFoundException(cmd, search_path) else: return CMD_CACHE[cmd] @staticmethod def getCreateFileCmd(path): """ function: get create file cmd input : path output : str """ return "touch '%s'" % path @staticmethod def getMoveFileCmd(src, dest): """ function: get move file cmd input : src, dest output : str """ cmd = "mv '%s' '%s'" % (src, dest) return cmd @staticmethod def getRemoveCmd(path_type): """ function: get remove cmd input : path_type output : str """ opts = " " if path_type == "file": opts = " -f " elif path_type == "directory": opts = " -rf " return CmdUtil.findCmdInPath('rm') + opts @staticmethod def getChmodCmd(permission, src, recursive=False): """ function: get chmod cmd input : permission, src, recursive output : str """ return CmdUtil.findCmdInPath('chmod') + \ (" -R " if recursive else BLANK_SPACE) + \ permission + BLANK_SPACE + src @staticmethod def getChownCmd(owner, group, src, recursive=False): """ function: get chown cmd input : owner, group, src, recursive output : str """ return CmdUtil.findCmdInPath('chown') + \ (" -R " if recursive else BLANK_SPACE) + owner + \ COLON + group + BLANK_SPACE + src @staticmethod def getCopyCmd(src, dest, path_type=""): """ function: get copy cmd input : src, dest, path_type output : str """ opts = " " if path_type == "directory": opts = " -r " return CmdUtil.findCmdInPath('cp') + " -p -f " + opts + BLANK_SPACE + "'" + \ src + "'" + BLANK_SPACE + "'" + dest + "'" @staticmethod def getMoveCmd(src, dest): """ function: get move cmd input : src, dest output : str """ return CmdUtil.findCmdInPath('mv') + " -f " + "'" + src + \ "'" + BLANK_SPACE + "'" + dest + "'" @staticmethod def getMakeDirCmd(src, recursive=False): """ function: get make dir cmd input : src, recursive output : str """ return CmdUtil.findCmdInPath('mkdir') + \ (" -p " if recursive else BLANK_SPACE) + "'" + src + "'" @staticmethod def getPingCmd(host, count, interval, packet_size=56): """ function: get ping cmd input : host, count, interval, packet_size output : str """ opts = " " if int(packet_size) != int(56): opts = " -s " + str(packet_size) return CmdUtil.findCmdInPath('ping') + BLANK_SPACE + host + " -c " + \ count + " -i " + interval + opts @staticmethod def getWcCmd(): """ function: get wc cmd input : NA output : str """ return CmdUtil.findCmdInPath('wc') @staticmethod def getTarCmd(): """ function: get tar cmd input : NA output : str """ return CmdUtil.findCmdInPath('tar') @staticmethod def getZipCmd(): """ function: get zip cmd input : NA output : str """ return CmdUtil.findCmdInPath('zip') @staticmethod def getUnzipCmd(): """ function: get unzip cmd input : NA output : str """ return CmdUtil.findCmdInPath('unzip') @staticmethod def getSedCmd(): """ function: get sed cmd input : NA output : str """ return CmdUtil.findCmdInPath('sed') @staticmethod def getGrepCmd(): """ function: get grep cmd input : NA output : str """ return CmdUtil.findCmdInPath('grep') @staticmethod def getDateCmd(): """ function: get date cmd input : NA output : str """ return CmdUtil.findCmdInPath('date') @staticmethod def getAwkCmd(): """ function: get awk cmd input : NA output : str """ return CmdUtil.findCmdInPath('awk') @staticmethod def getFindCmd(): """ function: get find cmd input : NA output : str """ return CmdUtil.findCmdInPath('find') @staticmethod def getTouchCmd(file_name): """ function: get touch cmd input : NA output : str """ return CmdUtil.findCmdInPath('touch') + BLANK_SPACE + file_name @staticmethod def getListCmd(): """ function: get list cmd input : NA output : str """ return CmdUtil.findCmdInPath('ls') @staticmethod def getSHA256Cmd(): """ function: get sha256 cmd input : NA output : str """ return CmdUtil.findCmdInPath('sha256sum') @staticmethod def getCatCmd(): """ function: get cat cmd input : NA output : str """ return CmdUtil.findCmdInPath('cat') @staticmethod def getCdCmd(path): """ function: get cd cmd input : path output : str """ return 'cd' + BLANK_SPACE + "'" + path + "'" @staticmethod def getAllCrontabCmd(): """ function: get all crontab cmd input : NA output : str """ cmd = CmdUtil.findCmdInPath('crontab') + BLANK_SPACE + " -l" return cmd @staticmethod def getCrontabCmd(): """ function: get crontab cmd input : NA output : str """ return CmdUtil.findCmdInPath('crontab') @staticmethod def getKillProcessCmd(signal, pid): """ function: get kill process cmd input : NA output : str """ return CmdUtil.findCmdInPath('kill') + " -" + signal + BLANK_SPACE + pid @staticmethod def getKillallProcessCmd(signal, user_name, proc_name=""): """ function: get killall process cmd input : signal, username, proc_name output : str """ if proc_name != "": return CmdUtil.findCmdInPath('killall') + " -s " + signal + " -u " + \ user_name + BLANK_SPACE + proc_name return CmdUtil.findCmdInPath('killall') + " -s " + signal + " -u " + \ user_name @staticmethod def getXargsCmd(): """ function: get xargs cmd input : NA output : str """ return CmdUtil.findCmdInPath('xargs') @staticmethod def getServiceCmd(service_name, action): """ function: get service cmd input : service_name, action output : str """ return CmdUtil.findCmdInPath('service') + BLANK_SPACE + service_name + \ BLANK_SPACE + action @staticmethod def getSystemctlCmd(service_name, action): """ function: get systemctl cmd input : service_name, action output : str """ return CmdUtil.findCmdInPath('systemctl') + BLANK_SPACE + action + \ BLANK_SPACE + service_name @staticmethod def getUlimitCmd(): """ function: get ulimit cmd input : NA output : str """ return 'ulimit' @staticmethod def getGetConfValueCmd(): """ function: get conf value cmd input : NA output : str """ return CmdUtil.findCmdInPath('getconf') + " PAGESIZE " @staticmethod def getMountCmd(): """ function: get dd cmd input : NA output : str """ return CmdUtil.findCmdInPath('mount') @staticmethod def getEthtoolCmd(): """ function: get eth tool cmd input : NA output : str """ return CmdUtil.findCmdInPath('ethtool') @staticmethod def getTailCmd(): """ function: get tail cmd input : NA output : str """ return CmdUtil.findCmdInPath('tail') @staticmethod def getSshCmd(address, timeout=None): """ function: get ssh cmd input : NA output : str """ if timeout: return "pssh --trace-id %s -s -t %s -H %s" % ( threading.currentThread().getName(), str(timeout), address) return "pssh --trace-id %s -s -H %s" % (threading.currentThread().getName(), address) @staticmethod def getSshCommand(ip, cmd, timeout=None): """ function : Get ssh command input : null output : exe_cmd """ exe_cmd = "%s \"%s\"" % (CmdUtil.getSshCmd(ip, timeout=timeout), cmd) return exe_cmd @staticmethod def getNtpqCmd(): """ function: get ntpq cmd input : NA output : str """ return "/usr/sbin/ntpq -p " @staticmethod def getShellCmd(): """ function: get shell cmd input : NA output : str """ return CmdUtil.findCmdInPath('sh') @staticmethod def getFileSHA256Cmd(fileName): """ function: get file sha256 cmd input : fileName output : str """ cmd = "%s '%s' | %s -F\" \" '{print $1}' " % (CmdUtil.getSHA256Cmd(), fileName, CmdUtil.getAwkCmd()) return cmd @staticmethod def getDiskFreeCmd(mounted="", inode=False): # -P is for POSIX formatting. Prevents error # on lines that would wrap return CmdUtil.findCmdInPath('df') + " -Pk " + \ (" -i " if inode else " -h ") + mounted @staticmethod def getReplaceFileLineContentCmd(old_line, new_line, path): """ function: get replace file line content cmd input : old_line, new_line, path output : str """ cmd = "%s -i \"s/%s/%s/g\" '%s'" % (CmdUtil.getSedCmd(), old_line, new_line, path) return cmd @staticmethod def getDirSizeCmd(path, unit=""): # -s only shows the total size # unit specify the output size unit return CmdUtil.findCmdInPath('du') + " -s " + (" -B %s " % unit if unit else " -h ") + path @staticmethod def getSysConfiguration(): """ function : The size range of PAGE_SIZE obtained by getconf input : NA output: string """ config_cmd = CmdUtil.getGetConfValueCmd() (status, output) = subprocess.getstatusoutput(config_cmd) # if cmd failed, then exit if status != 0: raise Exception(ErrorCode.GAUSS_502["GAUSS_50219"] % "system config pagesize" + "The cmd is %s" % config_cmd) return output @staticmethod def getExecuteCmdWithUserProfile(user, user_profile, execute_cmd, ignore_error=True): """ """ if (user != "") and (os.getuid() == 0): cmd = " su - %s -c 'source %s; %s'" % (user, user_profile, execute_cmd) else: cmd = "source %s; %s" % (user_profile, execute_cmd) if ignore_error: cmd += " 2>/dev/null" return cmd @staticmethod def getUserLimits(limit_type): """ function : Get current user process limits input : string output: string """ limit = CmdUtil.getUlimitCmd() limit_cmd = "%s -a | %s -F '%s'" % (limit, CmdUtil.getGrepCmd(), limit_type) (status, output) = subprocess.getstatusoutput(limit_cmd) # if cmd failed, then exit if status != 0: raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % limit_cmd + " Error:\n%s" % output) return output @staticmethod def retryGetstatusoutput(cmd, retry_time=3, sleep_time=1, check_output=False): """ function : retry getStatusoutput @param cmd: command going to be execute @param retry_time: default retry 3 times after execution failure @param sleep_time: default sleep 1 second then start retry """ retry_time += 1 for _ in range(retry_time): (status, output) = subprocess.getstatusoutput(cmd) if status != 0: time.sleep(sleep_time) elif check_output: if str(output).strip(): break else: time.sleep(sleep_time) else: break return status, output @staticmethod def retry_util_timeout(cmd, timeout, sleep_time=1): """ retry execute cmd with giving timeout. """ end_time = datetime.now() + timedelta(seconds=int(timeout)) status, output = 1, 1 while datetime.now() < end_time: status, output = CmdUtil.getstatusoutput_by_fast_popen(cmd) if status == 0: break else: time.sleep(sleep_time) return status, output @staticmethod def getstatusoutput_by_fast_popen(cmd): """ get status, output by executing command by fast popen """ fast_popen = FastPopen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True, preexec_fn=os.setsid) stdout, stderr = fast_popen.communicate() output = (stdout + stderr).strip() return fast_popen.returncode, output @staticmethod def exec_by_popen(cmd): """ execute cmd by popen """ env_source_cmd = CmdUtil.get_env_source_cmd() proc = Popen("%s;%s" % (env_source_cmd, cmd), shell=True, stdout=PIPE, stderr=PIPE, universal_newlines=True) stdout, stderr = proc.communicate() if proc.returncode == 0: return True, stdout return False, stderr @staticmethod def get_env_source_cmd(): """ get env source cmd """ env_source_cmd = CmdUtil.ENV_SOURCE_CMD return env_source_cmd @staticmethod def retry_exec_by_popen(cmd, retry_time=3, sleep_time=1, check_out=False): """ function : retry exec_by_popen @param cmd: command going to be execute @param retry_time: default retry 3 times after execution failure @param sleep_time: default sleep 1 second then start retry """ retry_time += 1 for _ in range(retry_time): (status, output) = CmdUtil.exec_by_popen(cmd) if not status: time.sleep(sleep_time) elif check_out: if str(output).strip(): break else: time.sleep(sleep_time) else: break return status, output @staticmethod def interactive_with_popen(cmd, password): """ function : Interactive password entry input : cmd, password output: NA """ env_source_cmd = CmdUtil.get_env_source_cmd() if isinstance(password, str): password = bytes(password, 'utf-8') try: proc = Popen("%s; %s" % (env_source_cmd, cmd), shell=True, stdout=PIPE, stderr=PIPE, stdin=PIPE) proc.stdin.write(password) proc.stdin.write(bytes("\n", 'utf-8')) proc.stdin.flush() except Exception: output, error = proc.communicate() return proc.returncode, output, error else: # Increase the system response time time.sleep(0.1) proc.stdin.write(password) proc.stdin.write(bytes("\n", 'utf-8')) proc.stdin.flush() output, error = proc.communicate() return proc.returncode, output, error