Example #1
0
    def __init__(self, options, args):
        self.master_datadir = options.masterDataDirectory

        # TODO: AK: Program logic should not be dictating master, standby, and segment information
        # In other words, the fundamental Operations should have APIs that preclude the need for this.
        self.master_host = None
        self.standby_host = None
        self.segment_host_list = None

        self.query = options.query
        self.build = options.build
        self.install = options.install
        self.remove = options.remove
        self.update = options.update
        self.clean = options.clean
        self.migrate = options.migrate
        self.interactive = options.interactive
        self.filename = options.filename

        # only one of the following may be provided: --install, --remove, --update, --query, --build, --clean, --migrate
        count = sum([
            1 for opt in [
                'install', 'remove', 'update', 'query', 'build', 'clean',
                'migrate'
            ] if getattr(self, opt)
        ])
        if count != 1:
            raise ExceptionNoStackTraceNeeded(
                'Exactly one of the following must be provided: --install, --remove, -update, --query, --clean, --migrate'
            )

        if self.query:
            # gppkg -q can be supplemented with --info, --list, --all
            count = sum([
                1 for opt in ['info', 'list', 'all'] if options.__dict__[opt]
            ])
            if count > 1:
                raise ExceptionNoStackTraceNeeded(
                    'For --query, at most one of the following can be provided: --info, --list, --all'
                )
            # for all query options other than --all, a package path must be provided
            if not options.all and len(args) != 1:
                raise ExceptionNoStackTraceNeeded(
                    'A package must be specified for -q, -q --info, and -q --list.'
                )

            if options.info:
                self.query = (QueryPackage.INFO, args[0])
            elif options.list:
                self.query = (QueryPackage.LIST, args[0])
            elif options.all:
                self.query = (QueryPackage.ALL, None)
            else:
                self.query = (None, args[0])
        elif self.migrate:
            if len(args) != 2:
                raise ExceptionNoStackTraceNeeded(
                    'Invalid syntax, expecting "gppkg --migrate <from_gphome> <to_gphome>".'
                )
            self.migrate = (args[0], args[1])
Example #2
0
    def run(self):
        if self.build:
            if self.filename:
                BuildGppkg(self.build, self.filename).run()
            else:
                BuildGppkg(self.build, None).run()
            return

        #Check for RPM and Solaris OS
        if curr_platform == SUNOS:
            raise ExceptionNoStackTraceNeeded(
                'gppkg is not supported on Solaris')

        try:
            if platform.linux_distribution()[0] == 'Ubuntu':
                cmd = Command(name='Check for dpkg', cmdStr='dpkg --version')
                cmd.run(validateAfter=True)
            else:
                cmd = Command(name='Check for rpm', cmdStr='rpm --version')
                cmd.run(validateAfter=True)
                results = cmd.get_results().stdout.strip()
                rpm_version_string = results.split(' ')[-1]

                if not rpm_version_string.startswith('4.'):
                    raise ExceptionNoStackTraceNeeded(
                        'gppkg requires rpm version 4.x')

        except ExecutionError, ex:
            results = ex.cmd.get_results().stderr.strip()
            if len(results) != 0 and 'not found' in results:
                raise ExceptionNoStackTraceNeeded(
                    'gppkg requires RPM to be available in PATH')
Example #3
0
    def _getParsedRow(self, filename, lineno, line):
        groups = line.split()  # NOT line.split(' ') due to MPP-15675
        if len(groups) not in [1, 2]:
            msg = "line %d of file %s: expected 1 or 2 groups but found %d" % (lineno, filename, len(groups))
            raise ExceptionNoStackTraceNeeded(msg)
        parts = groups[0].split('|')
        if len(parts) != 3:
            msg = "line %d of file %s: expected 3 parts on failed segment group, obtained %d" % (
                lineno, filename, len(parts))
            raise ExceptionNoStackTraceNeeded(msg)
        address, port, datadir = parts
        check_values(lineno, address=address, port=port, datadir=datadir)
        row = {
            'failedAddress': address,
            'failedPort': port,
            'failedDataDirectory': datadir,
            'lineno': lineno
        }
        if len(groups) == 2:
            parts2 = groups[1].split('|')
            if len(parts2) != 3:
                msg = "line %d of file %s: expected 3 parts on new segment group, obtained %d" % (
                    lineno, filename, len(parts2))
                raise ExceptionNoStackTraceNeeded(msg)
            address2, port2, datadir2 = parts2
            check_values(lineno, address=address2, port=port2, datadir=datadir2)
            row.update({
                'newAddress': address2,
                'newPort': port2,
                'newDataDirectory': datadir2
            })

        return row
Example #4
0
    def execute(self):
        """ TODO: Improve with grouping by host and ParallelOperation dispatch. """
        gparray = GpArray.initFromCatalog(dbconn.DbURL(port=self.master_port),
                                          utility=True)
        primaries = [
            seg for seg in gparray.getDbList()
            if seg.isSegmentPrimary(current_role=True)
        ]
        dump_count = 0
        for seg in primaries:
            if seg.isSegmentDown():
                """ Why must every Segment function have the word Segment in it ?! """
                raise ExceptionNoStackTraceNeeded(
                    "Host %s dir %s dbid %d marked as invalid" %
                    (seg.getSegmentHostName(), seg.getSegmentDataDirectory(),
                     seg.getSegmentDbId()))

            path = os.path.join(seg.getSegmentDataDirectory(), DUMP_DIR,
                                self.restore_timestamp[0:8])
            host = seg.getSegmentHostName()
            path = os.path.join(
                path, "%s0_%d_%s" %
                (DBDUMP_PREFIX, seg.getSegmentDbId(), self.restore_timestamp))
            if self.compress:
                path += ".gz"
            exists = CheckRemoteFile(path, host).run()
            if not exists:
                raise ExceptionNoStackTraceNeeded(
                    "No dump file on %s at %s" %
                    (seg.getSegmentHostName(), path))
Example #5
0
def parse_gpmovemirrors_line(filename, lineno, line):
    """
    Parse a line in the gpmovemirrors configuration file other than the first.

    >>> line = "[::1]:40001:/Users/ctaylor/data/m2/gpseg1 [::2]:40101:/Users/ctaylor/data/m2/gpseg1"
    >>> rows = parse_gpmovemirrors_line('file', 1, line)
    >>> rows["oldAddress"], rows["newAddress"]
    ('::1', '::2')

    """
    groups = len(line.split())
    if groups != 2:
        msg = "need two groups of fields delimited by a space for old and new mirror, not %d" % groups
        raise ExceptionNoStackTraceNeeded("%s:%s:%s LINE >>%s\n%s" % (filename, lineno, caller(), line, msg))
    rows = {}
    p = LineParser(caller(), filename, lineno, line)
    p.handle_field('[oldAddress]', rows) # [oldAddress] indicates possible IPv6 address
    p.handle_field('oldPort', rows)
    p.handle_field('oldDataDirectory', rows, delimiter=' ', stripchars=' \t') # MPP-15675 note stripchars here and next line
    p.handle_field('[newAddress]', rows, stripchars=' \t') # [newAddress] indicates possible IPv6 address
    p.handle_field('newPort', rows)
    p.handle_field('newDataDirectory', rows)
    if p.rest is not None:
        msg = "unexpected characters after mirror fields >>%s" % p.rest
        raise ExceptionNoStackTraceNeeded("%s:%s:%s LINE >>%s\n%s" % (filename, lineno, caller(), line, msg))
    return rows
Example #6
0
    def _parseConfigFile(config_file):
        """
        Parse the config file
        :param config_file:
        :return: List of dictionaries with each dictionary containing the failed and failover information??
        """
        rows = []
        with open(config_file) as f:
            for lineno, line in line_reader(f):

                groups = line.split()  # NOT line.split(' ') due to MPP-15675
                if len(groups) not in [1, 2]:
                    msg = "line %d of file %s: expected 1 or 2 groups but found %d" % (
                        lineno, config_file, len(groups))
                    raise ExceptionNoStackTraceNeeded(msg)
                parts = groups[0].split('|')
                if len(parts) != 3:
                    msg = "line %d of file %s: expected 3 parts on failed segment group, obtained %d" % (
                        lineno, config_file, len(parts))
                    raise ExceptionNoStackTraceNeeded(msg)
                address, port, datadir = parts
                check_values(lineno,
                             address=address,
                             port=port,
                             datadir=datadir)
                datadir = normalizeAndValidateInputPath(
                    datadir, f.name, lineno)

                row = {
                    'failedAddress': address,
                    'failedPort': port,
                    'failedDataDirectory': datadir,
                    'lineno': lineno
                }
                if len(groups) == 2:
                    parts2 = groups[1].split('|')
                    if len(parts2) != 3:
                        msg = "line %d of file %s: expected 3 parts on new segment group, obtained %d" % (
                            lineno, config_file, len(parts2))
                        raise ExceptionNoStackTraceNeeded(msg)
                    address2, port2, datadir2 = parts2
                    check_values(lineno,
                                 address=address2,
                                 port=port2,
                                 datadir=datadir2)
                    datadir2 = normalizeAndValidateInputPath(
                        datadir2, f.name, lineno)

                    row.update({
                        'newAddress': address2,
                        'newPort': port2,
                        'newDataDirectory': datadir2
                    })

                rows.append(row)

        RecoveryTripletsUserConfigFile._validate(rows)

        return rows
Example #7
0
    def __init__(self, options, args):
        self.coordinator_datadir = options.coordinatorDataDirectory

        # TODO: AK: Program logic should not be dictating coordinator, standby, and segment information
        # In other words, the fundamental Operations should have APIs that preclude the need for this.
        self.coordinator_host = None
        self.standby_host = None
        self.segment_host_list = None

        self.query = options.query
        self.build = options.build
        self.install = options.install
        self.remove = options.remove
        self.update = options.update
        self.clean = options.clean
        self.migrate = options.migrate
        self.interactive = options.interactive
        self.filename = options.filename

        # only one of the following may be provided: --install, --remove, --update, --query, --build, --clean, --migrate
        count = sum([1 for opt in ['install', 'remove', 'update', 'query', 'build', 'clean', 'migrate'] if getattr(self, opt)])
        if count != 1:
            raise ExceptionNoStackTraceNeeded('Exactly one of the following must be provided: --install, --remove, -update, --query, --clean, --migrate')

        if self.query:
            # gppkg -q can be supplemented with --info, --list, --all
            count = sum([1 for opt in ['info', 'list', 'all'] if options.__dict__[opt]])
            if count > 1:
                raise ExceptionNoStackTraceNeeded('For --query, at most one of the following can be provided: --info, --list, --all')
            # for all query options other than --all, a package path must be provided
            if not options.all and len(args) != 1:
                raise ExceptionNoStackTraceNeeded('A package must be specified for -q, -q --info, and -q --list.')

            if options.info:
                self.query = (QueryPackage.INFO, args[0])
            elif options.list:
                self.query = (QueryPackage.LIST, args[0])
            elif options.all:
                self.query = (QueryPackage.ALL, None)
            else:
                self.query = (None, args[0])
        elif self.migrate:
            if len(args) != 2:
                raise ExceptionNoStackTraceNeeded('Invalid syntax, expecting "gppkg --migrate <from_gphome> <to_gphome>".')
            self.migrate = (args[0], args[1])

        # gppkg should check gpexpand status unless in build mode.
        #
        # Build mode does not use any information from the cluster and does not
        # affect its running status, in fact it does not require a cluster
        # exists at all.
        if not self.build:
            check_result, msg = gp.conflict_with_gpexpand("gppkg",
                                                          refuse_phase1=True,
                                                          refuse_phase2=False)
            if not check_result:
                raise ExceptionNoStackTraceNeeded(msg)
    def validate(failed, live, failover):

        checkNotNone("liveSegment", live)

        if failed is None and failover is None:
            raise Exception(
                "internal error: insufficient information to recover a mirror")

        if not live.isSegmentQE():
            raise ExceptionNoStackTraceNeeded(
                "Segment to recover from for content %s is not a correct segment "
                "(it is a coordinator or standby coordinator)" %
                live.getSegmentContentId())
        if not live.isSegmentPrimary(True):
            raise ExceptionNoStackTraceNeeded(
                "Segment to recover from for content %s is not a primary" %
                live.getSegmentContentId())
        if not live.isSegmentUp():
            raise ExceptionNoStackTraceNeeded(
                "Primary segment is not up for content %s" %
                live.getSegmentContentId())
        if live.unreachable:
            raise ExceptionNoStackTraceNeeded(
                "The recovery source segment %s (content %s) is unreachable." %
                (live.getSegmentHostName(), live.getSegmentContentId()))

        if failed is not None:
            if failed.getSegmentContentId() != live.getSegmentContentId():
                raise ExceptionNoStackTraceNeeded(
                    "The primary is not of the same content as the failed mirror.  Primary content %d, "
                    "mirror content %d" %
                    (live.getSegmentContentId(), failed.getSegmentContentId()))
            if failed.getSegmentDbId() == live.getSegmentDbId():
                raise ExceptionNoStackTraceNeeded(
                    "For content %d, the dbid values are the same.  "
                    "A segment may not be recovered from itself" %
                    live.getSegmentDbId())

        if failover is not None:
            if failover.getSegmentContentId() != live.getSegmentContentId():
                raise ExceptionNoStackTraceNeeded(
                    "The primary is not of the same content as the mirror.  Primary content %d, "
                    "mirror content %d" % (live.getSegmentContentId(),
                                           failover.getSegmentContentId()))
            if failover.getSegmentDbId() == live.getSegmentDbId():
                raise ExceptionNoStackTraceNeeded(
                    "For content %d, the dbid values are the same.  "
                    "A segment may not be built from itself" %
                    live.getSegmentDbId())
            if failover.unreachable:
                raise ExceptionNoStackTraceNeeded(
                    "The recovery target segment %s (content %s) is unreachable."
                    % (failover.getSegmentHostName(),
                       failover.getSegmentContentId()))

        if failed is not None and failover is not None:
            # for now, we require the code to have produced this -- even when moving the segment to another
            #  location, we preserve the directory
            assert failed.getSegmentDbId() == failover.getSegmentDbId()
Example #9
0
    def validate_options(self):
        if self.table_file is None:
            raise ExceptionNoStackTraceNeeded('Please specify table file')

        if not os.path.exists(self.table_file):
            raise ExceptionNoStackTraceNeeded('Unable to find table file "{table_file}"'.format(table_file=self.table_file))

        if self.database is None:
            raise ExceptionNoStackTraceNeeded('Please specify the correct database')

        if self.port is None:
            if 'PGPORT' not in os.environ:
                raise ExceptionNoStackTraceNeeded('Please specify PGPORT using -p option or set PGPORT in the environment')
            self.port = os.environ['PGPORT']
Example #10
0
    def _process_createdb(self, restore_timestamp, restore_db, master_datadir, master_port): 
        conn = None
        try:
            dburl = dbconn.DbURL(port=master_port)
            conn = dbconn.connect(dburl)
            count = execSQLForSingleton(conn, "select count(*) from pg_database where datname='%s';" % restore_db)

            if count == 1:
                logger.info("Dropping database %s" % restore_db)
                try:
                    cursor=conn.cursor()
                    cursor.execute("commit")                          # hack to move drop stmt out of implied transaction
                    cursor.execute("drop database %s" % restore_db)
                    cursor.close()
                except Exception, e:
                    logger.exception("Could not create database %s" % restore_db)
                    raise ExceptionNoStackTraceNeeded('Failed to drop database %s' % restore_db)
                else:
                    logger.info('Dropped database %s' % restore_db)
        finally:
            if conn is not None:
                conn.close()

        createdb_file = os.path.join(master_datadir, DUMP_DIR, restore_timestamp[0:8], "%s%s" % (CREATEDB_PREFIX, restore_timestamp))
        logger.info('Invoking %s' % createdb_file)
        Psql('Invoking schema dump', filename=createdb_file).run(validateAfter=True)
Example #11
0
    def execute(self): 
        gparray = GpArray.initFromCatalog(dbconn.DbURL(port=self.master_port), utility=True)
        from_host, from_path = self.host, self.path
        logger.info("Commencing remote database dump file recovery process, please wait...")
        segs = [seg for seg in gparray.getDbList() if seg.isSegmentPrimary(current_role=True) or seg.isSegmentMaster()]
        pool = WorkerPool(numWorkers = min(len(segs), self.batch_default))
        for seg in segs:
            if seg.isSegmentMaster():
                file = '%s%s' % (MASTER_DBDUMP_PREFIX, self.restore_timestamp)
            else:
                file = '%s0_%d_%s' % (DBDUMP_PREFIX, seg.getSegmentDbId(), self.restore_timestamp)
            if self.compress:
                file += '.gz'

            to_host = seg.getSegmentHostName()
            to_path = os.path.join(seg.getSegmentDataDirectory(), DUMP_DIR, self.restore_timestamp[0:8])
            if not CheckRemoteDir(to_path, to_host).run():
                logger.info('Creating directory %s on %s' % (to_path, to_host))
                try:
                    MakeRemoteDir(to_path, to_host).run()
                except OSError, e:
                    raise ExceptionNoStackTraceNeeded("Failed to create directory %s on %s" % (to_path, to_host))
   
            logger.info("Commencing remote copy from %s to %s:%s" % (from_host, to_host, to_path))
            pool.addCommand(Scp('Copying dump for seg %d' % seg.getSegmentDbId(),
                            srcFile=os.path.join(from_path, file),
                            dstFile=os.path.join(to_path, file),
                            srcHost=from_host,
                            dstHost=to_host))
Example #12
0
def parse_gpexpand_segment_line(filename, lineno, line):
    """
    Parse a line of the gpexpand configuration file.

    >>> parse_gpexpand_segment_line('file', 1, "localhost:[::1]:40001:/Users/ctaylor/data/p2/gpseg1:4:1:p")
    ('localhost', '::1', '40001', '/Users/ctaylor/data/p2/gpseg1', '4', '1', 'p', None)
    >>> parse_gpexpand_segment_line('file', 1, "localhost:[::1]:40001:/Users/ctaylor/data/p2/gpseg1:4:1:p:41001")
    ('localhost', '::1', '40001', '/Users/ctaylor/data/p2/gpseg1', '4', '1', 'p', '41001')
    """
    p = LineParser(caller(), filename, lineno, line)
    hostname = p.handle_field(
        '[host]')  # [host] indicates possible IPv6 address
    address = p.handle_field(
        '[address]')  # [address] indicates possible IPv6 address
    port = p.handle_field('port')
    datadir = p.handle_field('datadir')
    dbid = p.handle_field('dbid')
    contentId = p.handle_field('contentId')
    role = p.handle_field('role')
    replicationPort = None
    if p.rest is not None:
        replicationPort = p.handle_field('replicationPort')
        if p.rest is not None:
            msg = "unexpected characters after replicationPort >>%s" % p.rest
            raise ExceptionNoStackTraceNeeded(
                "%s:%s:%s LINE >>%s\n%s" %
                (filename, lineno, caller(), line, msg))
    return hostname, address, port, datadir, dbid, contentId, role, replicationPort
Example #13
0
 def execute(self):
     if ((len(self.include_dump_tables) > 0 or
          (self.include_dump_tables_file is not None))
             and (len(self.exclude_dump_tables) > 0 or
                  (self.exclude_dump_tables_file is not None))):
         raise ExceptionNoStackTraceNeeded(
             "Cannot use -t/--table-file and -T/--exclude-table-file options at same time"
         )
     elif len(self.include_dump_tables
              ) > 0 or self.include_dump_tables_file is not None:
         logger.info("Configuring for single-database, include-table dump")
         ValidateIncludeTargets(
             dump_database=self.dump_database,
             dump_schema=self.dump_schema,
             include_dump_tables=self.include_dump_tables,
             include_dump_tables_file=self.include_dump_tables_file,
             master_port=self.master_port).run()
     elif len(self.exclude_dump_tables
              ) > 0 or self.exclude_dump_tables_file is not None:
         logger.info("Configuring for single-database, exclude-table dump")
         self.exclude_dump_tables = ValidateExcludeTargets(
             dump_database=self.dump_database,
             dump_schema=self.dump_schema,
             exclude_dump_tables=self.exclude_dump_tables,
             exclude_dump_tables_file=self.exclude_dump_tables_file,
             master_port=self.master_port).run()
     else:
         logger.info("Configuring for single database dump")
     return self.exclude_dump_tables
Example #14
0
def parse_gprecoverseg_line(filename, lineno, line):
    """
    Parse a line in the gprecoverseg configuration file other than the first.

    >>> line = "[::1]:40001:/Users/ctaylor/data/m2/gpseg1"
    >>> fixed, flex = parse_gprecoverseg_line('file', 1, line)
    >>> fixed["failedAddress"], fixed["failedPort"], fixed["failedDataDirectory"]
    ('::1', '40001', '/Users/ctaylor/data/m2/gpseg1')
    """

    groups = len(line.split())
    if groups not in [1, 2]:
        msg = "only one or two groups of fields delimited by a space, not %d" % groups
        raise ExceptionNoStackTraceNeeded("%s:%s:%s LINE >>%s\n%s" % (filename, lineno, caller(), line, msg))
    fixed = {}
    flexible = {}
    p = LineParser(caller(), filename, lineno, line)
    p.handle_field('[failedAddress]', fixed) # [failedAddress] indicates possible IPv6 address
    p.handle_field('failedPort', fixed)
    if groups == 1:
        p.handle_field('failedDataDirectory', fixed)
    else:
        p.handle_field('failedDataDirectory', fixed, delimiter=' ', stripchars=' \t') # MPP-15675 note stripchars here and next line
        p.handle_field('[newAddress]', fixed, stripchars=' \t') # [newAddress] indicates possible IPv6 address
        p.handle_field('newPort', fixed)
        p.handle_field('newDataDirectory', fixed)
    return fixed, flexible
Example #15
0
    def execute(self): 
        existing_tables = []
        table_counts = []
        conn = None
        try:
            dburl = dbconn.DbURL(port=self.master_port, dbname=self.restore_db)
            conn = dbconn.connect(dburl)
            for restore_table in self.restore_tables:
                if '.' not in restore_table:
                    logger.warn("No schema name supplied for %s, removing from list of tables to restore" % restore_table)
                    continue

                schema, table = restore_table.split('.')
                count = execSQLForSingleton(conn, "select count(*) from pg_class, pg_namespace where pg_class.relname = '%s' and pg_class.relnamespace = pg_namespace.oid and pg_namespace.nspname = '%s'" % (table, schema))
                if count == 0:
                    logger.warn("Table %s does not exist in database %s, removing from list of tables to restore" % (table, self.restore_db))
                    continue

                count = execSQLForSingleton(conn, "select count(*) from %s.%s" % (schema, table))
                if count > 0:
                    logger.warn('Table %s has %d records %s' % (restore_table, count, WARN_MARK))
                existing_tables.append(restore_table)
                table_counts.append((restore_table, count))
        finally:
            if conn is not None:
                conn.close()

        if len(existing_tables) == 0:
            raise ExceptionNoStackTraceNeeded("Have no tables to restore")
        logger.info("Have %d tables to restore, will continue" % len(existing_tables))

        return (existing_tables, table_counts)
Example #16
0
 def ensure_more_to_process(self, name):
     "Raise an exception if we've exhausted the input line"
     if self.rest is None:
         msg = "out of values (reading %s)" % name
         raise ExceptionNoStackTraceNeeded(
             "%s:%s:%s LINE >>%s\n%s" %
             (self.filename, self.lineno, self.caller, self.line, msg))
Example #17
0
 def ensure_starts_with(self, expected):
     "Returns true if line starts with expected value, or raise an exception otherwise"
     if not self.line.startswith(expected):
         msg = "does not start with %s" % expected
         raise ExceptionNoStackTraceNeeded(
             "%s:%s:%s LINE >>%s\n%s" %
             (self.filename, self.lineno, self.caller, self.line, msg))
     self.rest = self.rest[len(expected):]
Example #18
0
def check_values(lineno,
                 address=None,
                 port=None,
                 datadir=None,
                 content=None,
                 hostname=None,
                 dbid=None,
                 role=None):
    if address is not None and not is_valid_address(address):
        raise ExceptionNoStackTraceNeeded("Invalid address on line %d" %
                                          lineno)
    if port is not None and not is_valid_port(port):
        raise ExceptionNoStackTraceNeeded("Invalid port on line %d" % lineno)
    if datadir is not None and not is_valid_datadir(datadir):
        raise ExceptionNoStackTraceNeeded("Invalid directory on line %d" %
                                          lineno)
    if content is not None and not is_valid_contentid(content):
        raise ExceptionNoStackTraceNeeded("Invalid content ID on line %d" %
                                          lineno)
    if hostname is not None and not is_valid_address(hostname):
        raise ExceptionNoStackTraceNeeded("Invalid hostname on line %d" %
                                          lineno)
    if dbid is not None and not is_valid_dbid(dbid):
        raise ExceptionNoStackTraceNeeded("Invalid dbid on line %d" % lineno)
    if role is not None and not is_valid_role(role):
        raise ExceptionNoStackTraceNeeded("Invalid role on line %d" % lineno)
Example #19
0
def run_sql(conn, query):
    try:
        cursor = dbconn.execSQL(conn, query)
        res = cursor.fetchall()
        conn.commit()
        cursor.close()
    except Exception, db_err:
        raise ExceptionNoStackTraceNeeded("%s" %
                                          db_err.__str__())  # .split('\n')[0])
Example #20
0
    def execute(self):
        rebuild_excludes = []

        dump_tables = []
        for dump_table in self.exclude_dump_tables:
            dump_tables.append(dump_table)

        if self.exclude_dump_tables_file is not None:
            exclude_file = open(self.exclude_dump_tables_file, 'rU')
            if not exclude_file:
                raise ExceptionNoStackTraceNeeded("Can't open file %s" %
                                                  exclude_dump_tables_file)
            for line in exclude_file:
                dump_tables.append(line.strip('\n'))
            exclude_file.close()

        for dump_table in dump_tables:
            if '.' not in dump_table:
                raise ExceptionNoStackTraceNeeded(
                    "No schema name supplied for exclude table %s" %
                    dump_table)
            schema, table = dump_table.split('.')
            exists = CheckTableExists(schema=schema,
                                      table=table,
                                      database=self.dump_database,
                                      master_port=self.master_port).run()
            if exists:
                if self.dump_schema != schema:
                    logger.info("Adding table %s to exclude list" % dump_table)
                    rebuild_excludes.append(dump_table)
                else:
                    logger.warn(
                        "Schema dump request and exclude table %s not in that schema, ignoring"
                        % dump_table)
            else:
                logger.warn(
                    "Exclude table %s does not exist in %s database, ignoring"
                    % (dump_table, self.dump_database))
        if len(rebuild_excludes) == 0:
            logger.warn(
                "All exclude table names have been removed due to issues, see log file"
            )
        return self.exclude_dump_tables
Example #21
0
    def execute(self):
        if self.backup_dir is not None and self.report_dir is not None:
            master_dirs_to_check = [self.backup_dir, self.report_dir]
        elif self.backup_dir is not None:
            master_dirs_to_check = [self.backup_dir, self.master_datadir]
        elif self.report_dir is not None:
            master_dirs_to_check = [self.report_dir, self.master_datadir]
        else:
            master_dirs_to_check = [self.master_datadir]

        for dir in master_dirs_to_check:
            try:
                ValidateDumpDirs(dir).run()
            except DumpDirCreateFailed, e:
                raise ExceptionNoStackTraceNeeded(
                    'Could not create %s on master. Cannot continue.' % dir)
            except DumpDirNotWritable, e:
                raise ExceptionNoStackTraceNeeded(
                    'Could not write to %s on master. Cannot continue.' % dir)
Example #22
0
 def validate_table(self, schema_name, table_name):
     with dbconn.connect(dbconn.DbURL(dbname=self.database, port=self.port)) as conn:
         c = execSQLForSingleton(conn,
                                 """SELECT count(*)
                                    FROM pg_class, pg_namespace
                                    WHERE pg_namespace.nspname = '{schema}'
                                    AND pg_class.relname = '{table}'""".format(schema=schema_name, table=table_name))
         if not c:
             raise ExceptionNoStackTraceNeeded('Table {schema}.{table} does not exist'
                                               .format(schema=schema_name, table=table_name))
Example #23
0
 def execute(self):
     for fake_time in range(0, 1000000):
         fake_timestamp = "%s%06d" % (self.restore_timestamp[0:8], fake_time)
         path = os.path.join(self.master_datadir, DUMP_DIR, fake_timestamp[0:8], "%s%s" % (MASTER_DBDUMP_PREFIX, fake_timestamp))
         if self.compress:
             path += '.gz'
         if not CheckFile(path).run():
             break
     else:   
         raise ExceptionNoStackTraceNeeded("Could not construct table dump")
     return fake_timestamp
Example #24
0
 def validate_table_file(self):
     table_list = []
     with open(self.table_file) as fp:
         for line in fp:
             line = line.strip()
             try:
                 schema_name, table_name, sort_column_list = self.parse_line(line)
             except Exception as e:
                 raise ExceptionNoStackTraceNeeded("Line '{line}' is not formatted correctly: {ex}".format(line=line, ex=e))
             table_list.append((schema_name, table_name, sort_column_list))
     return table_list
Example #25
0
    def execute(self):
        path = os.path.join(self.master_datadir, DUMP_DIR, self.candidate_timestamp[0:8])
        createdb_file = os.path.join(path, "%s%s" % (CREATEDB_PREFIX, self.candidate_timestamp))
        if not CheckFile(createdb_file).run():
            raise ExceptionNoStackTraceNeeded("Dump file %s%s does not exist on Master" % (CREATEDB_PREFIX, self.candidate_timestamp))
        restore_db = GetDbName(createdb_file).run()

        compressed_file = os.path.join(path, "%s%s.gz" % (MASTER_DBDUMP_PREFIX, self.candidate_timestamp))
        compress = CheckFile(compressed_file).run()

        return (self.candidate_timestamp, restore_db, compress)
Example #26
0
    def run(self):
        if self.__options.parallelDegree < 1 or self.__options.parallelDegree > 64:
            raise ProgramArgumentValidationException(
                "Invalid parallelDegree provided with -B argument: %d" % self.__options.parallelDegree)

        self.__pool = WorkerPool(self.__options.parallelDegree)
        gpEnv = GpMasterEnvironment(self.__options.masterDataDirectory, True)

        # verify "where to recover" options
        optionCnt = 0
        if self.__options.newRecoverHosts is not None:
            optionCnt += 1
        if self.__options.recoveryConfigFile is not None:
            optionCnt += 1
        if self.__options.rebalanceSegments:
            optionCnt += 1
        if optionCnt > 1:
            raise ProgramArgumentValidationException("Only one of -i, -p, and -r may be specified")

        faultProberInterface.getFaultProber().initializeProber(gpEnv.getMasterPort())

        confProvider = configInterface.getConfigurationProvider().initializeProvider(gpEnv.getMasterPort())

        gpArray = confProvider.loadSystemConfig(useUtilityMode=False)

        num_workers = min(len(gpArray.get_hostlist()), self.__options.parallelDegree)
        hosts = set(gpArray.get_hostlist(includeMaster=False))
        unreachable_hosts = get_unreachable_segment_hosts(hosts, num_workers)
        for i, segmentPair in enumerate(gpArray.segmentPairs):
            if segmentPair.primaryDB.getSegmentHostName() in unreachable_hosts:
                logger.warning("Not recovering segment %d because %s is unreachable" % (segmentPair.primaryDB.dbid, segmentPair.primaryDB.getSegmentHostName()))
                gpArray.segmentPairs[i].primaryDB.unreachable = True

            if segmentPair.mirrorDB.getSegmentHostName() in unreachable_hosts:
                logger.warning("Not recovering segment %d because %s is unreachable" % (segmentPair.mirrorDB.dbid, segmentPair.mirrorDB.getSegmentHostName()))
                gpArray.segmentPairs[i].mirrorDB.unreachable = True

        if not gpArray.hasMirrors:
            raise ExceptionNoStackTraceNeeded(
                'GPDB Mirroring replication is not configured for this Greenplum Database instance.')

        # We have phys-rep/filerep mirrors.

        if self.__options.newRecoverHosts is not None:
            try:
                uniqueHosts = []
                for h in self.__options.newRecoverHosts.split(','):
                    if h.strip() not in uniqueHosts:
                        uniqueHosts.append(h.strip())
                self.__options.newRecoverHosts = uniqueHosts
            except Exception, ex:
                raise ProgramArgumentValidationException( \
                    "Invalid value for recover hosts: %s" % ex)
Example #27
0
 def execute(self):
     gparray = GpArray.initFromCatalog(dbconn.DbURL(port=self.master_port),
                                       utility=True)
     failed_segs = [
         seg for seg in gparray.getDbList()
         if seg.isSegmentPrimary(current_role=True) and seg.isSegmentDown()
     ]
     if len(failed_segs) != 0:
         logger.warn("Failed primary segment instances detected")
         failed_dbids = [seg.getSegmentDbid() for seg in failed_segs]
         raise ExceptionNoStackTraceNeeded(
             "Detected failed segment(s) with dbid=%s" %
             ",".join(failed_dbids))
Example #28
0
    def _validate(rows):
        """
        Runs checks for making sure all the rows are consistent
        :param rows:
        :return:
        """
        failed = {}
        new = {}
        for row in rows:
            address, port, datadir, lineno = \
                row['failedAddress'], row['failedPort'], row['failedDataDirectory'], row['lineno']

            if address + datadir in failed:
                msg = 'config file lines {0} and {1} conflict: ' \
                      'Cannot recover the same failed segment {2} and data directory {3} twice.' \
                    .format(failed[address+datadir], lineno, address, datadir)
                raise ExceptionNoStackTraceNeeded(msg)

            failed[address + datadir] = lineno

            if 'newAddress' not in row:
                if address + datadir in new:
                    msg = 'config file lines {0} and {1} conflict: ' \
                          'Cannot recover segment {2} with data directory {3} in place if it is used as a recovery segment.' \
                        .format(new[address+datadir], lineno, address, datadir)
                    raise ExceptionNoStackTraceNeeded(msg)

                continue

            address2, port2, datadir2 = row['newAddress'], row['newPort'], row[
                'newDataDirectory']

            if address2 + datadir2 in new:
                msg = 'config file lines {0} and {1} conflict: ' \
                      'Cannot recover to the same segment {2} and data directory {3} twice.' \
                    .format(new[address2+datadir2], lineno, address2, datadir2)
                raise ExceptionNoStackTraceNeeded(msg)

            new[address2 + datadir2] = lineno
Example #29
0
class ValidateDiskSpace(Operation):
    # TODO: this doesn't take into account that multiple segments may be dumping to the same logical disk.
    def __init__(self, free_space_percent, compress, dump_database,
                 include_dump_tables, batch_default, master_port):
        self.free_space_percent = free_space_percent
        self.compress = compress
        self.dump_database = dump_database
        self.include_dump_tables = include_dump_tables
        self.batch_default = batch_default
        self.master_port = master_port

    def execute(self):
        ValidateGpToolkit(database=self.dump_database,
                          master_port=self.master_port).run()

        operations = []
        gparray = GpArray.initFromCatalog(dbconn.DbURL(port=self.master_port),
                                          utility=True)
        segs = [
            seg for seg in gparray.getDbList()
            if seg.isSegmentPrimary(current_role=True)
        ]
        for seg in segs:
            operations.append(
                RemoteOperation(
                    ValidateSegDiskSpace(
                        free_space_percent=self.free_space_percent,
                        compress=self.compress,
                        dump_database=self.dump_database,
                        include_dump_tables=self.include_dump_tables,
                        datadir=seg.getSegmentDataDirectory(),
                        segport=seg.getSegmentPort()),
                    seg.getSegmentHostName()))

        ParallelOperation(operations, self.batch_default).run()

        success = 0
        for remote in operations:
            host = remote.host
            try:
                remote.get_ret()
            except NotEnoughDiskSpace, e:
                logger.error(
                    "%s has insufficient disk space. [Need: %dK, Free %dK]" %
                    (host, e.needed_space, e.free_space))
            else:
                success += 1
        if success < len(operations):
            raise ExceptionNoStackTraceNeeded(
                "Cannot continue. %d segment(s) failed disk space checks" %
                (len(operations) - success))
Example #30
0
 def execute(self):
     conn = None
     try:
         dburl = dbconn.DbURL(port=self.master_port)
         conn = dbconn.connect(dburl)
         count = execSQLForSingleton(
             conn, "select count(*) from pg_database where datname='%s';" %
             self.database)
         if count == 0:
             raise ExceptionNoStackTraceNeeded(
                 "Database %s does not exist." % self.database)
     finally:
         if conn is not None:
             conn.close()