Files
openGauss-OM/script/local/Restore.py
coolany eae422baf3 适配CM组件
Signed-off-by: coolany <kyosang@163.com>

support cgroup

追加合入
2022-03-05 18:51:52 +08:00

529 lines
20 KiB
Python

#!/usr/bin/env python3
# -*- 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 : Restore.py is a local utility to
# restore binary file and parameter file.
#############################################################################
import subprocess
import getopt
import os
import sys
sys.path.append(sys.path[0] + "/../")
from gspylib.common.ParameterParsecheck import Parameter
from gspylib.common.GaussLog import GaussLog
from gspylib.common.Common import DefaultValue
from gspylib.common.ErrorCode import ErrorCode
from gspylib.common.LocalBaseOM import LocalBaseOM
from gspylib.common.DbClusterInfo import dbClusterInfo
from gspylib.os.gsfile import g_file
from domain_utils.cluster_file.cluster_log import ClusterLog
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 domain_utils.domain_common.cluster_constants import ClusterConstants
from base_utils.common.constantsbase import ConstantsBase
from domain_utils.cluster_os.cluster_user import ClusterUser
# init config file parameter
POSTGRESQL_CONF = "postgresql.conf"
POSTGRESQL_HBA_CONF = "pg_hba.conf"
HOSTNAME = NetUtil.GetHostIpOrName()
# init global paramter
g_clusterUser = ""
g_ignoreMiss = False
g_forceRestore = False
g_staticFile = ""
class LocalRestore(LocalBaseOM):
'''
classdocs
'''
def __init__(self, logFile="", user="", restoreDir="", restorePara=False,
restoreBin=False):
"""
function: Constructor
input : logFile, user, restoreDir, restorePara, restoreBin
output: NA
"""
LocalBaseOM.__init__(self, logFile, user)
self.restoreDir = restoreDir
self.restorePara = restorePara
self.restoreBin = restoreBin
self.installPath = ""
self.binExtractName = ""
self.group = ""
self.dbNodeInfo = None
self.clusterInfo = None
self.__hostNameFile = None
# #static parameter
# Use binary_$hostname/parameter_$hostname to
# confirm the backup asked that
self.binTarName = "binary_%s.tar" % HOSTNAME
self.paraTarName = "parameter_%s.tar" % HOSTNAME
self.hostnameFileName = "HOSTNAME"
##########################################################################
# This is the main restore flow.
##########################################################################
def run(self):
"""
function: 1.parse the configuration file
2.check restored directory
3.restore files
input : NA
output: NA
"""
try:
self.logger.log("Executing the local restoration")
self.parseConfigFile()
self.checkRestoreDir()
self.doRestore()
self.logger.log("Successfully execute the local restoration.")
self.logger.closeLog()
sys.exit(0)
except Exception as e:
raise Exception(str(e))
def parseConfigFile(self):
"""
function: parse the configuration file:
1.get local installation path for restoration
2.Obtain user and group for restoration
3.Obtain the local node information for restoration
input : NA
output: NA
"""
self.logger.log("Parsing the configuration file.")
try:
self.clusterInfo = dbClusterInfo()
gaussHome = EnvUtil.getEnvironmentParameterValue("GAUSSHOME", self.user)
if g_forceRestore and self.restoreBin:
self.clusterInfo.appPath = gaussHome
else:
self.clusterInfo.initFromStaticConfig(self.user, g_staticFile)
hostName = NetUtil.GetHostIpOrName()
self.dbNodeInfo = self.clusterInfo.getDbNodeByName(hostName)
if self.dbNodeInfo is None:
self.logger.logExit(
ErrorCode.GAUSS_516["GAUSS_51619"] % hostName)
# Getting local installation path for restoration.
self.logger.log("Getting local installation path for restoration.")
self.installPath = os.path.realpath(self.clusterInfo.appPath)
self.binExtractName = self.installPath.split("/")[-1]
self.logger.debug(
"Local installation path: %s." % self.installPath)
except Exception as e:
raise Exception(str(e))
self.logger.log("Successfully parsed the configuration file.")
def checkRestoreDir(self):
"""
function: check restored directory
input : NA
output: NA
"""
self.logger.log("Checking restored directory.")
try:
if (not os.path.exists(self.restoreDir) or len(
os.listdir(self.restoreDir)) == 0):
if (g_ignoreMiss):
self.logger.log(
"Restored directory does not exist or is empty.")
sys.exit(0)
else:
raise Exception(ErrorCode.GAUSS_502[
"GAUSS_50228"] % "restored directory" +
" Error: \n%s" % self.restoreDir)
except Exception as e:
raise Exception(str(e))
self.logger.log("Successfully checked restored directory.")
def doRestore(self):
"""
function: restore files
Restoring binary files:
1.decompress tar file
2.Check binary files
3.Create installation path
4.Restore binary files to install path
Restoring parameter files:
1.decompress tar file
2.delete temporary directory
3.extract parameter files to the temporary directory
4.check hostname and parameter
5.Restore parameter files
6.Remove the temporary directory
input : NA
output: NA
"""
self.logger.log("Restoring files.")
if self.restoreBin:
self.logger.log("Restoring binary files.")
try:
# decompress tar file
self.decompressTarFile("binary")
# Checking binary files
self.logger.debug("Checking if binary files exist.")
tarName = os.path.join(self.restoreDir, self.binTarName)
if (not os.path.exists(tarName)):
raise Exception(
ErrorCode.GAUSS_502["GAUSS_50201"] % "Binary files")
# Creating installation path
self.logger.debug(
"Creating installation path if did not exist.")
if (not os.path.exists(self.installPath)):
os.makedirs(self.installPath,
ConstantsBase.KEY_DIRECTORY_PERMISSION)
# Restore binary files to install path.
self.logger.debug("Restore binary files to install path.")
FileUtil.cleanDirectoryContent(self.installPath)
cmd = g_file.SHELL_CMD_DICT["decompressTarFile"] % (
self.restoreDir, tarName)
cmd += " && "
cmd += g_file.SHELL_CMD_DICT["copyFile"] % (
"'%s'/*" % self.binExtractName, self.installPath)
self.logger.debug(
"Command for restoring binary files:%s." % cmd)
(status, output) = subprocess.getstatusoutput(cmd)
if (status != 0):
raise Exception(ErrorCode.GAUSS_502["GAUSS_50220"] % (
"binary files to install path[%s]" % \
self.installPath) + " Error: \n%s" % output)
FileUtil.removeDirectory(
os.path.join(self.restoreDir, self.binExtractName))
except Exception as e:
raise Exception(str(e))
self.logger.log("Successfully restored binary files.")
if self.restorePara:
self.logger.log("Restoring parameter files.")
# Re-obtaining clusterInfo because the restoreBin succeeded
if self.dbNodeInfo is None:
self.clusterInfo.initFromStaticConfig(self.user, g_staticFile)
hostName = NetUtil.GetHostIpOrName()
self.dbNodeInfo = self.clusterInfo.getDbNodeByName(
hostName)
if self.dbNodeInfo is None:
self.logger.logExit(
ErrorCode.GAUSS_516["GAUSS_51619"] % hostName)
# Restoring parameter files.
try:
# decompress tar file
self.decompressTarFile("parameter")
# delete temporary directory
self.logger.debug(
"Delete temporary directory if it has existed.")
temp_dir = os.path.join(self.restoreDir,
"parameter_%s" % HOSTNAME)
if (os.path.exists(temp_dir)):
FileUtil.removeDirectory(temp_dir)
# extract parameter files to the temporary directory
self.logger.debug(
"Extract parameter files to the temporary directory.")
tarName = os.path.join(self.restoreDir, self.paraTarName)
if (not os.path.exists(tarName)):
if (g_ignoreMiss):
self.logger.error(ErrorCode.GAUSS_502[
"GAUSS_50201"]
% "parameter files")
sys.exit(0)
else:
raise Exception(ErrorCode.GAUSS_502[
"GAUSS_50201"] % "parameter files")
cmd = g_file.SHELL_CMD_DICT["decompressTarFile"] % (
self.restoreDir, tarName)
(status, output) = subprocess.getstatusoutput(cmd)
if (status != 0):
raise Exception(ErrorCode.GAUSS_514[
"GAUSS_51400"] % cmd
+ " Error: \n%s" % output)
# check hostname
self.logger.debug("Checking hostname.")
self.__checkHostName(
"%s/%s" % (temp_dir, self.hostnameFileName))
# check parameter
self.logger.debug("Checking parameter files.")
paraFileList = []
self.__checkParaFiles(temp_dir, paraFileList)
self.logger.debug("Restoring parameter files.")
paraFileNum = len(paraFileList)
for i in range(paraFileNum):
tarFileName, paraFilePath = paraFileList[i].split('|')
FileUtil.cpFile(os.path.join(temp_dir, tarFileName),
paraFilePath)
self.logger.debug("Remove the temporary directory.")
FileUtil.removeDirectory(temp_dir)
except Exception as e:
FileUtil.removeDirectory(temp_dir)
raise Exception(str(e))
self.logger.log("Successfully restored parameter files.")
self.logger.log("Successfully restored files.")
def decompressTarFile(self, flag):
"""
function: Decompress package on restore node
input : flag
output: NA
"""
tarFile = "%s/%s.tar" % (self.restoreDir, flag)
if (not os.path.exists(tarFile)):
return
# Decompress package on restore node
cmd = g_file.SHELL_CMD_DICT["decompressTarFile"] % (
self.restoreDir, tarFile)
(status, output) = subprocess.getstatusoutput(cmd)
if (status != 0):
raise Exception(ErrorCode.GAUSS_502[
"GAUSS_50217"] % tarFile
+ " Error: \n%s." % output
+ "The cmd is %s " % cmd)
def __checkHostName(self, hostnameFile):
"""
function: make sure the hostname stored in tar files
input : hostnameFile
output: NA
"""
# make sure the hostname stored in tar files
localHostName = NetUtil.GetHostIpOrName()
with open(hostnameFile, 'r') as self.__hostNameFile:
storedHostName = self.__hostNameFile.read()
storedHostName.strip('\n')
if (((localHostName > storedHostName) - (
localHostName < storedHostName)) != 0):
raise Exception(ErrorCode.GAUSS_516["GAUSS_51637"] % \
(("Local hostname [%s]",
"the hostname [%s] stored in tar files") % (
localHostName, storedHostName)))
def __checkParaFiles(self, temp_dir, paraFileList):
"""
function: check parameter file
input : temp_dir, paraFileList
output: NA
"""
storedParaFileNum = len(os.listdir(temp_dir)) - 1
for inst in self.dbNodeInfo.datanodes:
self.__checkSingleParaFile(inst, temp_dir, paraFileList)
if ((storedParaFileNum > len(paraFileList)) -
(storedParaFileNum < len(paraFileList))) != 0:
raise Exception(ErrorCode.GAUSS_516["GAUSS_51637"] %
("number of parameter files",
"the number of files requested"))
def __checkSingleParaFile(self, inst, temp_dir, paraFileList):
"""
function: check single parameter file
input : inst, temp_dir, paraFileList
output: NA
"""
# makesure instance exist
if (not os.path.exists(inst.datadir)):
if (g_ignoreMiss):
self.logger.log(
"Data directory [%s] of instance [%s]does not exist." % (
inst.datadir, str(inst)))
return
else:
raise Exception(ErrorCode.GAUSS_502["GAUSS_50201"] % \
("Data directory [%s] of instance [%s]" % (
inst.datadir, str(inst))))
# get all parameter file path into paraFileMap
paraFileMap = {}
if inst.instanceRole == DefaultValue.INSTANCE_ROLE_DATANODE:
paraFileMap[POSTGRESQL_CONF] = \
os.path.join(inst.datadir, POSTGRESQL_CONF)
paraFileMap[POSTGRESQL_HBA_CONF] = \
os.path.join(inst.datadir, POSTGRESQL_HBA_CONF)
else:
raise Exception(ErrorCode.GAUSS_516["GAUSS_51204"] % (
"specified", inst.instanceRole))
for key in paraFileMap:
backupFileName = "%d_%s" % (inst.instanceId, key)
if (not os.path.exists(os.path.join(temp_dir, backupFileName))):
if (g_ignoreMiss):
self.logger.log(
"The file of %s does not exist." % backupFileName)
return
else:
raise Exception(
ErrorCode.GAUSS_502["GAUSS_50201"] % backupFileName)
newRecord = "%s|%s" % (backupFileName, paraFileMap[key])
paraFileList.append(newRecord)
##############################################################################
# Help context. U:R:oC:v:
##############################################################################
def usage():
"""
function: usage
input : NA
output : NA
"""
print(
"Restore.py is a local utility to restore binary file "
"and parameter file.")
print(" ")
print("Usage:")
print("python3 Restore.py --help")
print(" ")
print("Common options:")
print(" -U the user of cluster.")
print(" -P, --position=RESTOREPATH the restore directory.")
print(" -p, --parameter restore parameter files.")
print(" -b, --binary_file restore binary files.")
print(" -i, --ingore_miss ignore Backup entity miss.")
print(" -s, --static_file static configuration files.")
print(" -l, --logpath=LOGPATH the log directory.")
print(" -h, --help show this help, then exit.")
print(" ")
def checkUserExist():
"""
function: check user exists
input : NA
output: NA
"""
if (g_clusterUser == ""):
GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"] % "U" + ".")
ClusterUser.checkUser(g_clusterUser, False)
def checkRestorePara(restorePara, restoreBin):
"""
function: check restore parameter
input : NA
output: NA
"""
if not restorePara and not restoreBin:
GaussLog.exitWithError(
ErrorCode.GAUSS_500["GAUSS_50001"] % "p or -b" + ".")
def checkRestoreDir(restoreDir):
"""
function: check restore directory
input : NA
output: NA
"""
if (restoreDir == ""):
GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"] % "P" + ".")
def main():
"""
function: main function
input : NA
output: NA
"""
try:
opts, args = getopt.getopt(sys.argv[1:], "U:P:l:pbhifs:",
["position=", "parameter", "binary_file",
"logpath=", "help", "ingore_miss",
"force", "static_file="])
except getopt.GetoptError as e:
GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50000"] % e.msg)
if (len(args) > 0):
GaussLog.exitWithError(
ErrorCode.GAUSS_500["GAUSS_50000"] % str(args[0]))
global g_clusterUser
global g_ignoreMiss
global g_staticFile
global g_forceRestore
restoreDir = ""
restorePara = False
restoreBin = False
logFile = ""
for key, value in opts:
if (key == "-h" or key == "--help"):
usage()
sys.exit(0)
elif (key == "-U"):
g_clusterUser = value.strip()
elif (key == "-P" or key == "--position"):
restoreDir = value.strip()
elif (key == "-p" or key == "--parameter"):
restorePara = True
elif (key == "-b" or key == "--binary_file"):
restoreBin = True
elif (key == "-i" or key == "--ingore_miss"):
g_ignoreMiss = True
elif (key == "-s" or key == "--static_file"):
g_staticFile = value.strip()
elif (key == "-l" or key == "--logpath"):
logFile = value
elif (key == "-f" or key == "--force"):
g_forceRestore = True
else:
GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50000"] % value)
Parameter.checkParaVaild(key, value)
if (g_ignoreMiss):
gaussHome = EnvUtil.getEnv("GAUSSHOME")
if not gaussHome:
return
# check if user exist and is the right user
checkUserExist()
# check log file
logFile = ClusterLog.checkLogFile(logFile, g_clusterUser, "",
ClusterConstants.LOCAL_LOG_FILE)
# check -p and -b
checkRestorePara(restorePara, restoreBin)
# check -P
checkRestoreDir(restoreDir)
try:
LocalRestorer = LocalRestore(logFile, g_clusterUser, restoreDir,
restorePara, restoreBin)
LocalRestorer.run()
except Exception as e:
GaussLog.exitWithError(str(e))
if __name__ == '__main__':
main()