适配CM组件

Signed-off-by: coolany <kyosang@163.com>

support cgroup

追加合入
This commit is contained in:
coolany
2022-03-03 20:37:33 +08:00
parent 8874d89c6f
commit eae422baf3
229 changed files with 17230 additions and 13148 deletions

View File

@ -17,22 +17,51 @@
# ----------------------------------------------------------------------------
# Description : SshTool.py is utility to support ssh tools
#############################################################################
import socket
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
from base_utils.os.env_util import EnvUtil
from base_utils.os.file_util import FileUtil
from base_utils.os.net_util import NetUtil
from base_utils.os.cmd_util import CmdUtil
from domain_utils.domain_common.cluster_constants import ClusterConstants
from base_utils.security.sensitive_mask import SensitiveMask
from gspylib.common.Constants import Constants
try:
import paramiko
except ImportError as e:
import ctypes
if str(e).find('SSLv3_method') == -1:
# not find SSLv3_method, and it's not ours
local_path = os.path.dirname(os.path.realpath(__file__))
clib_path = os.path.realpath(os.path.join(local_path, "../../gspylib/clib/"))
ssl_path = os.path.join(clib_path, 'libssl.so.1.1')
crypto_path = os.path.join(clib_path, 'libcrypto.so.1.1')
if os.path.isfile(crypto_path):
ctypes.CDLL(crypto_path, mode=ctypes.RTLD_GLOBAL)
if os.path.isfile(ssl_path):
ctypes.CDLL(ssl_path, mode=ctypes.RTLD_GLOBAL)
else:
ssl_path = '/usr/lib64/libssl.so.1.1'
crypto_path = '/usr/lib64/libcrypto.so.1.1'
if os.path.isfile(crypto_path):
ctypes.CDLL(crypto_path, mode=ctypes.RTLD_GLOBAL)
if os.path.isfile(ssl_path):
ctypes.CDLL(ssl_path, mode=ctypes.RTLD_GLOBAL)
try:
import paramiko
except ImportError as ex:
raise Exception(ErrorCode.GAUSS_522["GAUSS_52200"] % str(e))
class SshTool():
"""
@ -49,6 +78,7 @@ class SshTool():
self.__pid = os.getpid()
self.__timeout = timeout + 10
self._finalizer = weakref.finalize(self, self.clenSshResultFiles)
self.__sessions = {}
currentTime = str(datetime.datetime.now()).replace(" ", "_").replace(
".", "_")
@ -75,20 +105,23 @@ class SshTool():
self.__resultStatus = {}
if logFile is None:
self.__logFile = "/dev/null"
self.__logFile = ClusterConstants.DEV_NULL
# before using, clean the old ones
g_file.removeFile(self.__hostsFile)
g_file.removeFile(self.__resultFile)
FileUtil.removeFile(self.__hostsFile)
FileUtil.removeFile(self.__resultFile)
if os.path.exists(self.__outputPath):
g_file.removeDirectory(self.__outputPath)
FileUtil.removeDirectory(self.__outputPath)
if os.path.exists(self.__errorPath):
g_file.removeDirectory(self.__errorPath)
FileUtil.removeDirectory(self.__errorPath)
self.__writeHostFiles()
def get_result_file(self):
return self.__hostsFile
def clenSshResultFiles(self):
"""
function: Delete file
@ -96,16 +129,16 @@ class SshTool():
output: NA
"""
if os.path.exists(self.__hostsFile):
g_file.removeFile(self.__hostsFile)
FileUtil.removeFile(self.__hostsFile)
if os.path.exists(self.__resultFile):
g_file.removeFile(self.__resultFile)
FileUtil.removeFile(self.__resultFile)
if os.path.exists(self.__outputPath):
g_file.removeDirectory(self.__outputPath)
FileUtil.removeDirectory(self.__outputPath)
if os.path.exists(self.__errorPath):
g_file.removeDirectory(self.__errorPath)
FileUtil.removeDirectory(self.__errorPath)
def __del__(self):
"""
@ -115,71 +148,21 @@ class SshTool():
"""
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):
def createTrust(self, user, ips=[], mpprcFile="", skipHostnameSet=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
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
tmp_hosts = Constants.TMP_HOSTS_FILE % self.__pid
status = 0
output = ""
if ips is None:
ips = []
try:
g_file.removeFile(tmp_hosts)
FileUtil.removeFile(tmp_hosts)
# 1.prepare hosts file
for ip in ips:
cmd = "echo %s >> %s 2>/dev/null" % (ip, tmp_hosts)
@ -188,61 +171,57 @@ class SshTool():
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,
FileUtil.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)
gphome = os.getenv("GPHOME")
if user == "root":
if mpprcFile != "" and FileUtil.check_file_permission(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 FileUtil.check_file_permission(
ClusterConstants.ETC_PROFILE, True):
cmd = "source %s; %s -f %s -l '%s'" % (ClusterConstants.ETC_PROFILE,
create_trust_file, tmp_hosts,
self.__logFile)
else:
if mpprcFile != "" and FileUtil.check_file_permission(mpprcFile, True) and \
self.checkMpprcfile(user, mpprcFile):
cmd = "source %s; %s/script/%s -f %s -l '%s'" % \
(mpprcFile, gphome,
create_trust_file, tmp_hosts, self.__logFile)
elif mpprcFile == "" and FileUtil.check_file_permission(
ClusterConstants.ETC_PROFILE, True):
cmd = "source %s; %s/script/%s -f %s -l '%s'" % \
(ClusterConstants.ETC_PROFILE, gphome, 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())
if os.getuid() == 0:
cmd = "su - %s -c \"%s\" 2>&1" % (user, cmd)
else:
sys.exit(1)
cmd += " 2>&1"
if user == "root":
status, output = subprocess.getstatusoutput(cmd)
else:
status = os.system(cmd)
if status != 0:
# we can not print cmd here, because it include user's passwd
FileUtil.removeFile(tmp_hosts)
raise Exception(ErrorCode.GAUSS_516["GAUSS_51632"] % "gs_sshexkey" +
"Error: %s" % output if output else "")
# 3.delete hosts file
FileUtil.removeFile(tmp_hosts)
except Exception as e:
g_file.removeFile(tmp_hosts)
FileUtil.removeFile(tmp_hosts)
raise Exception(str(e))
def checkMpprcfile(self, username, filePath):
@ -276,13 +255,13 @@ class SshTool():
if env_file != "":
mpprcFile = env_file
else:
mpprcFile = DefaultValue.getEnv(DefaultValue.MPPRC_FILE_ENV)
mpprcFile = EnvUtil.getEnv(DefaultValue.MPPRC_FILE_ENV)
if mpprcFile != "" and mpprcFile is not None:
userProfile = mpprcFile
else:
userProfile = "~/.bashrc"
osProfile = "/etc/profile"
userProfile = ClusterConstants.BASHRC
osProfile = ClusterConstants.ETC_PROFILE
return mpprcFile, userProfile, osProfile
def getGPHOMEPath(self, osProfile):
@ -336,7 +315,7 @@ class SshTool():
return resultMap, outputCollect
def timeOutClean(self, cmd, psshpre, hostList=None, env_file="",
parallel_num=300, signal=9):
parallel_num=300, signal=9, logger=None):
"""
function: timeout clean
"""
@ -388,9 +367,12 @@ class SshTool():
self.__outputPath,
self.__errorPath, osProfile, userProfile,
timeOutCmd, self.__resultFile)
subprocess.getstatusoutput(sshCmd)
(status, output) = CmdUtil.getstatusoutput_by_fast_popen(sshCmd)
if logger:
logger.debug("{timeout clean} status: %s, output: %s" % (
status, SensitiveMask.mask_pwd(output)))
def executeCommand(self, cmd, descript, cmdReturn=DefaultValue.SUCCESS,
def executeCommand(self, cmd, cmdReturn=DefaultValue.SUCCESS,
hostList=None, env_file="", parallel_num=300,
checkenv=False):
"""
@ -408,7 +390,11 @@ class SshTool():
try:
mpprcFile, userProfile, osProfile = self.getUserOSProfile(
env_file)
GPHOME = self.getGPHOMEPath(osProfile)
if os.getuid() == 0:
unpathpath = os.path.dirname(os.path.realpath(__file__))
GPHOME = os.path.realpath(os.path.join(unpathpath, "../../../"))
else:
GPHOME = self.getGPHOMEPath(osProfile)
psshpre = "python3 %s/script/gspylib/pssh/bin/pssh" % GPHOME
# clean result file
@ -451,7 +437,7 @@ class SshTool():
# single cluster or execute only in local node.
if (len(hostList) == 1 and
hostList[0] == DefaultValue.GetHostIpOrName()
hostList[0] == NetUtil.GetHostIpOrName()
and cmd.find(" --lock-cluster ") < 0):
localMode = True
if os.getuid() == 0 and (mpprcFile == "" or not mpprcFile):
@ -470,17 +456,19 @@ class SshTool():
parallel_num)
isTimeOut = True
raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"]
% sshCmd + " Error:\n%s" % output)
% SensitiveMask.mask_pwd(sshCmd) +
" Error:\n%s" % SensitiveMask.mask_pwd(output))
if status != 0:
raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"]
% sshCmd + " Error:\n%s" % output)
% SensitiveMask.mask_pwd(sshCmd) +
" Error:\n%s" % SensitiveMask.mask_pwd(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)
hostList[0], SensitiveMask.mask_pwd(output))
else:
# ip and host name should match here
resultMap, outputCollect = self.parseSshResult(hostList)
@ -494,9 +482,9 @@ class SshTool():
if outputCollect.find("GAUSS-5") == -1:
raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"]
% cmd + " Result:%s.\nError:\n%s"
% (resultMap, outputCollect))
% (resultMap, SensitiveMask.mask_pwd(outputCollect)))
else:
raise Exception(outputCollect)
raise Exception(SensitiveMask.mask_pwd(outputCollect))
if checkenv:
for res in output.split("\n"):
if res.find("[SUCCESS]") >= 0:
@ -540,10 +528,13 @@ class SshTool():
if os.path.exists(self.__resultFile):
os.remove(self.__resultFile)
if gp_path == "":
GPHOME = self.getGPHOMEPath(osProfile)
else:
if gp_path.strip():
GPHOME = gp_path.strip()
elif os.getuid() == 0:
unpathpath = os.path.dirname(os.path.realpath(__file__))
GPHOME = os.path.realpath(os.path.join(unpathpath, "../../../"))
else:
GPHOME = self.getGPHOMEPath(osProfile)
psshpre = "python3 %s/script/gspylib/pssh/bin/pssh" % GPHOME
if ssh_config:
if os.path.exists(ssh_config) and os.path.isfile(ssh_config):
@ -589,7 +580,7 @@ class SshTool():
# single cluster or execute only in local node.
if (len(hostList) == 1 and
hostList[0] == DefaultValue.GetHostIpOrName()):
hostList[0] == NetUtil.GetHostIpOrName()):
localMode = True
if os.getuid() == 0 and (mpprcFile == "" or not mpprcFile):
sshCmd = "source %s ; %s 2>&1" % (osProfile, cmd)
@ -606,37 +597,37 @@ class SshTool():
self.timeOutClean(cmd, psshpre, hostList, env_file,
parallel_num)
raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"]
% sshCmd + " Error:\n%s" % output)
% sshCmd + " Error:\n%s" % SensitiveMask.mask_pwd(output))
if status != 0:
raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"]
% sshCmd + " Error:\n%s" % output)
% sshCmd + " Error:\n%s" % SensitiveMask.mask_pwd(output))
if localMode:
dir_permission = 0o700
if status == 0:
resultMap[hostList[0]] = DefaultValue.SUCCESS
outputCollect = "[%s] %s:\n%s" % ("SUCCESS", hostList[0],
output)
SensitiveMask.mask_pwd(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)
FileUtil.createFileInSafeMode(file_path)
with open(file_path, "w") as fp:
fp.write(output)
fp.write(SensitiveMask.mask_pwd(output))
fp.flush()
fp.close()
else:
resultMap[hostList[0]] = DefaultValue.FAILURE
outputCollect = "[%s] %s:\n%s" % ("FAILURE", hostList[0],
output)
SensitiveMask.mask_pwd(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)
FileUtil.createFileInSafeMode(file_path)
with open(file_path, "w") as fp:
fp.write(output)
fp.write(SensitiveMask.mask_pwd(output))
fp.flush()
fp.close()
else:
@ -652,7 +643,8 @@ class SshTool():
if resultMap.get(host) != DefaultValue.SUCCESS:
if outputCollect.find("GAUSS-5") == -1:
outputCollect = ErrorCode.GAUSS_514["GAUSS_51400"] \
% cmd + " Error:\n%s." % outputCollect
% SensitiveMask.mask_pwd(cmd) \
+ " Error:\n%s." % SensitiveMask.mask_pwd(outputCollect)
break
return resultMap, outputCollect
@ -718,7 +710,7 @@ class SshTool():
if env_file != "":
mpprcFile = env_file
else:
mpprcFile = DefaultValue.getEnv(DefaultValue.MPPRC_FILE_ENV)
mpprcFile = EnvUtil.getEnv(DefaultValue.MPPRC_FILE_ENV)
if mpprcFile != "" and mpprcFile is not None:
scpCmd += " && source %s" % mpprcFile
@ -741,6 +733,9 @@ class SshTool():
self.__errorPath, srcFile,
targetDir, self.__resultFile)
hostList = self.hostNames
if len(hostList) == 1 and hostList[0] == socket.gethostname() and \
srcFile != targetDir:
scpCmd = "cp -r %s %s" % (srcFile, targetDir)
else:
scpCmd += " && %s -r -v -t %s -p %s -H %s -o %s -e %s %s %s" \
" 2>&1 | tee %s" % (pscppre, self.__timeout,
@ -778,8 +773,8 @@ class SshTool():
raise Exception(ErrorCode.GAUSS_502["GAUSS_50216"]
% ("file [%s]" % srcFile) +
" To directory: %s." % targetDir +
" Command: %s.\nError:\n%s" % (scpCmd,
outputCollect))
" Command: %s.\nError:\n%s" % (SensitiveMask.mask_pwd(scpCmd),
SensitiveMask.mask_pwd(outputCollect)))
def checkRemoteFileExist(self, node, fileAbsPath, mpprcFile):
"""
@ -789,7 +784,7 @@ class SshTool():
"""
sshcmd = "if [ -e '%s' ];then echo 'exist tar file yes flag';" \
"else echo 'exist tar file no flag';fi" % fileAbsPath
if node != DefaultValue.GetHostIpOrName():
if node != NetUtil.GetHostIpOrName():
outputCollect = self.getSshStatusOutput(sshcmd,
[node],
mpprcFile)[1]
@ -810,7 +805,7 @@ class SshTool():
output: NA
"""
try:
g_file.createFileInSafeMode(self.__hostsFile)
FileUtil.createFileInSafeMode(self.__hostsFile)
with open(self.__hostsFile, "w") as fp:
for host in self.hostNames:
fp.write("%s\n" % host)
@ -819,7 +814,7 @@ class SshTool():
% (DefaultValue.FILE_MODE,
self.__hostsFile))
except Exception as e:
g_file.removeFile(self.__hostsFile)
FileUtil.removeFile(self.__hostsFile)
raise Exception(ErrorCode.GAUSS_502["GAUSS_50205"] % "host file"
+ " Error: \n%s" % str(e))
@ -827,7 +822,7 @@ class SshTool():
# 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,
FileUtil.changeMode(DefaultValue.KEY_HOSTS_FILE, self.__hostsFile, False,
"python")
def __readCmdResult(self, resultFile, hostNum):
@ -866,3 +861,60 @@ class SshTool():
:return: void
"""
self.__timeout = timeout
def get_ssh_session(self, remote_ip):
"""
get ssh login session
:param remote_ip:
:return:
"""
if remote_ip in self.__sessions.keys():
return self.__sessions[remote_ip]
return None
def create_all_sessions(self, user, all_ips, passwds):
"""
:param user:
:param all_ips:
:param passwds:
:return:
"""
for ip in all_ips:
session = self.create_ssh_session(user, ip, passwds)
if session:
self.__sessions[ip] = session
if not session:
raise Exception(ErrorCode.GAUSS_535["GAUSS_53501"] +"IP is:%s" %ip)
def create_ssh_session(self, user, ip, passwd):
"""
create ssh session
:param user:
:param remote_ip:
:param _passwd:
:return:
"""
try:
ssh = paramiko.Transport((ip, 22))
except Exception as e:
raise Exception(
ErrorCode.GAUSS_512["GAUSS_51220"] % ip + " Error: \n%s" % str(
e))
try:
ssh.connect(username=user, password=passwd[0])
return ssh
except Exception as e:
ssh.close()
raise Exception(ErrorCode.GAUSS_511["GAUSS_51107"] +
"Failed to ssh connect to node[%s]. Error:\n%s" % (ip, e))
def close_all_session(self):
"""
close all sessions
:return:
"""
for session in self.__sessions.values():
session.close()