I1UY6Q 添加参数校验:用户,用户组,版本号一致性等
This commit is contained in:
@ -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:
|
||||||
|
@ -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"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
Reference in New Issue
Block a user