PageRenderTime 164ms CodeModel.GetById 60ms app.highlight 16ms RepoModel.GetById 84ms app.codeStats 1ms

/silversupport/service/postgis.py

https://bitbucket.org/ianb/silverlining/
Python | 152 lines | 141 code | 10 blank | 1 comment | 16 complexity | 99fd26c695be0ec1cf3463a2ef7ebe71 MD5 | raw file
  1import os
  2import shutil
  3from silversupport.shell import run
  4from silversupport.abstractservice import AbstractService
  5
  6
  7class Service(AbstractService):
  8
  9    packages = [
 10        'postgis',
 11        'postgresql-8.4',
 12        'postgresql-8.4-postgis',
 13        'postgresql-client',
 14        'postgresql-client-8.4',
 15        'postgresql-client-common',
 16        'postgresql-common',
 17        'proj',
 18        ]
 19
 20    platform_packages = dict(
 21        python=[
 22            'python-psycopg2',
 23            'python-egenix-mxdatetime',
 24            'python-egenix-mxtools',
 25            'python-gdal',
 26            'python-pyproj',
 27            'python-pyproj-data',
 28            ],
 29        php=[
 30            'php5-pgsql',
 31            ])
 32
 33    def install(self):
 34        if not os.path.exists('/usr/bin/psql'):
 35            self.install_packages()
 36            shutil.copyfile(os.path.join(os.path.dirname(__file__),
 37                                         'postgis-pg_hba.conf'),
 38                            '/etc/postgresql/8.4/main/pg_hba.conf')
 39            run(['chown', 'postgres:postgres',
 40                 '/etc/postgresql/8.4/main/pg_hba.conf'])
 41            run(['/etc/init.d/postgresql-8.4', 'restart'])
 42
 43        stdout, stderr, returncode = run(
 44            ['psql', '-U', 'postgres', '--tuples-only'],
 45            capture_stdout=True, capture_stderr=True,
 46            stdin="select r.rolname from pg_catalog.pg_roles as r;")
 47        if 'www-mgr' not in stdout:
 48            run(['createuser', '-U', 'postgres',
 49                 '--no-superuser', '--no-createdb',
 50                 '--no-createrole', 'www-mgr'])
 51
 52        stdout, stderr, returncode = run(
 53            ['psql', '-U', 'postgres', '-l'], capture_stdout=True)
 54        if 'template_postgis' not in stdout:
 55            run(['createdb', '-U', 'postgres', 'template_postgis'])
 56            parts = ['CREATE LANGUAGE plpgsql;\n']
 57            parts.append("UPDATE pg_database SET datistemplate='true' WHERE datname='template_postgis';")
 58            for filename in ['postgis.sql',
 59                             'spatial_ref_sys.sql']:
 60                filename = os.path.join(
 61                    '/usr/share/postgresql/8.4/contrib', filename)
 62                fp = open(filename)
 63                parts.append(fp.read())
 64                parts.append('\n;\n')
 65                fp.close()
 66            parts.append("GRANT ALL ON geometry_columns TO PUBLIC;\n")
 67            parts.append("GRANT ALL ON spatial_ref_sys TO PUBLIC;\n")
 68            run(['psql', '-U', 'postgres', 'template_postgis'],
 69                stdin=''.join(parts),
 70                capture_stdout=True)
 71
 72        app_name = self.app_config.app_name
 73        stdout, stderr, returncode = run(
 74            ['/usr/bin/psql', '-U', 'postgres', '-l', '-t', '-A'],
 75            capture_stdout=True)
 76        databases = [line.split('|')[0] for line in stdout.splitlines()]
 77        if app_name in databases:
 78            self.output('Database %s already exists' % app_name)
 79        else:
 80            self.output('Database %s does not exist; creating.' % app_name)
 81            run(['createdb', '-U', 'postgres', '-O', 'www-mgr', '-T', 'template_postgis',
 82                 app_name])
 83
 84    def env_setup(self):
 85        environ = {}
 86        app_name = self.app_config.app_name
 87        if not self.devel:
 88            environ['CONFIG_PG_DBNAME'] = app_name
 89            environ['CONFIG_PG_USER'] = 'www-mgr'
 90            environ['CONFIG_PG_PASSWORD'] = ''
 91            environ['CONFIG_PG_HOST'] = ''
 92            environ['CONFIG_PG_PORT'] = ''
 93            environ['CONFIG_PG_SQLALCHEMY'] = 'postgres://postgres@/%s' % app_name
 94        else:
 95            import getpass
 96            environ['CONFIG_PG_DBNAME'] = app_name
 97            environ['CONFIG_PG_USER'] = getpass.getuser()
 98            environ['CONFIG_PG_PASSWORD'] = ''
 99            environ['CONFIG_PG_HOST'] = ''
100            environ['CONFIG_PG_PORT'] = ''
101            for name, value in self.devel_config.items():
102                if name.startswith('postgis.'):
103                    name = name[len('postgis.'):]
104                    environ['CONFIG_PG_%s' % name.upper()] = value
105            sa = 'postgres://'
106            if environ.get('CONFIG_PG_USER'):
107                sa += environ['CONFIG_PG_USER']
108                if environ.get('CONFIG_PG_PASSWORD'):
109                    sa += ':' + environ['CONFIG_PG_PASSWORD']
110                sa += '@'
111            if environ.get('CONFIG_PG_HOST'):
112                ## FIXME: should this check for 'localhost', which SA actually doesn't like?
113                sa += environ['CONFIG_PG_HOST']
114            if environ.get('CONFIG_PG_PORT'):
115                sa += ':' + environ['CONFIG_PG_PORT']
116            sa += '/' + environ['CONFIG_PG_DBNAME']
117            environ['CONFIG_PG_SQLALCHEMY'] = sa
118        return environ
119
120    def cli_options(self, force_user=None):
121        if not force_user:
122            force_user = self.env['CONFIG_PG_USER']
123        options = ['-U', force_user]
124        if self.env.get('CONFIG_PG_HOST'):
125            options.extend(['--host', self.env['CONFIG_PG_HOST']])
126            if self.env.get('CONFIG_PG_PORT'):
127                options.extend(['--port', self.env['CONFIG_PG_PORT']])
128        return options
129
130    def backup(self, output_dir):
131        ## FIXME: this includes a bunch of nonsense
132        run(['pg_dump', '--format=custom', '--no-owner', '--no-acl', '--no-privileges']
133            + self.cli_options('postgres')
134            + [self.env['CONFIG_PG_DBNAME'], '--file', os.path.join(output_dir, 'postgis.pgdump')])
135        fp = open(os.path.join(output_dir, 'postgis.README.txt'), 'w')
136        fp.write(self.BACKUP_README)
137        fp.close()
138
139    BACKUP_README = """\
140    The backup is created by pg_dump -Fc.  To restore it use pg_restore.
141    """
142
143    def restore(self, input_dir):
144        path = os.path.join(input_dir, 'postgis.pgdump')
145        dbname = self.env['CONFIG_PG_DBNAME']
146        run(['pg_restore'] + self.cli_options('postgres') + ['--dbname', dbname, path])
147
148    def clear(self):
149        dbname = self.env['CONFIG_PG_DBNAME']
150        ## FIXME: -U etc?
151        run(['dropdb'] + self.cli_options('postgres') + [dbname])
152        self.install()