I1UY6Q 添加参数校验:用户,用户组,版本号一致性等

This commit is contained in:
zhang_xubo
2020-09-13 16:39:27 +08:00
parent 5d90db59ae
commit 7acbe191ec
3 changed files with 161 additions and 28 deletions

View File

@ -20,12 +20,8 @@
############################################################################# #############################################################################
import os import os
import pwd
import sys import sys
import threading
import uuid
import subprocess
import weakref
sys.path.append(sys.path[0]) sys.path.append(sys.path[0])
from gspylib.common.DbClusterInfo import dbClusterInfo, \ from gspylib.common.DbClusterInfo import dbClusterInfo, \
@ -61,6 +57,7 @@ class Expansion(ParallelBaseOM):
os.path.join(os.path.realpath(__file__), "../../")) os.path.join(os.path.realpath(__file__), "../../"))
self.standbyLocalMode = False self.standbyLocalMode = False
self.envFile = DefaultValue.getEnv("MPPDB_ENV_SEPARATE_PATH")
def usage(self): def usage(self):
""" """
@ -142,6 +139,13 @@ General options:
backIpList = clusterInfo.getClusterBackIps() backIpList = clusterInfo.getClusterBackIps()
nodeNameList = clusterInfo.getClusterNodeNames() nodeNameList = clusterInfo.getClusterNodeNames()
# only support single az now.
azNames = clusterInfo.getazNames()
self.azName = "AZ1"
if len(azNames) > 0:
self.azName = azNames[0]
self.localIp = backIpList[0]
self.nodeNameList = nodeNameList self.nodeNameList = nodeNameList
self.backIpNameMap = {} self.backIpNameMap = {}
for backip in backIpList: for backip in backIpList:

View File

@ -1108,7 +1108,11 @@ class ErrorCode():
"database on node is abnormal. \n" "database on node is abnormal. \n"
"node [%s], user [%s], dataNode [%s]. \n" "node [%s], user [%s], dataNode [%s]. \n"
"You can use command \"gs_ctl query -D %s\" for more " "You can use command \"gs_ctl query -D %s\" for more "
"detail." "detail.",
"GAUSS_35704": "[GAUSS-35704] %s [%s] does not exist on node [%s].",
"GAUSS_35705": "[GAUSS-35705] Error, the database version is "
"inconsistent in %s: %s"
} }

View File

@ -25,8 +25,12 @@ import os
import getpass import getpass
import pwd import pwd
import datetime import datetime
import weakref
from random import sample from random import sample
import time import time
import grp
import socket
import stat
from multiprocessing import Process, Value from multiprocessing import Process, Value
sys.path.append(sys.path[0] + "/../../../../") sys.path.append(sys.path[0] + "/../../../../")
@ -134,9 +138,10 @@ class ExpansionImpl():
for host in newHosts: for host in newHosts:
# create single deploy xml file for each standby node # create single deploy xml file for each standby node
xmlContent = self.__generateXml(host) xmlContent = self.__generateXml(host)
fo = open("%s" % tempXmlFile, "w") with os.fdopen(os.open("%s" % tempXmlFile, os.O_WRONLY | os.O_CREAT,
fo.write( xmlContent ) stat.S_IWUSR | stat.S_IRUSR),'w') as fo:
fo.close() fo.write( xmlContent )
fo.close()
# send single deploy xml file to each standby node # send single deploy xml file to each standby node
sshTool = SshTool(host) sshTool = SshTool(host)
retmap, output = sshTool.getSshStatusOutput("mkdir -p %s" % retmap, output = sshTool.getSshStatusOutput("mkdir -p %s" %
@ -180,7 +185,7 @@ class ExpansionImpl():
<DEVICELIST> <DEVICELIST>
<DEVICE sn="1000001"> <DEVICE sn="1000001">
<PARAM name="name" value="{nodeName}"/> <PARAM name="name" value="{nodeName}"/>
<PARAM name="azName" value="AZ1"/> <PARAM name="azName" value="{azName}"/>
<PARAM name="azPriority" value="1"/> <PARAM name="azPriority" value="1"/>
<PARAM name="backIp1" value="{backIp}"/> <PARAM name="backIp1" value="{backIp}"/>
<PARAM name="sshIp1" value="{sshIp}"/> <PARAM name="sshIp1" value="{sshIp}"/>
@ -193,7 +198,7 @@ class ExpansionImpl():
</ROOT> </ROOT>
""".format(nodeName=nodeName,backIp=backIp,appPath=appPath, """.format(nodeName=nodeName,backIp=backIp,appPath=appPath,
logPath=logPath,toolPath=toolPath,corePath=corePath, logPath=logPath,toolPath=toolPath,corePath=corePath,
sshIp=sshIp,port=port,dataNode=dataNode) sshIp=sshIp,port=port,dataNode=dataNode,azName=self.context.azName)
return xmlConfig return xmlConfig
def changeUser(self): def changeUser(self):
@ -582,10 +587,11 @@ retry for %s times" % start_retry_num)
subprocess.getstatusoutput("mkdir -m a+x -p %s; touch %s; \ subprocess.getstatusoutput("mkdir -m a+x -p %s; touch %s; \
cat /dev/null > %s" % \ cat /dev/null > %s" % \
(self.tempFileDir, tempShFile, tempShFile)) (self.tempFileDir, tempShFile, tempShFile))
fo = open("%s" % tempShFile, "w") with os.fdopen(os.open("%s" % tempShFile, os.O_WRONLY | os.O_CREAT,
fo.write("#bash\n") stat.S_IWUSR | stat.S_IRUSR),'w') as fo:
fo.write( command ) fo.write("#bash\n")
fo.close() fo.write( command )
fo.close()
# send guc command bashfile to each host and execute it. # send guc command bashfile to each host and execute it.
sshTool.scpFiles("%s" % tempShFile, "%s" % tempShFile, [host], sshTool.scpFiles("%s" % tempShFile, "%s" % tempShFile, [host],
@ -619,14 +625,14 @@ retry for %s times" % start_retry_num)
remoteHostInfo = nodeDict[remoteHost] remoteHostInfo = nodeDict[remoteHost]
guc_repl_template = """\ guc_repl_template = """\
gs_guc set -D {dn} -c "replconninfo{index}=\ gs_guc set -D {dn} -c "replconninfo{index}=\
'localhost={localhost} localport={localport} \ 'localhost={localhost} localport={localport} \
localheartbeatport={localeHeartPort} \ localheartbeatport={localeHeartPort} \
localservice={localservice} \ localservice={localservice} \
remotehost={remoteNode} \ remotehost={remoteNode} \
remoteport={remotePort} \ remoteport={remotePort} \
remoteheartbeatport={remoteHeartPort} \ remoteheartbeatport={remoteHeartPort} \
remoteservice={remoteservice}'" remoteservice={remoteservice}'"
""".format(dn=localeHostInfo["dataNode"], """.format(dn=localeHostInfo["dataNode"],
index=index, index=index,
localhost=localeHostInfo["sshIp"], localhost=localeHostInfo["sshIp"],
@ -653,8 +659,13 @@ retry for %s times" % start_retry_num)
def checkLocalModeOnStandbyHosts(self): def checkLocalModeOnStandbyHosts(self):
""" """
expansion the installed standby node. check standby database.
1. if the database is normal
2. if the databases version are same before existing and new
""" """
standbyHosts = self.context.newHostList standbyHosts = self.context.newHostList
envfile = self.envFile
self.logger.log("Checking the database with locale mode.") self.logger.log("Checking the database with locale mode.")
for host in standbyHosts: for host in standbyHosts:
hostName = self.context.backIpNameMap[host] hostName = self.context.backIpNameMap[host]
@ -665,6 +676,39 @@ retry for %s times" % start_retry_num)
GaussLog.exitWithError(ErrorCode.GAUSS_357["GAUSS_35703"] % GaussLog.exitWithError(ErrorCode.GAUSS_357["GAUSS_35703"] %
(hostName, self.user, dataNode, dataNode)) (hostName, self.user, dataNode, dataNode))
allHostIp = []
allHostIp.append(self.context.localIp)
versionDic = {}
for hostip in standbyHosts:
allHostIp.append(hostip)
sshTool= SshTool(allHostIp)
#get version in the nodes
getversioncmd = "gaussdb --version"
resultMap, outputCollect = sshTool.getSshStatusOutput(getversioncmd,
[], envfile)
self.cleanSshToolFile(sshTool)
versionLines = outputCollect.splitlines()
for verline in versionLines:
if verline[0:9] == '[SUCCESS]':
ipKey = verline[10:-1]
continue
else:
versionStr = "".join(verline)
preVersion = versionStr.split(' ')
versionInfo = preVersion[4]
versionDic[ipKey] = versionInfo[:-2]
for hostip in versionDic:
if hostip == self.context.localIp:
versionCompare = ""
versionCompare = versionDic[hostip]
else:
if versionDic[hostip] == versionCompare:
continue
else:
GaussLog.exitWithError(ErrorCode.GAUSS_357["GAUSS_35705"] \
%(hostip, versionDic[hostip]))
self.logger.log("Successfully checked the database with locale mode.") self.logger.log("Successfully checked the database with locale mode.")
def preInstall(self): def preInstall(self):
@ -686,12 +730,92 @@ standby nodes.")
""" """
self.logger.debug("start to delete temporary file") self.logger.debug("start to delete temporary file")
hostNames = self.context.nodeNameList hostNames = self.context.nodeNameList
sshTool = SshTool(hostNames) def checkNodesDetail(self):
clearCmd = "source %s ; rm -rf %s" % (self.envFile, self.tempFileDir) """
result, output = sshTool.getSshStatusOutput(clearCmd, """
hostNames, self.envFile) self.checkUserAndGroupExists()
self.logger.debug(output) self.checkXmlFileAccessToUser()
def checkXmlFileAccessToUser(self):
"""
Check if the xml config file has readable access to user.
"""
userInfo = pwd.getpwnam(self.user)
uid = userInfo.pw_uid
gid = userInfo.pw_gid
xmlFile = self.context.xmlFile
fstat = os.stat(xmlFile)
mode = fstat[stat.ST_MODE]
if (fstat[stat.ST_UID] == uid and (mode & stat.S_IRUSR > 0)) or \
(fstat[stat.ST_GID] == gid and (mode & stat.S_IRGRP > 0)):
pass
else:
self.logger.debug("User %s has no access right for file %s" \
% (self.user, xmlFile))
os.chown(xmlFile, uid, gid)
os.chmod(xmlFile, stat.S_IRUSR)
def checkUserAndGroupExists(self):
"""
check system user and group exists and be same
on primary and standby nodes
"""
inputUser = self.user
inputGroup = self.group
user_group_id = ""
isUserExits = False
localHost = socket.gethostname()
for user in pwd.getpwall():
if user.pw_name == self.user:
user_group_id = user.pw_gid
isUserExits = True
break
if not isUserExits:
GaussLog.exitWithError(ErrorCode.GAUSS_357["GAUSS_35704"] \
% ("User", self.user, localHost))
isGroupExits = False
group_id = ""
for group in grp.getgrall():
if group.gr_name == self.group:
group_id = group.gr_gid
isGroupExits = True
if not isGroupExits:
GaussLog.exitWithError(ErrorCode.GAUSS_357["GAUSS_35704"] \
% ("Group", self.group, localHost))
if user_group_id != group_id:
GaussLog.exitWithError("User [%s] is not in the group [%s]."\
% (self.user, self.group))
hostNames = self.context.newHostList
envfile = self.envFile
sshTool = SshTool(hostNames)
#get username in the other standy nodes
getUserNameCmd = "cat /etc/passwd | grep -w %s" % inputUser
resultMap, outputCollect = sshTool.getSshStatusOutput(getUserNameCmd,
[], envfile)
for hostKey in resultMap:
if resultMap[hostKey] == STATUS_FAIL:
self.cleanSshToolFile(sshTool)
GaussLog.exitWithError(ErrorCode.GAUSS_357["GAUSS_35704"] \
% ("User", self.user, hostKey))
#get groupname in the other standy nodes
getGroupNameCmd = "cat /etc/group | grep -w %s" % inputGroup
resultMap, outputCollect = sshTool.getSshStatusOutput(getGroupNameCmd,
[], envfile)
for hostKey in resultMap:
if resultMap[hostKey] == STATUS_FAIL:
self.cleanSshToolFile(sshTool)
GaussLog.exitWithError(ErrorCode.GAUSS_357["GAUSS_35704"] \
% ("Group", self.group, hostKey))
self.cleanSshToolFile(sshTool)
def installAndExpansion(self): def installAndExpansion(self):
""" """
install database and expansion standby node with db om user install database and expansion standby node with db om user
@ -727,6 +851,7 @@ Start to establish the primary-standby relationship.")
""" """
start expansion start expansion
""" """
self.checkNodesDetail()
# preinstall on standby nodes with root user. # preinstall on standby nodes with root user.
if not self.context.standbyLocalMode: if not self.context.standbyLocalMode:
self.preInstall() self.preInstall()