509 lines
18 KiB
Python
509 lines
18 KiB
Python
import os
|
|
import sys
|
|
import socket
|
|
import subprocess
|
|
|
|
from gspylib.common.GaussLog import GaussLog
|
|
from gspylib.common.Common import DefaultValue
|
|
from base_utils.os.net_util import NetUtil
|
|
from base_utils.template.xml_constant import XmlConstant
|
|
|
|
|
|
def check_illegal_character(user_put):
|
|
for rac in DefaultValue.PATH_CHECK_LIST:
|
|
flag = user_put.find(rac)
|
|
if flag >= 0:
|
|
GaussLog.printMessage("%s %s" % (user_put, XmlConstant.RESOURCE_DATA.get('invalid_character')))
|
|
return False
|
|
return True
|
|
|
|
|
|
def check_port(port, action='', database_port=''):
|
|
if not str(port).isdigit():
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('invalid_num'))
|
|
return False
|
|
if int(port) > 65535 or int(port) < 1024:
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('invalid_port'))
|
|
return False
|
|
|
|
if action == 'cm':
|
|
if port == database_port:
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('cm_port_repeat'))
|
|
return False
|
|
if int(port) in range(int(database_port), int(database_port) + 11):
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('cm_port_beyond'))
|
|
return False
|
|
return True
|
|
|
|
|
|
def check_database_dir(database_dir):
|
|
# check illegal character
|
|
if not check_illegal_character(database_dir):
|
|
return False
|
|
|
|
# check isabs path
|
|
if not os.path.isabs(database_dir):
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('invalid_abs_dir'))
|
|
return False
|
|
|
|
database_dir = os.path.normpath(database_dir)
|
|
|
|
# check path exists
|
|
if os.path.exists(database_dir):
|
|
if not os.path.isdir(database_dir):
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('invalid_dir'))
|
|
return False
|
|
|
|
# check permission
|
|
if not os.access(database_dir, os.R_OK | os.W_OK):
|
|
GaussLog.printMessage("%s %s" % (XmlConstant.RESOURCE_DATA.get('not_permission'), database_dir))
|
|
return False
|
|
else:
|
|
cmd = "mkdir -p %s && rm -rf %s" % (database_dir, database_dir)
|
|
(status, output) = subprocess.getstatusoutput(cmd)
|
|
if status != 0:
|
|
GaussLog.printMessage("%s %s" % (database_dir, XmlConstant.RESOURCE_DATA.get('mkdir_dir_failed')))
|
|
return False
|
|
return True
|
|
|
|
|
|
def check_ip_hostname_valid(ip, hostname):
|
|
if not NetUtil.isIpValid(ip):
|
|
GaussLog.printMessage("%s %s" % (ip, XmlConstant.RESOURCE_DATA.get('invalid_ip')))
|
|
return False
|
|
if not check_illegal_character(ip):
|
|
return False
|
|
if not check_illegal_character(hostname):
|
|
return False
|
|
return True
|
|
|
|
|
|
def check_ip_node_count():
|
|
if len(XmlConstant.PRI_STANDBY_IP.keys()) != XmlConstant.PRI_STANDBY_COUNT:
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('ip_hostname_not_match'))
|
|
return False
|
|
return True
|
|
|
|
|
|
def get_ip_hostname(user_input):
|
|
pri_standby_ip = {}
|
|
ip_lists = []
|
|
hostname_lists = []
|
|
ip_hostname = user_input.split(";")
|
|
# ip_hostname remove empty elements
|
|
ip_hostname = [tmp for tmp in ip_hostname if tmp]
|
|
if (len(ip_hostname) != XmlConstant.PRI_STANDBY_COUNT):
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('ip_hostname_not_match'))
|
|
return False
|
|
for tmp in ip_hostname:
|
|
if len(tmp.strip().split()) != 2:
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('ip_hostname_not_match'))
|
|
return False
|
|
ip = str(tmp.strip().split()[0])
|
|
hostname = str(tmp.strip().split()[1])
|
|
if not check_ip_hostname_valid(ip, hostname):
|
|
return False
|
|
pri_standby_ip[ip] = hostname
|
|
ip_lists.append(ip)
|
|
hostname_lists.append(hostname)
|
|
|
|
XmlConstant.PRI_STANDBY_IP = pri_standby_ip
|
|
XmlConstant.IP_LISTS = ip_lists
|
|
XmlConstant.HOSTNAME_LISTS = hostname_lists
|
|
if not check_ip_node_count():
|
|
return False
|
|
return True
|
|
|
|
|
|
class TemplateStatus:
|
|
|
|
def work(self):
|
|
pass
|
|
|
|
|
|
def check_xml_isabs(xml_dir):
|
|
if os.path.isabs(xml_dir):
|
|
target_xml = xml_dir
|
|
else:
|
|
target_xml = os.path.join(XmlConstant.get_current_dir(), xml_dir)
|
|
return os.path.normpath(target_xml)
|
|
|
|
|
|
def check_xml_file_permission(target_xml):
|
|
if os.path.exists(target_xml):
|
|
if not os.path.isfile(target_xml):
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('invalid_xml_dir'))
|
|
return False
|
|
|
|
# check permission
|
|
if not os.access(target_xml, os.R_OK | os.W_OK):
|
|
GaussLog.printMessage("%s %s" % (XmlConstant.RESOURCE_DATA.get('not_permission'), target_xml))
|
|
return False
|
|
else:
|
|
cmd = "touch %s && rm -rf %s" % (target_xml, target_xml)
|
|
(status, output) = subprocess.getstatusoutput(cmd)
|
|
if status != 0:
|
|
GaussLog.printMessage("%s %s" % (target_xml, XmlConstant.RESOURCE_DATA.get('mkdir_file_failed')))
|
|
return False
|
|
return True
|
|
|
|
|
|
def check_xml_dir_repeat(target_xml):
|
|
cur_dir = XmlConstant.get_current_dir()
|
|
files = []
|
|
for tmp in XmlConstant.KEEP_FILES:
|
|
file = os.path.normpath(os.path.join(cur_dir, tmp))
|
|
files.append(file)
|
|
if target_xml in files:
|
|
GaussLog.printMessage("%s %s" % (XmlConstant.RESOURCE_DATA.get('invalid_xml_path'), target_xml))
|
|
return False
|
|
return True
|
|
|
|
|
|
def check_input_xml_info(xml_dir):
|
|
# check illegal
|
|
if not check_illegal_character(xml_dir):
|
|
return False
|
|
# get xml file's abs dir
|
|
XmlConstant.TARGET_XML = check_xml_isabs(xml_dir)
|
|
if not check_xml_file_permission(XmlConstant.TARGET_XML):
|
|
return False
|
|
if not check_xml_dir_repeat(XmlConstant.TARGET_XML):
|
|
return False
|
|
return True
|
|
|
|
|
|
class XmlStatus(TemplateStatus):
|
|
|
|
def work(self):
|
|
for i in range(XmlConstant.TRIES):
|
|
if i == 3:
|
|
sys.exit(0)
|
|
# 用户输入back回退到上个流程
|
|
user_input = input(XmlConstant.RESOURCE_DATA.get('input_xml_path')).strip()
|
|
if user_input.lower() in ('back', 'b'):
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('not_back'))
|
|
return XmlStatus()
|
|
if not user_input:
|
|
tmp_dir = os.path.join(XmlConstant.get_current_dir(), 'cluster.xml')
|
|
if os.path.exists(tmp_dir):
|
|
os.remove(tmp_dir)
|
|
XmlConstant.TARGET_XML = tmp_dir
|
|
if not check_input_xml_info(tmp_dir):
|
|
continue
|
|
return DatabaseInstallStatus()
|
|
if not check_input_xml_info(user_input):
|
|
continue
|
|
return DatabaseInstallStatus()
|
|
|
|
|
|
class DatabaseInstallStatus(TemplateStatus):
|
|
|
|
def work(self):
|
|
for i in range(XmlConstant.TRIES):
|
|
if i == 3:
|
|
sys.exit(0)
|
|
user_input = input(XmlConstant.RESOURCE_DATA.get('input_database_path')).strip()
|
|
if user_input.lower() in ('back', 'b'):
|
|
return XmlStatus()
|
|
if not user_input:
|
|
XmlConstant.OPENGAUSS_INSTALL_DIR = XmlConstant.DATABASE_INSTALL_DIR
|
|
if not check_database_dir(XmlConstant.OPENGAUSS_INSTALL_DIR):
|
|
continue
|
|
return DataPortStatus()
|
|
if not check_database_dir(user_input):
|
|
continue
|
|
XmlConstant.OPENGAUSS_INSTALL_DIR = os.path.normpath(user_input)
|
|
return DataPortStatus()
|
|
|
|
|
|
class DataPortStatus(TemplateStatus):
|
|
|
|
def work(self):
|
|
for i in range(XmlConstant.TRIES):
|
|
if i == 3:
|
|
sys.exit(0)
|
|
user_input = input(XmlConstant.RESOURCE_DATA.get('input_database_port')).strip()
|
|
if user_input.lower() in ('back', 'b'):
|
|
return DatabaseInstallStatus()
|
|
if not user_input:
|
|
XmlConstant.DATABASE_PORT = XmlConstant.DEFAULT_DATABASE_PORT
|
|
return PriStandbyStatus()
|
|
if not check_port(user_input):
|
|
continue
|
|
XmlConstant.DATABASE_PORT = user_input
|
|
return PriStandbyStatus()
|
|
|
|
|
|
class PriStandbyStatus(TemplateStatus):
|
|
|
|
def work(self):
|
|
XmlConstant.IS_PRI_STANDBY = False
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('choose_pri_standby'))
|
|
XmlConstant.select_option(XmlConstant.RESOURCE_DATA.get('deploy_pri_standby'),
|
|
XmlConstant.RESOURCE_DATA.get('deploy_single'))
|
|
|
|
for i in range(XmlConstant.TRIES):
|
|
if i == 3:
|
|
sys.exit(0)
|
|
user_input = input(XmlConstant.RESOURCE_DATA.get('input_pri_standby')).strip()
|
|
if user_input.lower() in ('back', 'b'):
|
|
return DataPortStatus()
|
|
if not user_input:
|
|
XmlConstant.IS_PRI_STANDBY = True
|
|
return DdesStatus()
|
|
if not user_input.isdigit():
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('invalid_num'))
|
|
continue
|
|
if user_input == "1":
|
|
XmlConstant.IS_PRI_STANDBY = True
|
|
return DdesStatus()
|
|
elif user_input == "2":
|
|
XmlConstant.IS_PRI_STANDBY = False
|
|
return PriStandbyCountStatus()
|
|
else:
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('invalid_character'))
|
|
continue
|
|
|
|
|
|
class DdesStatus(TemplateStatus):
|
|
|
|
def work(self):
|
|
XmlConstant.IS_DDES = False
|
|
XmlConstant.IS_CM = False
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('choose_ddes'))
|
|
XmlConstant.select_option(XmlConstant.RESOURCE_DATA.get('not_deploy'), XmlConstant.RESOURCE_DATA.get('deploy'))
|
|
|
|
for i in range(XmlConstant.TRIES):
|
|
if i == 3:
|
|
sys.exit(0)
|
|
user_input = input(XmlConstant.RESOURCE_DATA.get('input_ddes')).strip()
|
|
if user_input.lower() in ('back', 'b'):
|
|
return PriStandbyStatus()
|
|
if not user_input:
|
|
XmlConstant.IS_DDES = False
|
|
return CmStatus()
|
|
if not user_input.isdigit():
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('invalid_num'))
|
|
continue
|
|
if user_input == "1":
|
|
XmlConstant.IS_DDES = False
|
|
return CmStatus()
|
|
elif user_input == "2":
|
|
XmlConstant.IS_DDES = True
|
|
XmlConstant.IS_CM = True
|
|
return DdesDssHomeStatus()
|
|
else:
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('invalid_character'))
|
|
continue
|
|
|
|
|
|
class DdesDssHomeStatus(TemplateStatus):
|
|
|
|
def work(self):
|
|
for i in range(XmlConstant.TRIES):
|
|
if i == 3:
|
|
sys.exit(0)
|
|
user_input = input(XmlConstant.RESOURCE_DATA.get('intput_dss_home')).strip()
|
|
if user_input.lower() in ('back', 'b'):
|
|
return DdesStatus()
|
|
if not user_input:
|
|
XmlConstant.DDES_INFO['dss_home'] = XmlConstant.DSS_HOME_DIR
|
|
if not check_database_dir(XmlConstant.DDES_INFO['dss_home']):
|
|
continue
|
|
return DdesDssVgNameStatus()
|
|
if not check_database_dir(user_input):
|
|
continue
|
|
XmlConstant.DDES_INFO['dss_home'] = os.path.normpath(user_input)
|
|
return DdesDssVgNameStatus()
|
|
|
|
|
|
class DdesDssVgNameStatus(TemplateStatus):
|
|
|
|
def work(self):
|
|
for i in range(XmlConstant.TRIES):
|
|
if i == 3:
|
|
sys.exit(0)
|
|
user_input = input(XmlConstant.RESOURCE_DATA.get('intput_ss_dss_vg_name')).strip()
|
|
if user_input.lower() in ('back', 'b'):
|
|
return DdesDssHomeStatus()
|
|
if not user_input:
|
|
XmlConstant.DDES_INFO['ss_dss_vg_name'] = XmlConstant.DSS_VG_NAME_DIR
|
|
return DdesDssVgInfoStatus()
|
|
XmlConstant.DDES_INFO['ss_dss_vg_name'] = user_input
|
|
return DdesDssVgInfoStatus()
|
|
|
|
|
|
class DdesDssVgInfoStatus(TemplateStatus):
|
|
|
|
def work(self):
|
|
for i in range(XmlConstant.TRIES):
|
|
if i == 3:
|
|
sys.exit(0)
|
|
user_input = input(XmlConstant.RESOURCE_DATA.get('input_dss_vg_info')).strip()
|
|
if user_input.lower() in ('back', 'b'):
|
|
return DdesDssVgNameStatus()
|
|
if not user_input:
|
|
XmlConstant.DDES_INFO['dss_vg_info'] = XmlConstant.DSS_VG_INFO_DIR
|
|
return DdesVotingStatus()
|
|
XmlConstant.DDES_INFO['dss_vg_info'] = user_input
|
|
return DdesVotingStatus()
|
|
|
|
|
|
class DdesVotingStatus(TemplateStatus):
|
|
|
|
def work(self):
|
|
for i in range(XmlConstant.TRIES):
|
|
if i == 3:
|
|
sys.exit(0)
|
|
user_input = input(XmlConstant.RESOURCE_DATA.get('input_voting_disk_path')).strip()
|
|
if user_input.lower() in ('back', 'b'):
|
|
return DdesDssVgInfoStatus()
|
|
if not user_input:
|
|
XmlConstant.DDES_INFO['votingDiskPath'] = XmlConstant.VOTING_DIR
|
|
return DdesShareDiskStatus()
|
|
XmlConstant.DDES_INFO['votingDiskPath'] = user_input
|
|
return DdesShareDiskStatus()
|
|
|
|
|
|
class DdesShareDiskStatus(TemplateStatus):
|
|
|
|
def work(self):
|
|
for i in range(XmlConstant.TRIES):
|
|
if i == 3:
|
|
sys.exit(0)
|
|
user_input = input(XmlConstant.RESOURCE_DATA.get('input_share_disk_dir')).strip()
|
|
if user_input.lower() in ('back', 'b'):
|
|
return DdesVotingStatus()
|
|
if not user_input:
|
|
XmlConstant.DDES_INFO['shareDiskDir'] = XmlConstant.SHAREDISK_DIR
|
|
return CmServerPortStatus()
|
|
XmlConstant.DDES_INFO['shareDiskDir'] = user_input
|
|
return CmServerPortStatus()
|
|
|
|
|
|
class CmStatus(TemplateStatus):
|
|
|
|
def work(self):
|
|
XmlConstant.IS_CM = False
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('choose_cm'))
|
|
XmlConstant.select_option(XmlConstant.RESOURCE_DATA.get('deploy'), XmlConstant.RESOURCE_DATA.get('not_deploy'))
|
|
|
|
for i in range(XmlConstant.TRIES):
|
|
if i == 3:
|
|
sys.exit(0)
|
|
user_input = input(XmlConstant.RESOURCE_DATA.get('input_cm')).strip()
|
|
if user_input.lower() in ('back', 'b'):
|
|
if XmlConstant.IS_DDES:
|
|
return DdesShareDiskStatus()
|
|
else:
|
|
return DdesStatus()
|
|
if not user_input:
|
|
XmlConstant.IS_CM = True
|
|
return CmServerPortStatus()
|
|
if not user_input.isdigit():
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('invalid_num'))
|
|
continue
|
|
if user_input == "1":
|
|
XmlConstant.IS_CM = True
|
|
return CmServerPortStatus()
|
|
elif user_input == "2":
|
|
XmlConstant.IS_CM = False
|
|
return PriStandbyCountStatus()
|
|
else:
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('invalid_character'))
|
|
continue
|
|
|
|
|
|
class CmServerPortStatus(TemplateStatus):
|
|
|
|
def work(self):
|
|
for i in range(XmlConstant.TRIES):
|
|
if i == 3:
|
|
sys.exit(0)
|
|
user_input = input(XmlConstant.RESOURCE_DATA.get('cm_port')).strip()
|
|
if user_input.lower() in ('back', 'b'):
|
|
if XmlConstant.IS_DDES:
|
|
return DdesShareDiskStatus()
|
|
return CmStatus()
|
|
if not user_input:
|
|
XmlConstant.CM_SERVER_PORT = XmlConstant.DEFAULT_CM_SERVER_PORT
|
|
if not check_port(XmlConstant.CM_SERVER_PORT, 'cm', XmlConstant.DATABASE_PORT):
|
|
continue
|
|
return PriStandbyCountStatus()
|
|
if not check_port(user_input, 'cm', XmlConstant.DATABASE_PORT):
|
|
continue
|
|
XmlConstant.CM_SERVER_PORT = user_input
|
|
return PriStandbyCountStatus()
|
|
|
|
|
|
class PriStandbyCountStatus(TemplateStatus):
|
|
|
|
def work(self):
|
|
if not XmlConstant.IS_PRI_STANDBY:
|
|
XmlConstant.PRI_STANDBY_COUNT = 1
|
|
return PriStandbyIpStatus()
|
|
|
|
for i in range(XmlConstant.TRIES):
|
|
if i == 3:
|
|
sys.exit(0)
|
|
user_input = input(XmlConstant.RESOURCE_DATA.get('max_nodes')).strip()
|
|
if user_input.lower() in ('back', 'b'):
|
|
if XmlConstant.IS_DDES or XmlConstant.IS_CM:
|
|
return CmServerPortStatus()
|
|
if not XmlConstant.IS_CM:
|
|
return CmStatus()
|
|
return PriStandbyStatus()
|
|
if not user_input:
|
|
XmlConstant.PRI_STANDBY_COUNT = 3
|
|
return PriStandbyIpStatus()
|
|
if not user_input.isdigit():
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('invalid_num'))
|
|
continue
|
|
if 2 <= int(user_input) <= 9:
|
|
XmlConstant.PRI_STANDBY_COUNT = int(user_input)
|
|
return PriStandbyIpStatus()
|
|
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('invalid_character'))
|
|
continue
|
|
|
|
|
|
def get_localhost_name():
|
|
return socket.gethostname()
|
|
|
|
|
|
def get_localhost_ip():
|
|
addr_info = socket.getaddrinfo(get_localhost_name(), None)
|
|
for info in addr_info:
|
|
# 从地址信息中提取 IPv4 或 IPv6 地址
|
|
host_ip = info[NetUtil.ADDRESS_FAMILY_INDEX][NetUtil.IP_ADDRESS_INDEX]
|
|
return host_ip
|
|
|
|
|
|
class PriStandbyIpStatus(TemplateStatus):
|
|
|
|
def work(self):
|
|
ip_lists = []
|
|
hostname_lists = []
|
|
if not XmlConstant.IS_PRI_STANDBY:
|
|
hostname_lists.append(get_localhost_name())
|
|
ip_lists.append(get_localhost_ip())
|
|
XmlConstant.IP_LISTS = ip_lists
|
|
XmlConstant.HOSTNAME_LISTS = hostname_lists
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('finish'))
|
|
return
|
|
|
|
for i in range(XmlConstant.TRIES):
|
|
if i == 3:
|
|
sys.exit(0)
|
|
user_input = input(XmlConstant.RESOURCE_DATA.get('input_ip_hostname')).strip()
|
|
if user_input.lower() in ('back', 'b'):
|
|
return PriStandbyCountStatus()
|
|
if not user_input:
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('ip_hostname_empty'))
|
|
continue
|
|
if not get_ip_hostname(user_input):
|
|
continue
|
|
GaussLog.printMessage(XmlConstant.RESOURCE_DATA.get('finish'))
|
|
return
|