Exemple #1
0
    def test_parse_dsn(self):
        from psycopg2 import ProgrammingError

        self.assertEqual(
            ext.parse_dsn('dbname=test user=tester password=secret'),
            dict(user='******', password='******', dbname='test'),
            "simple DSN parsed")

        self.assertRaises(ProgrammingError, ext.parse_dsn,
                          "dbname=test 2 user=tester password=secret")

        self.assertEqual(
            ext.parse_dsn("dbname='test 2' user=tester password=secret"),
            dict(user='******', password='******', dbname='test 2'),
            "DSN with quoting parsed")

        # Can't really use assertRaisesRegexp() here since we need to
        # make sure that secret is *not* exposed in the error messgage
        # (and it also requires python >= 2.7).
        raised = False
        try:
            # unterminated quote after dbname:
            ext.parse_dsn("dbname='test 2 user=tester password=secret")
        except ProgrammingError, e:
            raised = True
            self.assertTrue(str(e).find('secret') < 0,
                            "DSN was not exposed in error message")
Exemple #2
0
    def test_parse_dsn_uri(self):
        self.assertEqual(ext.parse_dsn('postgresql://*****:*****@/test'),
                         dict(user='******', password='******', dbname='test'),
                         "valid URI dsn parsed")

        raised = False
        try:
            # extra '=' after port value
            ext.parse_dsn(dsn='postgresql://*****:*****@/test?port=1111=x')
        except psycopg2.ProgrammingError, e:
            raised = True
            self.assertTrue(str(e).find('secret') < 0,
                            "URI was not exposed in error message")
Exemple #3
0
def run_osm2pgsql(options):
    """ Run osm2pgsql with the given options.
    """
    env = os.environ
    cmd = [
        options['osm2pgsql'], '--hstore', '--latlon', '--slim',
        '--with-forward-dependencies', 'false', '--log-progress', 'true',
        '--number-processes',
        str(options['threads']), '--cache',
        str(options['osm2pgsql_cache']), '--output', 'gazetteer', '--style',
        str(options['osm2pgsql_style'])
    ]
    if options['append']:
        cmd.append('--append')

    if options['flatnode_file']:
        cmd.extend(('--flat-nodes', options['flatnode_file']))

    dsn = parse_dsn(options['dsn'])
    if 'password' in dsn:
        env['PGPASSWORD'] = dsn['password']
    if 'dbname' in dsn:
        cmd.extend(('-d', dsn['dbname']))
    if 'user' in dsn:
        cmd.extend(('--username', dsn['user']))
    for param in ('host', 'port'):
        if param in dsn:
            cmd.extend(('--' + param, dsn[param]))

    cmd.append(str(options['import_file']))

    subprocess.run(cmd, cwd=options.get('cwd', '.'), env=env, check=True)
Exemple #4
0
 def test_unicode_value(self):
     snowman = u"\u2603"
     d = ext.parse_dsn('dbname=' + snowman)
     if sys.version_info[0] < 3:
         self.assertEqual(d['dbname'], snowman.encode('utf8'))
     else:
         self.assertEqual(d['dbname'], snowman)
Exemple #5
0
    def before_call(self, scope, cursor, connection, _args, _kwargs, response, exception):
        span = scope.span
        span.domain_name = constants.DomainNames['DB']
        span.class_name = constants.ClassNames['POSTGRESQL']

        dsn = parse_dsn(connection.dsn)
        
        query = ''
        operation = ''
        try:
            query = _args[0]
            if len(query) > 0:
                operation = query.split()[0].strip("\"").lower()
        except Exception:
            pass

        tags = {
            constants.SpanTags['OPERATION_TYPE']: PostgreIntegration._OPERATION_TO_TYPE.get(operation, ''),
            constants.SpanTags['DB_INSTANCE']: dsn.get('dbname', ''),
            constants.SpanTags['DB_HOST']: dsn.get('host', ''),
            constants.SpanTags['DB_TYPE']: "postgresql",
            constants.SpanTags['DB_STATEMENT_TYPE']: operation.upper(),
            constants.SpanTags['TRIGGER_CLASS_NAME']: "API",
            constants.SpanTags['TOPOLOGY_VERTEX']: True
        }

        if not ConfigProvider.get(config_names.THUNDRA_TRACE_INTEGRATIONS_RDB_STATEMENT_MASK):
            tags[constants.DBTags['DB_STATEMENT']] = query

        span.tags = tags
Exemple #6
0
    def from_options(
        cls,
        options: optparse.Values,
        dsn: str,
        hostname: str,
    ) -> "Host":
        """Build a host instance from options and dsn

        >>> options = optparse.Values(
        ...     defaults = {
        ...         "username": "******",
        ...         "host": "test",
        ...         "port": 5432,
        ...         "dbname": "pg",
        ... })
        >>> Host.from_options(options, "", "test")
        Host(hostname='test', user='******', host='test', port=5432, dbname='pg')
        >>> Host.from_options(options, "host=/tmp port=5432 user=toto dbname=pgbench", "test")
        Host(hostname='test', user='******', host='/tmp', port=5432, dbname='pgbench')
        >>> Host.from_options(options, "postgresql://toto@localhost:5432/bench", "test")
        Host(hostname='test', user='******', host='localhost', port=5432, dbname='bench')
        """

        pdsn = parse_dsn(dsn)

        return cls(
            hostname,
            pdsn.get("user", options.username),
            pdsn.get("host", options.host),
            int(pdsn.get("port", options.port)),
            pdsn.get("dbname", options.dbname),
        )
def get_database_password(dsn):
    if 'ENCRYPTED_DATABASE_PASSWORD' in os.environ:
        # boto returns decrypted as b'bytes' so decode to convert to password string
        return decrypt(os.environ['ENCRYPTED_DATABASE_PASSWORD']).decode()
    else:
        dsn_components = parse_dsn(dsn)
        return boto3.client('rds').generate_db_auth_token(dsn_components['host'], 5432, dsn_components['user'])
Exemple #8
0
        def wrapper(dsn, connection_factory=None, *args, **kwargs):
            config = parse_dsn(dsn)
            host = config.get("host")
            if host is None:
                host = kwargs.get("host")

            if host is None:
                # Host may be left out to use localhost or
                # possibly set using environment variables, nothing
                # we can do in either case.
                logger.error(
                    "'host' parameter is not present in call to psycopg2.connect, "
                    "DNS resolution might not work properly"
                )

                return fn(dsn, connection_factory, *args, **kwargs)

            if re.search(host_regex, host):
                logger.debug("Host %s matched SRV regex, resolving", host)
                host, port = resolve_srv_record(host, srv_resolver)
                config["host"] = host
                config["port"] = port

            dsn = make_dsn(**config)

            return fn(dsn, connection_factory, *args, **kwargs)
 def truncate_table(self):
     print('Truncating table %s ...' % self.target_table)
     conn = psycopg2.connect(**parse_dsn(self.db_config.db_connect_string))
     cur = conn.cursor()
     cur.execute('TRUNCATE TABLE %s' % self.target_table)
     conn.commit()
     cur.close()
     conn.close()
Exemple #10
0
 def test_unicode_value(self):
     from psycopg2.extensions import parse_dsn
     snowman = u"\u2603"
     d = parse_dsn('dbname=' + snowman)
     if sys.version_info[0] < 3:
         self.assertEqual(d['dbname'], snowman.encode('utf8'))
     else:
         self.assertEqual(d['dbname'], snowman)
Exemple #11
0
def get_database_settings(options):
    """Get the database setting to use.

    It will either read --database-uri from the options, or prompt for it.
    When prompting for it, it will default to the maas-test-db URI if the
    maas-test-db snap is installed and connected.

    """
    database_uri = options.database_uri
    test_db_socket = os.path.join(os.environ["SNAP_COMMON"], "test-db-socket")
    test_db_uri = f"postgres:///maasdb?host={test_db_socket}&user=maas"
    if database_uri is None:
        default_uri = None
        if os.path.exists(test_db_socket):
            default_uri = MAAS_TEST_DB_URI
        database_uri = required_prompt(
            "Database URI",
            default=default_uri,
            help_text=ARGUMENTS["database-uri"]["help"],
        )
        if not database_uri:
            database_uri = test_db_uri
    # parse_dsn gives very confusing error messages if you pass in
    # an invalid URI, so let's make sure the URI is of the form
    # postgres://... before calling parse_dsn.
    if database_uri != MAAS_TEST_DB_URI and not database_uri.startswith(
            "postgres://"):
        raise DatabaseSettingsError(
            f"Database URI needs to be either '{MAAS_TEST_DB_URI}' or "
            "start with 'postgres://'")
    if database_uri == MAAS_TEST_DB_URI:
        database_uri = test_db_uri
    try:
        parsed_dsn = parse_dsn(database_uri)
    except psycopg2.ProgrammingError as error:
        raise DatabaseSettingsError("Error parsing database URI: " +
                                    str(error).strip())
    unsupported_params = set(parsed_dsn.keys()).difference(
        ["user", "password", "host", "dbname", "port"])
    if unsupported_params:
        raise DatabaseSettingsError(
            "Error parsing database URI: Unsupported parameters: " +
            ", ".join(sorted(unsupported_params)))
    if "user" not in parsed_dsn:
        raise DatabaseSettingsError(f"No user found in URI: {database_uri}")
    if "host" not in parsed_dsn:
        parsed_dsn["host"] = "localhost"
    if "dbname" not in parsed_dsn:
        parsed_dsn["dbname"] = parsed_dsn["user"]
    database_settings = {
        "database_host": parsed_dsn["host"],
        "database_name": parsed_dsn["dbname"],
        "database_user": parsed_dsn.get("user", ""),
        "database_pass": parsed_dsn.get("password"),
    }
    if "port" in parsed_dsn:
        database_settings["database_port"] = int(parsed_dsn["port"])
    return database_settings
Exemple #12
0
    def __init__(self, dsn):
        parsed = ext.parse_dsn(dsn)

        # ca chain downloaded from https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL.html
        # or `wget https: //s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.pem`
        self.ssl_root_cert = parsed.get(
            "sslrootcert", "./certificates/rds-combined-ca-bundle.pem")
        self.logger = logging.getLogger(__name__ + "." +
                                        self.__class__.__name__)
Exemple #13
0
    def __init__(self, dsn, region):
        parsed = ext.parse_dsn(dsn)
        self.host = parsed.get("host", "localhost")
        self.port = parsed.get("port", "5432")
        self.user = parsed.get("user", "postgres")

        self.client = boto3.client('rds', region_name=region)
        self.logger = logging.getLogger(__name__ + "." +
                                        self.__class__.__name__)
def connect(db_url: str) -> Any:
    """
    Return a database connection based on the input database URL.

    @param db_url: The database URL.
    @returns: The connection.
    """
    db_params = parse_dsn(db_url)
    return psycopg2.connect(**db_params)
Exemple #15
0
    def __init__(self, connection, cursor, _args, _kwargs, start_time,
                 exception):
        """
        Initialize.
        :param connection: The SQL engine the event is using
        :param cursor: Cursor object used in the even
        :param args: args passed to called function
        :param kwargs: kwargs passed to called function
        :param start_time: Start timestamp (epoch)
        :param exception: Exception (if occurred)
        """

        super(DBAPIEvent, self).__init__(start_time)
        self.event_id = 'dbapi-{}'.format(str(uuid4()))

        # in case of pg instrumentation we extract data from the dsn property
        if hasattr(connection, 'dsn'):
            dsn = parse_dsn(connection.dsn)
            db_name = dsn.get('dbname', '')
            host = dsn.get('host', 'local')
            query = cursor.query
        else:
            query = _args[0]
            host = connection.extract_hostname
            db_name = connection.extract_dbname

        self.resource['name'] = db_name if db_name else host

        # NOTE: The operation might not be identified properly when
        # using 'WITH' clause
        splitted_query = query.split()
        if not splitted_query:
            print_debug('Cannot extract operation from query {}'.format(query))
            operation = ''
        else:
            operation = splitted_query[0].lower()
        self.resource['operation'] = operation
        # override event type with the specific DB type
        self.resource['type'] = database_connection_type(
            host, self.RESOURCE_TYPE)
        self.resource['metadata'] = {
            'Host': host,
            'Driver': connection.__class__.__module__.split('.')[0],
            'Table Name': self._extract_table_name(query, operation)
        }

        # for select we always want to save the query
        if ((operation == 'select') or (not trace_factory.metadata_only)):
            self.resource['metadata']['Query'] = query[:MAX_QUERY_SIZE]

        if exception is None:
            # Update response data
            self.resource['metadata']['Related Rows Count'] = int(
                cursor.rowcount)
        else:
            self.set_exception(exception, traceback.format_exc())
Exemple #16
0
    def load(self, features=None, nrows=None):
        self.categoricals = {}
        self.transforms_log = [[], [], [], []]

        import csv
        from io import StringIO

        path = self.options['data_path']
        if isinstance(path, StringIO):
            path.seek(0)
            self.df = pd.read_csv(path,
                                  encoding='utf-8',
                                  escapechar="\\",
                                  usecols=features,
                                  na_values=['?'],
                                  nrows=nrows)
            if self.options.get("targetFeature") in self.df.columns:
                self.dropna([self.options["targetFeature"]])
        else:
            if path.startswith("jdbc:"):
                import psycopg2
                from psycopg2.extensions import parse_dsn
                path = path.replace(
                    'sslfactory=org.postgresql.ssl.NonValidatingFactory&', '')
                ary = path.split('tablename')
                path = ary[0]
                tablename = ary[1]
                dataset_name = tablename

                self.dbconn_args = parse_dsn(path[5:])
                conn = psycopg2.connect(**self.dbconn_args)
                self.df = pd.read_sql("select * from %s" % tablename, con=conn)
            else:
                path, remote_path = self._check_remote_path()
                try:
                    self.df = self.load_from_file(path,
                                                  features=features,
                                                  nrows=nrows)
                except:
                    if remote_path:
                        logging.exception(
                            "Loading local file failed. Download it again...")
                        self.options['data_path'] = remote_path
                        path, remote_path = self._check_remote_path(
                            force_download=True)
                        self.df = self.load_from_file(path,
                                                      features=features,
                                                      nrows=nrows)
                    else:
                        raise

                self.dataset_name = os.path.basename(path)

            if self.options.get("targetFeature") in self.df.columns:
                self.dropna([self.options["targetFeature"]])
        return self
def parse_connect_string(connect_string):
    # According to:
    # https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING

    try:
        parsed_string = parse_dsn(connect_string)
    except Exception:
        raise Exception("Invalid connect string: " + connect_string)

    return parsed_string
Exemple #18
0
def _connection_args_from_dsn(dsn):
    params = parse_dsn(dsn)
    return [
        "-h",
        params["host"],
        "-U",
        params["user"],
        "-p",
        params["port"],
        "--no-password",
    ]
Exemple #19
0
def _set_attributes_from_cursor(span: trace.Span, vendor, cursor):
    """Attempt to set db connection attributes by introspecting the cursor."""
    if vendor == "postgres":
        # pylint: disable=import-outside-toplevel
        from psycopg2.extensions import parse_dsn

        if hasattr(cursor, "connection") and hasattr(cursor.connection, "dsn"):
            dsn = getattr(cursor.connection, "dsn", None)
            if dsn:
                data = parse_dsn(dsn)
                span.set_attribute(_DB, data.get("dbname"))
                span.set_attribute(_HOST, data.get("host"))
                span.set_attribute(_PORT, int(data.get("port")))
Exemple #20
0
 def args(self, **override):
     if self.url:
         args = parse_dsn(self.url)
     else:
         args = {}
     for k in ['host', 'port', 'dbname', 'user', 'password']:
         v = getattr(self, k)
         if v is not None:
             args[k] = v
     if not args['dbname']:
         args['dbname'] = 'tusker'
     args.update(override)
     return args
Exemple #21
0
def _get_attributes_from_cursor(vendor, cursor, attrs):
    """Attempt to set db connection attributes by introspecting the cursor."""
    if vendor == "postgresql":
        # pylint: disable=import-outside-toplevel
        from psycopg2.extensions import parse_dsn

        if hasattr(cursor, "connection") and hasattr(cursor.connection, "dsn"):
            dsn = getattr(cursor.connection, "dsn", None)
            if dsn:
                data = parse_dsn(dsn)
                attrs[SpanAttributes.DB_NAME] = data.get("dbname")
                attrs[SpanAttributes.NET_PEER_NAME] = data.get("host")
                attrs[SpanAttributes.NET_PEER_PORT] = int(data.get("port"))
    return attrs
Exemple #22
0
 def __init__(self,
              source_dsn,
              slot_name=None,
              keepslot=False,
              decoder='wal2json'):
     self.source_dsn = source_dsn
     self.dbname = parse_dsn(source_dsn)['dbname']
     self.conn = None
     self.slot_name = slot_name or 'connemara_%s' % self.dbname
     self.keepslot = keepslot
     self.decoder = decoder
     self.statements = []
     self.conn = psycopg2.connect(
         self.source_dsn, connection_factory=LogicalReplicationConnection)
 def purge_old(self):
     logging.debug('purge_old()')
     # purge all records flagged as upload_record = false
     connection = psycopg2.connect(
         **parse_dsn(self.db_config.db_connect_string))
     cursor = connection.cursor()
     # delete all rows
     cursor.execute("ROLLBACK;")
     cursor.execute("DELETE FROM %s WHERE upload_record != true;" %
                    self.target_table)
     # reset sequence to 0
     # cursor.execute("ROLLBACK;")
     # seq = self.target_table + '_id_seq'
     # cursor.execute("ALTER SEQUENCE %s RESTART;" % seq)
     # persist changes
     connection.commit()
     cursor.close()
     connection.close()
Exemple #24
0
def import_events(event, __):
    logger = logging.getLogger('event-recorder')
    logger.setLevel(logging.INFO)

    dsn = os.environ['DB_CONNECTION_STRING']

    database_password = None
    if 'ENCRYPTED_DATABASE_PASSWORD' in os.environ:
        # boto returns decrypted as b'bytes' so decode to convert to password string
        database_password = decrypt(
            os.environ['ENCRYPTED_DATABASE_PASSWORD']).decode()
    else:
        dsn_components = parse_dsn(dsn)
        database_password = boto3.client('rds').generate_db_auth_token(
            dsn_components['host'], 5432, dsn_components['user'])

    db_connection = create_db_connection(dsn, database_password)
    logger.info('Created connection to DB')

    for record in event['Records']:
        bucket = record['s3']['bucket']['name']
        filename = record['s3']['object']['key']

        iterable = fetch_import_file(bucket, filename)

        for line in iterable:
            try:
                message_envelope = json.loads(line)
                event = event_from_json_object(message_envelope['document'])

                if write_audit_event_to_database(event, db_connection):
                    if event.event_type == 'session_event' and event.details.get(
                            'session_event_type') == 'idp_authn_succeeded':
                        write_billing_event_to_database(event, db_connection)
                    if event.event_type == 'session_event' and event.details.get(
                            'session_event_type') == 'fraud_detected':
                        write_fraud_event_to_database(event, db_connection)

            except Exception as exception:
                logger.exception('Failed to store message{}'.format(exception))

        delete_import_file(bucket, filename)
Exemple #25
0
    def run(self, conn, conninfo):
        if not conninfo['standby']:
            return []

        try:
            # Get primary parameters from primary_conninfo
            dsn = parse_dsn(get_primary_conninfo(conn))
            p_host = dsn['host']

            # pg_stat_wal_receiver lookup
            rows = conn.query("""\
            SELECT '{p_host}' AS upstream,
            CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END AS connected
            FROM pg_stat_wal_receiver
            WHERE status='streaming' AND
                    conninfo LIKE '%host={p_host}%'
            """.format(p_host=p_host))
            return list(rows)
        except Exception as e:
            logger.exception(str(e))
            return []
Exemple #26
0
    def connect(self, schema=None):
        """
        Method which attempts connection to postresql instance using either
        a series of dsn kwargs or a libpq string. If schema is passed it
        will set path to that schema so all subsequent queries will be
        executed there.

        - *schema*: schema to connect to. If not provided, then public.

        It returns a Psycpog2 connection class. If it cannot connect it will 
        return None.

        See here for conn class https://www.psycopg.org/docs/connection.html
        """

        try:
            if self.libpq_string is not None:
                connection = psycopg2.connect(**parse_dsn(self.libpq_string))
            else:
                connection = psycopg2.connect(**self.kwargs)

        except DatabaseError as error:

            raise DatabaseError(psycopg2_exception_enhanced(error))

        if connection is not None and schema is not None:
            with connection:
                with connection.cursor() as cur:
                    schema = sql.Identifier(schema)
                    try:
                        cur.execute(
                            sql.SQL(
                                "create schema if not exists {schema}; "
                                "set search_path to {schema}, public;").format(
                                    schema=schema))

                    except Exception as error:
                        raise DatabaseError(psycopg2_exception_enhanced(error))

        return connection
Exemple #27
0
    def __init__(self, dsn, region):
        self.logger = logging.getLogger(__name__ + "." +
                                        self.__class__.__name__)

        parsed = ext.parse_dsn(dsn)
        user = parsed.get("user")
        password = parsed.get("password")

        if not password and user and user.startswith("iam_"):
            self.logger.info(
                "Using RDS dns kwargs supplier because password is empty and username starts with iam_"
            )
            self.kwargs = {
                'password': RdsIamAuthTokenGenerator(dsn, region),
                'sslmode': RdsIamAuthSslModeProvider(dsn),
                'sslrootcert': RdsIamAuthSslRootProvider(dsn)
            }
        else:
            self.logger.info(
                "Not using RDS dns kwargs supplier because password is not empty or "
                "username does not start with iam_")
            self.kwargs = {}
Exemple #28
0
def collect_psycopg2_metrics(context, trace, instance, args):
    try:
        from psycopg2.extensions import parse_dsn
    except ImportError:  # pragma: no cover
        from .dbapi import parse_dsn

    connection = instance.connection_proxy
    dsn = parse_dsn(connection.dsn)

    db = dsn.get("dbname")
    hostname = dsn.get("host", "localhost")
    port = dsn.get("port", 5432)

    command, table = None, None

    query = sqlparse.parse(instance.query)

    if not query and args:
        query = sqlparse.parse(args[0])

    if query:
        query = query[0]
        command = query.get_type()
        table = query.get_name()

    request = Request(
        command=ensure_utf8(command),
        key=None,
        hostname=ensure_utf8(hostname),
        port=ensure_utf8(port),
        connectionName=None,
        db=ensure_utf8(db),
        table=ensure_utf8(table),
    )
    request = request._asdict()
    context.iopipe.mark.db_trace(trace, "postgresql", request)
Exemple #29
0
def get_conn_id(conn):
    """
    Extract application_name from dsn
    """
    parsed = parse_dsn(conn.dsn)
    return parsed['application_name']
    # Build the list of objects to ignore.
    # This include every object belonging to an extension,
    # plus any object specifically ignored in the config file.
    objects_in_extensions = dumper.fetch_objects_in_extensions()
    all_objects = list(itertools.chain(*objects_in_extensions.values()))
    for obj in conf.get('ignored_objects', []):
        all_objects.append(obj)
    ignore_whole_schemas = conf.get('ignored_schemas', [])
    ignore_whole_schemas.append('_timescaledb_internal')
    dumper.create_repl_slot()
    logger.debug("dumper start")
    ddlscript = dumper.dump(ignored_schemas=ignore_whole_schemas)
    logger.debug("dumper end")

    dbname = parse_dsn(source_dsn)['dbname']
    schema_map = {'public': '%s_public' % dbname}
    for schema in ddlscript.objects_created_by_type[ObjectType.OBJECT_SCHEMA]:
        schema_map[schema] = '%s_%s' % (dbname, schema)
    table_mapping = {}
    # Remap the object and keep track of tables
    # This is fine for «small» dumps, but if we ever get gigantic schemas
    # RAM could be an issue.
    # In that case we shouldn't keep the whole dump's parse tree in RAM.
    filtered_statements = []
    for statement in ddlscript.statements:
        obj_creation = object_creation(statement)
        if obj_creation:
            objtype, fqname = obj_creation
            if objtype == ObjectType.OBJECT_SCHEMA:
                schema_name = fqname
Exemple #31
0
def test_dsn(engine, pg_params):
    params = pg_params.copy()
    params['password'] = '******'
    params['dbname'] = params.pop('database')
    params['port'] = str(params['port'])
    assert parse_dsn(engine.dsn) == params