automation/tincrepo/main/mpp/lib/gpfilespace.py (272 lines of code) (raw):

#!/usr/bin/env python ''' gpfilespace wrapper for executing and creating filespace/tablespace ''' ############################################################################ import os import re import tinctest from gppylib.commands.base import Command from mpp.lib.PSQL import PSQL from mpp.lib.config import GPDBConfig from tinctest.lib import local_path, run_shell_command from tinctest.main import TINCException class GPfilespaceException(TINCException): pass class Gpfilespace(object): TRANSACTION_FILE = "TRANSACTION_FILES" TEMPORARY_FILE = "TEMPORARY_FILES" SUC_PATTERNS = [".*INFO.*Checking if filespace \w+ exists.*", ".*INFO.*Obtaining current filespace information.*", ".*INFO.*Obtaining current filespace entries used by.*", ".*INFO.*Moving \w+ filespace.* from \w+ to \w+.*", ".*INFO.*Starting Greenplum Database.*"] MASTER_FAIL_STARTUP_PATTERNS = [".*CRITICAL.*Failed to start Master instance in admin mode.*", ".*waiting for server to start......could not start server.*"] SEG_FAIL_STARTUP_PATTERNS = [".*INFO.*Master Started.*", ".*INFO.*Checking for filespace consistency.*", ".*ERROR.*\w+ entries are inconsistent.*", ".*ERROR.*Filespaces are inconsistent. Abort Greenplum Database start.*", ".*INFO.*Shutting down master.*"] FAIL_SHOW_PATTERNS = [".*ERROR.*Filespace is inconsistent.*"] DEFAULT_FS = "pg_system" DEFAULT_FS_OPTION = "default" TEMP_DIR = "pgsql_tmp" TRANS_DIR = ["pg_clog", "pg_distributedlog", "pg_distributedxidmap", "pg_multixact", "pg_subtrans", "pg_xlog"] LOCAL_TRAN_FILE = "gp_transaction_files_filespace" LOCAL_TEMP_FILE = "gp_temporary_files_filespace" TS_LIST = ['ts_a1','ts_a2','ts_a3','ts_b1','ts_b2','ts_b3','ts_c1','ts_c2','ts_c3'] def __init__(self): self.gphome = os.environ.get('GPHOME') self.config = GPDBConfig() def run(self, config=None, logdir=None, output=None, host=None, port=None, username=None, password=None, movetemp=None, movetrans=None, showtemp=None, showtrans=None, help=None): ''' @param config: Config File @param logdir: Log dirctory, default gpAdminLogs @param output: Output directory @param host: hostname @param port: port number @param username: username @param password: password @param movetempfilespace: move temporary filespace @param movetransfilespace: move transaction filespace @param showtempfilespace: show temporary filespace @param showtransfilespace: show transaction filespace @param help: show help @return result object (result.rc, result.stdout, result.stderr) ''' cmd_opt = "" if config: cmd_opt += " -c %s " % config if logdir: cmd_opt += " -l %s " % logdir if output: cmd_opt += " -o %s " % logdir if host: cmd_opt += " -h %s " % host if port: cmd_opt += " -p %s " % port if username: cmd_opt += " -U %s " % username if password: cmd_opt += " -W %s " % password if movetemp: cmd_opt += " --movetempfilespace %s " % movetemp if movetrans: cmd_opt += " --movetransfilespace %s " % movetrans if showtemp: cmd_opt += " --showtempfilespace " if showtrans: cmd_opt += " --showtransfilespace " if help: cmd_opt = " -? " filespace_cmd = '%s/bin/gpfilespace %s' % (self.gphome, cmd_opt) # @todo: We shouldn't source greenplum_path.sh cmd = Command(name='Gpfilespace command', cmdStr="source %s/greenplum_path.sh;%s" % (self.gphome,filespace_cmd)) tinctest.logger.info(" %s" % cmd) cmd.run(validateAfter=True) result = cmd.get_results() if result.rc != 0: raise GPfilespaceException('Issue with Gpfilespace Command') return result def move_tempdefault(self): ''' gpfilespace --movetempfilespace default ''' self.run(movetemp="default") if not self.get_filespace_location(self.TEMPORARY_FILE) == self.DEFAULT_FS: raise GPfilespaceException("Issue with gpfilespace") def move_transdefault(self): ''' gpfilespace --movetransfilespace default ''' self.run(movetrans="default") if not self.get_filespace_location(self.TRANSACTION_FILE) == self.DEFAULT_FS: raise GPfilespaceException("Issue with gpfilespace") def showtempfiles(self): ''' gpfilespace --showtempfilespace @return output and return code ''' return self.run(showtemp=True) def showtransfiles(self): ''' gpfilespace --showtransfilespace @return output and return code ''' return self.run(showtrans=True) def get_filespace_location(self, ftype=TEMPORARY_FILE): ''' Get the filespace name for temporary location @return filespace location ''' if ftype == "TEMPORARY_FILES": out = self.showtempfiles() else: out = self.showtransfiles() for line in out.stdout.splitlines(): if re.search(".*Current Filespace.*%s.*" % ftype, line): return line.split(" ")[-1].strip() def get_filespace_directory(self, ftype=TEMPORARY_FILE): ''' Get the filespace directory location @return dir_fs: array of filespace directories ''' dir_fs = [] if ftype == "TEMPORARY_FILES": out = self.showtempfiles() else: out = self.showtransfiles() for line in out.stdout.splitlines(): if re.search(".*INFO.*-\d+.*", line): dir_fs.append(line.split(" ")[-1].strip()) return dir_fs def get_hosts_for_filespace(self, location): ''' Get the hostname for the filespace location @param location: location of filespace @return filespace: dictionary of hostname, location, content, role, preferred_role @note: This return multiple rows for the same filespace location ''' cmd = "select hostname, fselocation, content, role, preferred_role from gp_segment_configuration, pg_filespace_entry where fselocation='%s' and dbid=fsedbid" % (location) fs_out = PSQL.run_sql_command(cmd, flags = '-t -q', dbname='postgres') filespace = [] if len(fs_out.strip()) > 0: for line in fs_out.splitlines(): if len(line.strip())>0: data = {} (hostname, location, content, role, preferred_role) = line.split('|') data['hostname'], data['location'], data['content'], data['role'], data['preferred_role'] = hostname.strip(), location.strip(), content.strip(), role.strip(), preferred_role.strip() filespace.append(data) return filespace else: raise GPfilespaceException("Issue with getting host for filespace") def movetransfiles_localfilespace(self, filespace): ''' Helper function to move Transaction Files to local filespace ''' cur_filespace = self.get_filespace_location(self.TRANSACTION_FILE) if cur_filespace != filespace: # Do not move again out = self.run(movetrans=filespace) # Verify after moving, if it has been moved cur_filespace = self.get_filespace_location(self.TRANSACTION_FILE) if not (cur_filespace==filespace): raise GPfilespaceException("Issue with moving transaction filespace") def movetempfiles_localfilespace(self, filespace): ''' Helper function to move Temporary Files to local filespace ''' cur_filespace = self.get_filespace_location(self.TEMPORARY_FILE) if cur_filespace != filespace: # Do not move again out = self.run(movetemp=filespace) # Verify after moving, if it has been moved cur_filespace = self.get_filespace_location(self.TEMPORARY_FILE) if not (cur_filespace==filespace): raise GPfilespaceException("Issue with moving temporary filespace") def exists(self, filespace): ''' Check whether filespace exist in catalog @param filespace: filespace name @return True or False ''' fs_out = PSQL.run_sql_command("select count(*) from pg_filespace where fsname='%s'" % filespace, flags = '-t -q', dbname='postgres') if int(fs_out.strip()) > 0: return True return False def create_filespace(self, filespace): ''' @param filespace: Filespace Name ''' if self.exists(filespace) is True: tinctest.logger.info('Filespace %s exists' % filespace) return file1 = local_path(filespace) f1 = open(file1+".fs.config","w") f1.write('filespace:%s\n' % filespace) for record in self.config.record: if record.role: fileloc = '%s/%s/primary' % (os.path.split(record.datadir)[0], filespace) else: fileloc = '%s/%s/mirror' % (os.path.split(record.datadir)[0], filespace) # @todo: use a common utility to create/delete remotely cmd = "gpssh -h %s -e 'rm -rf %s; mkdir -p %s'" % (record.hostname, fileloc, fileloc) run_shell_command(cmd) f1.write("%s:%s:%s/%s\n" % (record.hostname, record.dbid, fileloc, os.path.split(record.datadir)[1])) f1.close() result = self.run(config=f1.name) if result.rc != 0: raise GPfilespaceException('"gpfilespace creation filespace FAILED". Output = %s ' % out) def drop_filespace(self, filespace): ''' @param filespace : filespace name @description: Drop the filespace @note : This assumes that all objects created in this filespace are deleted by the test ''' sql_cmd = 'Drop Filespace %s;' % filespace out = PSQL.run_sql_command(sql_cmd, flags = '-t -q', dbname='postgres') tinctest.logger.info('out %s' % out) if 'ERROR' in out : tinctest.logger.info('The filespace could not be deleted. Could be that its not empty') return False return True class GPDBGpfilespace(object): def __init__(self): self.gphome = os.environ.get('GPHOME') self.config = GPDBConfig() def exists(self, filespace): ''' Check whether filespace exist in catalog @param filespace: filespace name @return True or False ''' fs_out = PSQL.run_sql_command("select count(*) from pg_filespace where fsname='%s'" % filespace, flags = '-t -q', dbname='postgres') if int(fs_out.strip()) > 0: return True return False def create_filespace(self, filespace): ''' @param filespace: Filespace Name ''' if self.exists(filespace) is True: tinctest.logger.info('Filespace %s exists' % filespace) return file1 = local_path(filespace) f1 = open(file1+".fs.config","w") f1.write('filespace:%s\n' % filespace) f1.write('fsysname:hdfs\n') fsrep = PSQL.run_sql_command("select fsrep from pg_filespace where fsname='dfs_system';", flags = '-t -q', dbname='postgres') f1.write('fsreplica:%s\n' % fsrep.strip()) dfs_loc_cmd = "SELECT substring(fselocation from length('hdfs:// ') for (position('/' in substring(fselocation from length('hdfs:// ')))-1)::int) FROM pg_filespace pgfs, pg_filespace_entry pgfse WHERE pgfs.fsname = 'dfs_system' AND fsedbid = 2 AND pgfse.fsefsoid=pgfs.oid ;" dfs_loc = PSQL.run_sql_command(dfs_loc_cmd,flags = '-t -q', dbname='postgres') for record in self.config.record: if record.content == -1: fileloc = '%s/hdfs_%s' % (os.path.split(record.datadir)[0], filespace) f1.write("%s:%s:%s/%s\n" % (record.hostname, record.dbid, fileloc, os.path.split(record.datadir)[1])) cmd = "gpssh -h %s -e 'rm -rf %s; mkdir -p %s'" % (record.hostname, fileloc, fileloc) run_shell_command(cmd) else: f1.write("%s:%s:[%s/%s/%s]\n" % (record.hostname, record.dbid, dfs_loc.strip(), filespace, os.path.split(record.datadir)[1])) f1.close() filespace_cmd = '%s/bin/gpfilespace -c %s' % (self.gphome, f1.name) cmd = Command(name='Gpfilespace command', cmdStr="%s" % (filespace_cmd)) tinctest.logger.info(" %s" % cmd) cmd.run(validateAfter=True) result = cmd.get_results() if result.rc != 0: raise GPfilespaceException('"gpfilespace creation filespace FAILED". Output = %s ' % resutl.stdout)