PageRenderTime 105ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/silversupport/service/postgis.py

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