2020-12-16 17:25:24 +08:00

861 lines
37 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 : SshTool.py is utility to support ssh tools
#############################################################################
import subprocess
import os
import sys
import datetime
import weakref
import getpass
import time
import re
from random import sample
sys.path.append(sys.path[0] + "/../../")
from gspylib.common.ErrorCode import ErrorCode
from gspylib.common.Common import DefaultValue
from gspylib.os.gsfile import g_file
from gspylib.common.GaussLog import GaussLog
class SshTool():
"""
Class for controling multi-hosts
"""
def __init__(self, hostNames, logFile=None,
timeout=DefaultValue.TIMEOUT_PSSH_COMMON, key=""):
'''
Constructor
'''
self.hostNames = hostNames
self.__logFile = logFile
self.__pid = os.getpid()
self.__timeout = timeout + 30
self._finalizer = weakref.finalize(self, self.clenSshResultFiles)
currentTime = str(datetime.datetime.now()).replace(" ", "_").replace(
".", "_")
randomnum = ''.join(sample('0123456789', 3))
# can tmp path always access?
if key == "":
self.__hostsFile = "/tmp/gauss_hosts_file_%d_%s_%s" % (
self.__pid, currentTime, randomnum)
self.__resultFile = "/tmp/gauss_result_%d_%s_%s.log" % (
self.__pid, currentTime, randomnum)
self.__outputPath = "/tmp/gauss_output_files_%d_%s_%s" % (
self.__pid, currentTime, randomnum)
self.__errorPath = "/tmp/gauss_error_files_%d_%s_%s" % (
self.__pid, currentTime, randomnum)
else:
self.__hostsFile = "/tmp/gauss_hosts_file_%d_%s_%s_%s" % (
self.__pid, key, currentTime, randomnum)
self.__resultFile = "/tmp/gauss_result_%d_%s_%s_%s.log" % (
self.__pid, key, currentTime, randomnum)
self.__outputPath = "/tmp/gauss_output_files_%d_%s_%s_%s" % (
self.__pid, key, currentTime, randomnum)
self.__errorPath = "/tmp/gauss_error_files_%d_%s_%s_%s" % (
self.__pid, key, currentTime, randomnum)
self.__resultStatus = {}
if logFile is None:
self.__logFile = "/dev/null"
# before using, clean the old ones
g_file.removeFile(self.__hostsFile)
g_file.removeFile(self.__resultFile)
if os.path.exists(self.__outputPath):
g_file.removeDirectory(self.__outputPath)
if os.path.exists(self.__errorPath):
g_file.removeDirectory(self.__errorPath)
self.__writeHostFiles()
def clenSshResultFiles(self):
"""
function: Delete file
input : NA
output: NA
"""
if os.path.exists(self.__hostsFile):
g_file.removeFile(self.__hostsFile)
if os.path.exists(self.__resultFile):
g_file.removeFile(self.__resultFile)
if os.path.exists(self.__outputPath):
g_file.removeDirectory(self.__outputPath)
if os.path.exists(self.__errorPath):
g_file.removeDirectory(self.__errorPath)
def __del__(self):
"""
function: Delete file
input : NA
output: NA
"""
self._finalizer()
def exchangeHostnameSshKeys(self, user, pwd, mpprcFile=""):
"""
function: Exchange ssh public keys for specified user, using hostname
input : user, pwd, mpprcFile
output: NA
"""
if mpprcFile != "":
exkeyCmd = "su - %s -c 'source %s&&mvxssh-exkeys -f %s -p" \
" %s' 2>>%s" % (user, mpprcFile, self.__hostsFile,
pwd, self.__logFile)
else:
exkeyCmd = "su - %s -c 'source /etc/profile&&mvxssh-exkeys -f" \
" %s -p %s' 2>>%s" % (user, self.__hostsFile,
pwd, self.__logFile)
(status, output) = subprocess.getstatusoutput(exkeyCmd)
if status != 0:
raise Exception(ErrorCode.GAUSS_511["GAUSS_51112"] % user +
"Error: \n%s" % output.replace(pwd, "******") +
"\nYou can comment Cipher 3des."
" Ciphers aes128-cbc and MACs in"
" /etc/ssh/ssh_config and try again.")
def exchangeIpSshKeys(self, user, pwd, ips, mpprcFile=""):
"""
function: Exchange ssh public keys for specified user,
using ip address
input : user, pwd, ips, mpprcFile
output: NA
"""
if mpprcFile != "":
exkeyCmd = "su - %s -c 'source %s&&mvxssh-exkeys " \
% (user, mpprcFile)
else:
exkeyCmd = "su - %s -c 'source /etc/profile&&mvxssh-exkeys " \
% user
for ip in ips:
exkeyCmd += " -h %s " % ip.strip()
exkeyCmd += "-p %s' 2>>%s" % (pwd, self.__logFile)
(status, output) = subprocess.getstatusoutput(exkeyCmd)
if status != 0:
raise Exception(ErrorCode.GAUSS_511["GAUSS_51112"]
% user + "Error: \n%s"
% output.replace(pwd, "******") +
"\nYou can comment Cipher 3des, Ciphers"
" aes128-cbc and MACs in /etc/ssh/ssh_config"
" and try again.")
def createTrust(self, user, pwd, ips=None, mpprcFile="",
skipHostnameSet=False, preMode=False):
"""
function: create trust for specified user with both ip and hostname,
when using N9000 tool create trust failed
do not support using a normal user to create trust for
another user.
input : user, pwd, ips, mpprcFile, skipHostnameSet
output: NA
"""
tmp_hosts = "/tmp/tmp_hosts_%d" % self.__pid
cnt = 0
status = 0
output = ""
if ips is None:
ips = []
try:
g_file.removeFile(tmp_hosts)
# 1.prepare hosts file
for ip in ips:
cmd = "echo %s >> %s 2>/dev/null" % (ip, tmp_hosts)
(status, output) = subprocess.getstatusoutput(cmd)
if status != 0:
raise Exception(ErrorCode.GAUSS_502["GAUSS_50201"]
% tmp_hosts + " Error:\n%s." % output
+ "The cmd is %s" % cmd)
g_file.changeMode(DefaultValue.KEY_HOSTS_FILE, tmp_hosts, False,
"python")
# 2.call createtrust script
create_trust_file = "gs_sshexkey"
if pwd is None or len(str(pwd)) == 0:
GaussLog.printMessage("Please enter password for current"
" user[%s]." % user)
pwd = getpass.getpass()
if (mpprcFile != "" and
g_file.checkFilePermission(mpprcFile, True) and
self.checkMpprcfile(user, mpprcFile)):
cmd = "source %s; %s -f %s -l '%s'" % (
mpprcFile, create_trust_file, tmp_hosts,
self.__logFile)
elif (mpprcFile == "" and g_file.checkFilePermission(
'/etc/profile', True)):
cmd = "source /etc/profile;" \
" %s -f %s -l '%s'" % (create_trust_file,
tmp_hosts, self.__logFile)
if skipHostnameSet:
cmd += " --skip-hostname-set"
cmd += " 2>&1"
tempcmd = ["su", "-", user, "-c"]
tempcmd.append(cmd)
cmd = tempcmd
p = subprocess.Popen(cmd, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if os.getuid() != 0:
time.sleep(5)
p.stdin.write((pwd+"\n").encode(encoding="utf-8"))
time.sleep(10)
p.stdin.write((pwd+"\n").encode(encoding="utf-8"))
(output, err) = p.communicate()
# 3.delete hosts file
g_file.removeFile(tmp_hosts)
if output is not None:
output = str(output, encoding='utf-8')
if re.search("\[GAUSS\-", output):
if re.search("Please enter password", output):
GaussLog.printMessage(
ErrorCode.GAUSS_503["GAUSS_50306"] % user)
else:
GaussLog.printMessage(output.strip())
sys.exit(1)
else:
GaussLog.printMessage(output.strip())
else:
sys.exit(1)
except Exception as e:
g_file.removeFile(tmp_hosts)
raise Exception(str(e))
def checkMpprcfile(self, username, filePath):
"""
function:
check if given user has operation permission for Mpprcfile
precondition:
1.user should be exist---root/cluster user
2.filePath should be an absolute path
postcondition:
1.return True or False
input : username,filePath
output: True/False
"""
ownerPath = os.path.split(filePath)[0]
cmd = "su - %s -c 'cd %s'" % (username, ownerPath)
(status, output) = subprocess.getstatusoutput(cmd)
if status != 0:
raise Exception(ErrorCode.GAUSS_500["GAUSS_50004"]
% '-sep-env-file' + " Error:\n%s." % output
+ "The cmd is %s" % cmd)
return True
def getUserOSProfile(self, env_file=""):
"""
function: get user os profile
input : env_file
output: mpprcFile, userProfile, osProfile
"""
if env_file != "":
mpprcFile = env_file
else:
mpprcFile = DefaultValue.getEnv(DefaultValue.MPPRC_FILE_ENV)
if mpprcFile != "" and mpprcFile is not None:
userProfile = mpprcFile
else:
userProfile = "~/.bashrc"
osProfile = "/etc/profile"
return mpprcFile, userProfile, osProfile
def getGPHOMEPath(self, osProfile):
"""
function: get GPHOME path
input : osProfile
output: output
"""
try:
cmd = "source %s && echo $GPHOME" % osProfile
(status, output) = subprocess.getstatusoutput(cmd)
if status != 0 or not output or output.strip() == "":
raise Exception(ErrorCode.GAUSS_518["GAUSS_51802"] % "GPHOME"
+ "The cmd is %s" % cmd)
return output.strip()
except Exception as e:
raise Exception(str(e))
def parseSshResult(self, hostList=None):
"""
function: parse ssh result
input : hostList
output: resultMap, outputCollect
"""
try:
if hostList is None:
hostList = []
outputCollect = ""
prefix = ""
resultMap = self.__readCmdResult(self.__resultFile, len(hostList))
for host in hostList:
sshOutPutFile = "%s/%s" % (self.__outputPath, host)
sshErrorPutFile = "%s/%s" % (self.__errorPath, host)
if resultMap[host] == DefaultValue.SUCCESS:
prefix = "SUCCESS"
else:
prefix = "FAILURE"
outputCollect += "[%s] %s:\n" % (prefix, str(host))
if os.path.isfile(sshOutPutFile):
context = ""
with open(sshOutPutFile, "r") as fp:
context = fp.read()
outputCollect += context
if os.path.isfile(sshErrorPutFile):
context = ""
with open(sshErrorPutFile, "r") as fp:
context = fp.read()
outputCollect += context
except Exception as e:
raise Exception(str(e))
return resultMap, outputCollect
def timeOutClean(self, cmd, psshpre, hostList=None, env_file="",
parallel_num=300, signal=9):
"""
function: timeout clean
"""
if hostList is None:
hostList = []
pstree = "python3 %s -sc" % os.path.realpath(os.path.dirname(
os.path.realpath(__file__)) + "/../../py_pstree.py")
mpprcFile, userProfile, osProfile = self.getUserOSProfile(env_file)
# kill the parent and child process. get all process by py_pstree.py
timeOutCmd = "source %s && pidList=\`ps aux | grep \\\"%s\\\" |" \
" grep -v 'grep' | awk '{print \$2}' | xargs \`; " \
% (osProfile, cmd)
timeOutCmd += "for pid in \$pidList; do %s \$pid | xargs -r -n 100" \
" kill -%s; done" % (pstree, str(signal))
if len(hostList) == 0:
if os.getuid() == 0 and (mpprcFile == "" or not mpprcFile):
sshCmd = "source %s && %s -t %s -h %s -P -p %s -o %s -e" \
" %s \"source %s; %s\" 2>&1 | tee %s" % \
(
osProfile, psshpre, self.__timeout,
self.__hostsFile,
parallel_num, self.__outputPath,
self.__errorPath, osProfile, timeOutCmd,
self.__resultFile)
else:
sshCmd = "source %s && %s -t %s -h %s -P -p %s -o %s -e" \
" %s \"source %s;source %s;%s\" 2>&1 | tee %s" % \
(
osProfile, psshpre, self.__timeout,
self.__hostsFile,
parallel_num, self.__outputPath,
self.__errorPath, osProfile, userProfile,
timeOutCmd,
self.__resultFile)
else:
if os.getuid() == 0 and (mpprcFile == "" or not mpprcFile):
sshCmd = "source %s && %s -t %s -H %s -P -p %s -o %s -e" \
" %s \"source %s; %s\" 2>&1 | tee %s" % \
(osProfile, psshpre, self.__timeout,
" -H ".join(hostList), parallel_num,
self.__outputPath,
self.__errorPath, osProfile, timeOutCmd,
self.__resultFile)
else:
sshCmd = "source %s && %s -t %s -H %s -P -p %s -o %s -e" \
" %s \"source %s;source %s;%s\" 2>&1 | tee %s" % \
(osProfile, psshpre, self.__timeout,
" -H ".join(hostList), parallel_num,
self.__outputPath,
self.__errorPath, osProfile, userProfile,
timeOutCmd, self.__resultFile)
subprocess.getstatusoutput(sshCmd)
def executeCommand(self, cmd, descript, cmdReturn=DefaultValue.SUCCESS,
hostList=None, env_file="", parallel_num=300,
checkenv=False):
"""
function: Execute command on all hosts
input : cmd, descript, cmdReturn, hostList, env_file, parallel_num
output: NA
"""
sshCmd = ""
localMode = False
resultMap = {}
outputCollect = ""
isTimeOut = False
if hostList is None:
hostList = []
try:
mpprcFile, userProfile, osProfile = self.getUserOSProfile(
env_file)
GPHOME = self.getGPHOMEPath(osProfile)
psshpre = "python3 %s/script/gspylib/pssh/bin/pssh" % GPHOME
# clean result file
if os.path.exists(self.__resultFile):
os.remove(self.__resultFile)
if len(hostList) == 0:
if os.getuid() == 0 and (mpprcFile == "" or not mpprcFile):
sshCmd = "source %s && %s -t %s -h %s -P -p %s -o %s -e" \
" %s \"source %s; %s\" 2>&1 | tee %s" \
% (osProfile, psshpre, self.__timeout,
self.__hostsFile, parallel_num,
self.__outputPath, self.__errorPath,
osProfile, cmd, self.__resultFile)
else:
sshCmd = "source %s && %s -t %s -h %s -P -p %s -o %s -e" \
" %s \"source %s;source %s;%s\" 2>&1 | tee %s" \
% (osProfile, psshpre, self.__timeout,
self.__hostsFile, parallel_num,
self.__outputPath, self.__errorPath,
osProfile, userProfile, cmd,
self.__resultFile)
hostList = self.hostNames
else:
if os.getuid() == 0 and (mpprcFile == "" or not mpprcFile):
sshCmd = "source %s && %s -t %s -H %s -P -p %s -o %s -e" \
" %s \"source %s; %s\" 2>&1 | tee %s" \
% (osProfile, psshpre, self.__timeout,
" -H ".join(hostList), parallel_num,
self.__outputPath, self.__errorPath,
osProfile, cmd, self.__resultFile)
else:
sshCmd = "source %s && %s -t %s -H %s -P -p %s -o %s -e" \
" %s \"source %s;source %s;%s\" 2>&1 | tee %s" \
% (osProfile, psshpre, self.__timeout,
" -H ".join(hostList), parallel_num,
self.__outputPath, self.__errorPath,
osProfile, userProfile, cmd,
self.__resultFile)
# single cluster or execute only in local node.
if (len(hostList) == 1 and
hostList[0] == DefaultValue.GetHostIpOrName()
and cmd.find(" --lock-cluster ") < 0):
localMode = True
if os.getuid() == 0 and (mpprcFile == "" or not mpprcFile):
sshCmd = "source %s ; %s 2>&1" % (osProfile, cmd)
else:
sshCmd = "source %s ; source %s; %s 2>&1" \
% (osProfile, userProfile, cmd)
# if it is localMode, it means does not call pssh,
# so there is no time out
(status, output) = subprocess.getstatusoutput(sshCmd)
# when the pssh is time out, kill parent and child process
if not localMode:
if output.find("Timed out, Killed by signal 9") > 0:
self.timeOutClean(cmd, psshpre, hostList, env_file,
parallel_num)
isTimeOut = True
raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"]
% sshCmd + " Error:\n%s" % output)
if status != 0:
raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"]
% sshCmd + " Error:\n%s" % output)
if localMode:
resultMap[hostList[0]] = DefaultValue.SUCCESS if status == 0 \
else DefaultValue.FAILURE
outputCollect = "[%s] %s:\n%s" \
% ("SUCCESS" if status == 0 else "FAILURE",
hostList[0], output)
else:
# ip and host name should match here
resultMap, outputCollect = self.parseSshResult(hostList)
except Exception as e:
if not isTimeOut:
self.clenSshResultFiles()
raise Exception(str(e))
for host in hostList:
if resultMap.get(host) != cmdReturn:
if outputCollect.find("GAUSS-5") == -1:
raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"]
% cmd + " Result:%s.\nError:\n%s"
% (resultMap, outputCollect))
else:
raise Exception(outputCollect)
if checkenv:
for res in output.split("\n"):
if res.find("[SUCCESS]") >= 0:
continue
elif res == "":
continue
else:
if mpprcFile != "" and mpprcFile is not None:
envfile = mpprcFile + " and /etc/profile"
else:
envfile = "/etc/profile and ~/.bashrc"
raise Exception(ErrorCode.GAUSS_518["GAUSS_51808"]
% res + "Please check %s." % envfile)
def getSshStatusOutput(self, cmd, hostList=None, env_file="",
gp_path="", parallel_num=300, ssh_config=""):
"""
function: Get command status and output
input : cmd, hostList, env_file, gp_path, parallel_num
output: resultMap, outputCollect
"""
sshCmd = ""
localMode = False
resultMap = {}
outputCollect = ""
isTimeOut = False
need_replace_quotes = False
if hostList is None:
hostList = []
if cmd.find("[need_replace_quotes]") != -1:
cmd = cmd.replace("[need_replace_quotes]", "")
need_replace_quotes = True
fp = None
try:
mpprcFile, userProfile, osProfile = self.getUserOSProfile(
env_file)
# clean result file
if os.path.exists(self.__resultFile):
os.remove(self.__resultFile)
if gp_path == "":
GPHOME = self.getGPHOMEPath(osProfile)
else:
GPHOME = gp_path.strip()
psshpre = "python3 %s/script/gspylib/pssh/bin/pssh" % GPHOME
if ssh_config:
if os.path.exists(ssh_config) and os.path.isfile(ssh_config):
psshpre += ' -x "-F %s" ' % ssh_config
if len(hostList) == 0:
if os.getuid() == 0 and (mpprcFile == "" or not mpprcFile):
sshCmd = "source %s && %s -t %s -h %s -P -p %s -o %s -e" \
" %s \"source %s; %s\" 2>&1 | tee %s" \
% (osProfile, psshpre, self.__timeout,
self.__hostsFile, parallel_num,
self.__outputPath, self.__errorPath,
osProfile, cmd, self.__resultFile)
else:
sshCmd = "source %s && %s -t %s -h %s -P -p %s -o %s -e" \
" %s \"source %s;source %s;%s\" 2>&1 | tee %s" \
% (osProfile, psshpre, self.__timeout,
self.__hostsFile, parallel_num,
self.__outputPath, self.__errorPath,
osProfile, userProfile, cmd,
self.__resultFile)
hostList = self.hostNames
else:
if need_replace_quotes:
remote_cmd = cmd.replace("\"", "\\\"")
else:
remote_cmd = cmd
if os.getuid() == 0 and (mpprcFile == "" or not mpprcFile):
sshCmd = "source %s && %s -t %s -H %s -P -p %s -o %s -e" \
" %s \"source %s; %s\" 2>&1 | tee %s" \
% (osProfile, psshpre, self.__timeout,
" -H ".join(hostList), parallel_num,
self.__outputPath, self.__errorPath,
osProfile, remote_cmd, self.__resultFile)
else:
sshCmd = "source %s && %s -t %s -H %s -P -p %s -o %s -e" \
" %s \"source %s;source %s;%s\" 2>&1 | tee %s" \
% (osProfile, psshpre, self.__timeout,
" -H ".join(hostList), parallel_num,
self.__outputPath, self.__errorPath,
osProfile, userProfile, remote_cmd,
self.__resultFile)
# single cluster or execute only in local node.
if (len(hostList) == 1 and
hostList[0] == DefaultValue.GetHostIpOrName()):
localMode = True
if os.getuid() == 0 and (mpprcFile == "" or not mpprcFile):
sshCmd = "source %s ; %s 2>&1" % (osProfile, cmd)
else:
sshCmd = "source %s ; source %s; %s 2>&1" % (osProfile,
userProfile,
cmd)
(status, output) = subprocess.getstatusoutput(sshCmd)
# when the pssh is time out, kill parent and child process
if not localMode:
if output.find("Timed out, Killed by signal 9") > 0:
isTimeOut = True
self.timeOutClean(cmd, psshpre, hostList, env_file,
parallel_num)
raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"]
% sshCmd + " Error:\n%s" % output)
if status != 0:
raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"]
% sshCmd + " Error:\n%s" % output)
if localMode:
dir_permission = 0o700
if status == 0:
resultMap[hostList[0]] = DefaultValue.SUCCESS
outputCollect = "[%s] %s:\n%s" % ("SUCCESS", hostList[0],
output)
if not os.path.exists(self.__outputPath):
os.makedirs(self.__outputPath, mode=dir_permission)
file_path = os.path.join(self.__outputPath, hostList[0])
g_file.createFileInSafeMode(file_path)
with open(file_path, "w") as fp:
fp.write(output)
fp.flush()
fp.close()
else:
resultMap[hostList[0]] = DefaultValue.FAILURE
outputCollect = "[%s] %s:\n%s" % ("FAILURE", hostList[0],
output)
if not os.path.exists(self.__errorPath):
os.makedirs(self.__errorPath, mode=dir_permission)
file_path = os.path.join(self.__errorPath, hostList[0])
g_file.createFileInSafeMode(file_path)
with open(file_path, "w") as fp:
fp.write(output)
fp.flush()
fp.close()
else:
resultMap, outputCollect = self.parseSshResult(hostList)
except Exception as e:
if fp:
fp.close()
if not isTimeOut:
self.clenSshResultFiles()
raise Exception(str(e))
for host in hostList:
if resultMap.get(host) != DefaultValue.SUCCESS:
if outputCollect.find("GAUSS-5") == -1:
outputCollect = ErrorCode.GAUSS_514["GAUSS_51400"] \
% cmd + " Error:\n%s." % outputCollect
break
return resultMap, outputCollect
def parseSshOutput(self, hostList):
"""
function:
parse ssh output on every host
input:
hostList: the hostname list of all hosts
output:
a dict, like this "hostname : info of this host"
hiden info:
the output info of all hosts
ppp:
for a host in hostList
if outputfile exists
open file with the same name
read context into a str
close file
save info of this host
else
raise exception
return host info list
"""
resultMap = {}
try:
for host in hostList:
context = ""
sshOutPutFile = "%s/%s" % (self.__outputPath, host)
sshErrorPutFile = "%s/%s" % (self.__errorPath, host)
if os.path.isfile(sshOutPutFile):
with open(sshOutPutFile, "r") as fp:
context = fp.read()
resultMap[host] = context
if os.path.isfile(sshErrorPutFile):
with open(sshErrorPutFile, "r") as fp:
context += fp.read()
resultMap[host] = context
if (not os.path.isfile(sshOutPutFile) and
not os.path.isfile(sshErrorPutFile)):
raise Exception(ErrorCode.GAUSS_502["GAUSS_50201"]
% "%s or %s"
% (sshOutPutFile, sshErrorPutFile))
except Exception as e:
raise Exception(str(e))
return resultMap
def scpFiles(self, srcFile, targetDir, hostList=None, env_file="",
gp_path="", parallel_num=300):
"""
function: copy files to other path
input : srcFile, targetDir, hostList, env_file, gp_path, parallel_num
output: NA
"""
scpCmd = "source /etc/profile"
outputCollect = ""
if hostList is None:
hostList = []
try:
if env_file != "":
mpprcFile = env_file
else:
mpprcFile = DefaultValue.getEnv(DefaultValue.MPPRC_FILE_ENV)
if mpprcFile != "" and mpprcFile is not None:
scpCmd += " && source %s" % mpprcFile
if gp_path == "":
cmdpre = "%s && echo $GPHOME" % scpCmd
(status, output) = subprocess.getstatusoutput(cmdpre)
if status != 0 or not output or output.strip() == "":
raise Exception(ErrorCode.GAUSS_518["GAUSS_51802"]
% "GPHOME" + "The cmd is %s" % cmdpre)
GPHOME = output.strip()
else:
GPHOME = gp_path.strip()
pscppre = "python3 %s/script/gspylib/pssh/bin/pscp" % GPHOME
if len(hostList) == 0:
scpCmd += " && %s -r -v -t %s -p %s -h %s -o %s -e %s %s %s" \
" 2>&1 | tee %s" % (pscppre, self.__timeout,
parallel_num, self.__hostsFile,
self.__outputPath,
self.__errorPath, srcFile,
targetDir, self.__resultFile)
hostList = self.hostNames
else:
scpCmd += " && %s -r -v -t %s -p %s -H %s -o %s -e %s %s %s" \
" 2>&1 | tee %s" % (pscppre, self.__timeout,
parallel_num,
" -H ".join(hostList),
self.__outputPath,
self.__errorPath, srcFile,
targetDir, self.__resultFile)
(status, output) = subprocess.getstatusoutput(scpCmd)
if status != 0:
raise Exception(ErrorCode.GAUSS_502["GAUSS_50216"]
% ("file [%s]" % srcFile) +
" To directory: %s."
% targetDir + " Error:\n%s" % output)
if output.find("Timed out") > 0:
raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % scpCmd
+ " Error:\n%s" % output)
# ip and host name should match here
resultMap, outputCollect = self.parseSshResult(hostList)
except Exception as e:
self.clenSshResultFiles()
raise Exception(str(e))
for host in hostList:
if resultMap.get(host) != DefaultValue.SUCCESS:
raise Exception(ErrorCode.GAUSS_502["GAUSS_50216"]
% ("file [%s]" % srcFile) +
" To directory: %s." % targetDir +
" Command: %s.\nError:\n%s" % (scpCmd,
outputCollect))
def checkRemoteFileExist(self, node, fileAbsPath, mpprcFile):
"""
check remote node exist file
this method depend on directory permisstion 'x'
if exist return true,else retrun false
"""
sshcmd = "if [ -e '%s' ];then echo 'exist tar file yes flag';" \
"else echo 'exist tar file no flag';fi" % fileAbsPath
if node != DefaultValue.GetHostIpOrName():
outputCollect = self.getSshStatusOutput(sshcmd,
[node],
mpprcFile)[1]
else:
outputCollect = subprocess.getstatusoutput(sshcmd)[1]
if 'exist tar file yes flag' in outputCollect:
return True
elif 'exist tar file no flag' in outputCollect:
return False
else:
raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % sshcmd
+ "On node %s" % node)
def __writeHostFiles(self):
"""
function: Write all hostname to a file
input : NA
output: NA
"""
try:
g_file.createFileInSafeMode(self.__hostsFile)
with open(self.__hostsFile, "w") as fp:
for host in self.hostNames:
fp.write("%s\n" % host)
fp.flush()
subprocess.getstatusoutput("chmod %s '%s'"
% (DefaultValue.FILE_MODE,
self.__hostsFile))
except Exception as e:
g_file.removeFile(self.__hostsFile)
raise Exception(ErrorCode.GAUSS_502["GAUSS_50205"] % "host file"
+ " Error: \n%s" % str(e))
# change the mode
# if it created by root user,and permission is 640, then
# install user will have no permission to read it, so we should set
# its permission 644.
g_file.changeMode(DefaultValue.KEY_HOSTS_FILE, self.__hostsFile, False,
"python")
def __readCmdResult(self, resultFile, hostNum):
"""
function: Read command result
input : resultFile, hostNum, cmd
output: resultMap
"""
resultMap = {}
try:
with open(resultFile, "r") as fp:
lines = fp.readlines()
context = "".join(lines)
for line in lines:
resultPair = line.strip().split(" ")
if len(resultPair) >= 4 and resultPair[2] == "[FAILURE]":
resultMap[resultPair[3]] = "Failure"
if len(resultPair) >= 4 and resultPair[2] == "[SUCCESS]":
resultMap[resultPair[3]] = "Success"
if len(resultMap) != hostNum:
raise Exception(ErrorCode.GAUSS_516["GAUSS_51637"]
% ("valid return item number [%d]"
% len(resultMap), "host number[%d]"
% hostNum) + " The return result:\n%s."
% context)
except Exception as e:
raise Exception(str(e))
return resultMap
def setTimeOut(self, timeout):
"""
function: Set a new timeout value for ssh tool.
:param timeout: The new timeout value in seconds.
:return: void
"""
self.__timeout = timeout