Example #1
0
def ensure_db_relation_resources(rel):
    """Create the database resources needed for the relation."""

    master = rel.local

    if "password" not in master:
        return

    hookenv.log("Ensuring database {!r} and user {!r} exist for {}" "".format(master["database"], master["user"], rel))

    # First create the database, if it isn't already.
    postgresql.ensure_database(master["database"])

    # Next, connect to the database to create the rest in a transaction.
    con = postgresql.connect(database=master["database"])

    superuser, replication = _credential_types(rel)
    postgresql.ensure_user(
        con,
        master["user"],
        master["password"],
        superuser=superuser,
        replication=replication,
    )
    if not superuser:
        postgresql.ensure_user(con, master["schema_user"], master["schema_password"])

    # Grant specified privileges on the database to the user. This comes
    # from the PostgreSQL service configuration, as allowing the
    # relation to specify how much access it gets is insecure.
    config = hookenv.config()
    privs = set(filter(None, config["relation_database_privileges"].split(",")))
    postgresql.grant_database_privileges(con, master["user"], master["database"], privs)
    if not superuser:
        postgresql.grant_database_privileges(con, master["schema_user"], master["database"], privs)

    # Reset the roles granted to the user as requested.
    if "roles" in master:
        roles = filter(None, master.get("roles", "").split(","))
        postgresql.grant_user_roles(con, master["user"], roles)

    # Create requested extensions. We never drop extensions, as there
    # may be dependent objects.
    if "extensions" in master:
        extensions = list(filter(None, master.get("extensions", "").split(",")))
        # Convert to the (extension, schema) tuple expected by
        # postgresql.ensure_extensions
        for i in range(0, len(extensions)):
            m = re.search(r"^\s*([^(\s]+)\s*(?:\((\w+)\))?", extensions[i])
            if m is None:
                raise RuntimeError("Invalid extension {}".format(extensions[i]))
            extensions[i] = (m.group(1), m.group(2) or "public")
        postgresql.ensure_extensions(con, extensions)

    con.commit()  # Don't throw away our changes.
    def test_ensure_database(self, connect):
        cur = connect().cursor()

        # If the database exists, nothing happens.
        cur.fetchone.return_value = sentinel.something
        postgresql.ensure_database("hello")
        cur.execute.assert_has_calls([call("SELECT datname FROM pg_database WHERE datname=%s", ("hello",))])

        # If the database does not exist, it is created.
        cur.fetchone.return_value = None
        postgresql.ensure_database("hello")
        cur.execute.assert_has_calls(
            [call("SELECT datname FROM pg_database WHERE datname=%s", ("hello",)), call("CREATE DATABASE %s", (ANY,))]
        )
        # The database name in that last call was correctly quoted.
        quoted_dbname = cur.execute.call_args[0][1][0]
        self.assertIsInstance(quoted_dbname, postgresql.AsIs)
        self.assertEqual(str(quoted_dbname), '"hello"')
Example #3
0
def ensure_db_relation_resources(rel):
    """Create the database resources needed for the relation."""

    master = rel.local

    hookenv.log("Ensuring database {!r} and user {!r} exist for {}" "".format(master["database"], master["user"], rel))

    # First create the database, if it isn't already.
    postgresql.ensure_database(master["database"])

    # Next, connect to the database to create the rest in a transaction.
    con = postgresql.connect(database=master["database"])

    superuser, replication = _credential_types(rel)
    postgresql.ensure_user(con, master["user"], master["password"], superuser=superuser, replication=replication)
    if not superuser:
        postgresql.ensure_user(con, master["schema_user"], master["schema_password"])

    # Grant specified privileges on the database to the user. This comes
    # from the PostgreSQL service configuration, as allowing the
    # relation to specify how much access it gets is insecure.
    config = hookenv.config()
    privs = set(filter(None, config["relation_database_privileges"].split(",")))
    postgresql.grant_database_privileges(con, master["user"], master["database"], privs)
    if not superuser:
        postgresql.grant_database_privileges(con, master["schema_user"], master["database"], privs)

    # Reset the roles granted to the user as requested.
    if "roles" in master:
        roles = filter(None, master.get("roles", "").split(","))
        postgresql.grant_user_roles(con, master["user"], roles)

    # Create requested extensions. We never drop extensions, as there
    # may be dependent objects.
    if "extensions" in master:
        extensions = filter(None, master.get("extensions", "").split(","))
        postgresql.ensure_extensions(con, extensions)

    con.commit()  # Don't throw away our changes.
Example #4
0
    def test_ensure_database(self, connect):
        cur = connect().cursor()

        # If the database exists, nothing happens.
        cur.fetchone.return_value = sentinel.something
        postgresql.ensure_database('hello')
        cur.execute.assert_has_calls([
            call('SELECT datname FROM pg_database WHERE datname=%s',
                 ('hello', ))
        ])

        # If the database does not exist, it is created.
        cur.fetchone.return_value = None
        postgresql.ensure_database('hello')
        cur.execute.assert_has_calls([
            call('SELECT datname FROM pg_database WHERE datname=%s',
                 ('hello', )),
            call('CREATE DATABASE %s OWNER %s', (ANY, ANY))
        ])
        # The database name in that last call was correctly quoted.
        quoted_dbname = cur.execute.call_args[0][1][0]
        self.assertIsInstance(quoted_dbname, postgresql.AsIs)
        self.assertEqual(str(quoted_dbname), '"hello"')