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_extensions(self, pgidentifier, log): con = MagicMock() cur = con.cursor() pgidentifier.side_effect = lambda d: "q_{}".format(d) existing_extensions = set(["extA", "extB"]) wanted_extensions = set(["extB", "extC"]) cur.fetchall.return_value = [[x] for x in existing_extensions] postgresql.ensure_extensions(con, wanted_extensions) cur.execute.assert_has_calls( [call("SELECT extname FROM pg_extension"), call("CREATE EXTENSION %s", ("q_extC",))] )
def test_ensure_extensions(self, pgidentifier, log): con = MagicMock() cur = con.cursor() pgidentifier.side_effect = lambda d: 'q_{}'.format(d) existing_extensions = set([('extA', 'public'), ('extB', 'public')]) wanted_extensions = set([('extB', 'public'), ('extC', 'custom')]) cur.fetchall.return_value = [x for x in existing_extensions] postgresql.ensure_extensions(con, wanted_extensions) cur.execute.assert_has_calls([ call( 'SELECT extname, nspname FROM pg_extension, pg_namespace WHERE pg_namespace.oid = extnamespace' ), call('CREATE SCHEMA IF NOT EXISTS %s', ('q_custom', )), call('GRANT USAGE ON SCHEMA %s TO PUBLIC', ('q_custom', )), call('CREATE EXTENSION %s WITH SCHEMA %s', ('q_extC', 'q_custom')) ])
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.