2022-11-07 20:17:20 +08:00

681 lines
19 KiB
Python

# -*- 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