Source code for seaworthy.containers.postgresql

"""
PostgreSQL container definition.
"""

from seaworthy.definitions import ContainerDefinition
from seaworthy.utils import output_lines


[docs]class PostgreSQLContainer(ContainerDefinition): """ PostgreSQL container definition. .. todo:: Write more docs. """ DEFAULT_NAME = 'postgresql' DEFAULT_IMAGE = 'postgres:alpine' # The postgres image starts up PostgreSQL twice--the first time to set up # the database and user, and the second to actually run the thing. DEFAULT_WAIT_PATTERNS = ( r'database system is ready to accept connections', r'database system is ready to accept connections',) DEFAULT_DATABASE = 'database' DEFAULT_USER = 'user' DEFAULT_PASSWORD = 'password' def __init__(self, name=DEFAULT_NAME, image=DEFAULT_IMAGE, wait_patterns=DEFAULT_WAIT_PATTERNS, database=DEFAULT_DATABASE, user=DEFAULT_USER, password=DEFAULT_PASSWORD, **kwargs): """ :param database: the name of a database to create at startup :param user: the name of a user to create at startup :param password: the password for the user """ super().__init__(name, image, wait_patterns, **kwargs) self.database = database self.user = user self.password = password
[docs] def base_kwargs(self): """ Add a ``tmpfs`` entry for ``/var/lib/postgresql/data`` to avoid unnecessary disk I/O and ``environment`` entries for the configured db and user creds. """ return { 'environment': { 'POSTGRES_DB': self.database, 'POSTGRES_USER': self.user, 'POSTGRES_PASSWORD': self.password, }, 'tmpfs': {'/var/lib/postgresql/data': 'uid=70,gid=70'}, }
[docs] def exec_pg_success(self, cmd): """ Execute a command inside a running container as the postgres user, asserting success. """ result = self.inner().exec_run(cmd, user='postgres') assert result.exit_code == 0, result.output.decode('utf-8') return result
[docs] def clean(self): """ Remove all data by dropping and recreating the configured database. .. note:: Only the configured database is removed. Any other databases remain untouched. """ self.exec_pg_success(['dropdb', '-U', self.user, self.database]) self.exec_pg_success(['createdb', '-U', self.user, self.database])
[docs] def exec_psql(self, command, psql_opts=['-qtA']): """ Execute a ``psql`` command inside a running container. By default the container's database is connected to. :param command: the command to run (passed to ``-c``) :param psql_opts: a list of extra options to pass to ``psql`` :returns: a tuple of the command exit code and output """ cmd = ['psql'] + psql_opts + [ '--dbname', self.database, '-U', self.user, '-c', command, ] return self.inner().exec_run(cmd, user='postgres')
[docs] def list_databases(self): """ Runs the ``\\list`` command and returns a list of column values with information about all databases. """ lines = output_lines(self.exec_psql('\\list')) return [line.split('|') for line in lines]
[docs] def list_tables(self): """ Runs the ``\\dt`` command and returns a list of column values with information about all tables in the database. """ lines = output_lines(self.exec_psql('\\dt')) return [line.split('|') for line in lines]
[docs] def list_users(self): """ Runs the ``\\du`` command and returns a list of column values with information about all user roles. """ lines = output_lines(self.exec_psql('\\du')) return [line.split('|') for line in lines]
[docs] def database_url(self): """ Returns a "database URL" for use with DJ-Database-URL and similar libraries. """ return 'postgres://{}:{}@{}/{}'.format( self.user, self.password, self.name, self.database)