Merge pull request #6398 from s0undt3ch/issues/6352-parser-psql-beta-version

Properly parse a PSQL server version, even beta versions
This commit is contained in:
David Boucha 2013-07-28 09:21:26 -07:00
commit a3dc67c15e

View File

@ -19,6 +19,7 @@ Module to provide Postgres compatibility to salt.
# Import python libs
import datetime
import distutils
import pipes
import logging
import csv
@ -101,6 +102,18 @@ def version(user=None, host=None, port=None, maintenance_db=None,
return line
def _parsed_version(user=None, host=None, port=None, maintenance_db=None,
password=None, runas=None):
'''
Returns the server version properly parsed and int casted for internal use
'''
psql_version = version(
user, host, port, maintenance_db, password, runas
)
return distutils.version.LooseVersion(psql_version).version
def _connection_defaults(user=None, host=None, port=None, maintenance_db=None,
password=None):
'''
@ -209,12 +222,14 @@ def db_list(user=None, host=None, port=None, maintenance_db=None,
ret = {}
query = 'SELECT datname as "Name", pga.rolname as "Owner", ' \
'pg_encoding_to_char(encoding) as "Encoding", ' \
'datcollate as "Collate", datctype as "Ctype", ' \
'datacl as "Access privileges", spcname as "Tablespace" ' \
'FROM pg_database pgd, pg_roles pga, pg_tablespace pgts ' \
'WHERE pga.oid = pgd.datdba AND pgts.oid = pgd.dattablespace'
query = (
'SELECT datname as "Name", pga.rolname as "Owner", '
'pg_encoding_to_char(encoding) as "Encoding", '
'datcollate as "Collate", datctype as "Ctype", '
'datacl as "Access privileges", spcname as "Tablespace" '
'FROM pg_database pgd, pg_roles pga, pg_tablespace pgts '
'WHERE pga.oid = pgd.datdba AND pgts.oid = pgd.dattablespace'
)
rows = psql_query(query, runas=runas, host=host, user=user,
port=port, maintenance_db=maintenance_db,
@ -276,9 +291,9 @@ def db_create(name,
# doesn't get thrown by dashes in the name
'OWNER': owner and '"{0}"'.format(owner),
'TEMPLATE': template,
'ENCODING': encoding and '\'{0}\''.format(encoding),
'LC_COLLATE': lc_collate and '\'{0}\''.format(lc_collate),
'LC_CTYPE': lc_ctype and '\'{0}\''.format(lc_ctype),
'ENCODING': encoding and '{0!r}'.format(encoding),
'LC_COLLATE': lc_collate and '{0!r}'.format(lc_collate),
'LC_CTYPE': lc_ctype and '{0!r}'.format(lc_ctype),
'TABLESPACE': tablespace,
}
with_chunks = []
@ -320,8 +335,8 @@ def db_alter(name, user=None, host=None, port=None, maintenance_db=None,
queries.append('ALTER DATABASE "{0}" SET TABLESPACE "{1}"'.format(
name, tablespace
))
for Q in queries:
cmd = _psql_cmd('-c', Q, user=user, host=host, port=port,
for query in queries:
cmd = _psql_cmd('-c', query, user=user, host=host, port=port,
maintenance_db=maintenance_db, password=password)
ret = _run_psql(cmd, runas=runas, password=password, host=host)
if ret['retcode'] != 0:
@ -362,13 +377,13 @@ def user_list(user=None, host=None, port=None, maintenance_db=None,
ret = {}
ver = version(user=user,
host=host,
port=port,
maintenance_db=maintenance_db,
password=password,
runas=runas).split('.')
if len(ver) >= 2 and int(ver[0]) >= 9 and int(ver[1]) >= 1:
ver = _parsed_version(user=user,
host=host,
port=port,
maintenance_db=maintenance_db,
password=password,
runas=runas)
if len(ver) >= 2 and ver[0] >= 9 and ver[1] >= 1:
query = (
'SELECT rolname as "name", rolsuper as "superuser", '
'rolinherit as "inherits privileges", '
@ -471,25 +486,25 @@ def _role_create(name,
# check if role exists
if user_exists(name, user, host, port, maintenance_db,
password=password, runas=runas):
log.info('{0} \'{1}\' already exists'.format(create_type, name,))
log.info('{0} {1!r} already exists'.format(create_type, name))
return False
sub_cmd = 'CREATE {0} "{1}" WITH'.format(create_type, name, )
sub_cmd = 'CREATE {0} "{1}" WITH'.format(create_type, name)
if rolepassword is not None:
if encrypted:
sub_cmd = '{0} ENCRYPTED'.format(sub_cmd, )
sub_cmd = '{0} ENCRYPTED'.format(sub_cmd)
escaped_password = rolepassword.replace('\'', '\'\'')
sub_cmd = '{0} PASSWORD \'{1}\''.format(sub_cmd, escaped_password)
sub_cmd = '{0} PASSWORD {1!r}'.format(sub_cmd, escaped_password)
if createdb:
sub_cmd = '{0} CREATEDB'.format(sub_cmd, )
sub_cmd = '{0} CREATEDB'.format(sub_cmd)
if createuser:
sub_cmd = '{0} CREATEUSER'.format(sub_cmd, )
sub_cmd = '{0} CREATEUSER'.format(sub_cmd)
if superuser:
sub_cmd = '{0} SUPERUSER'.format(sub_cmd, )
sub_cmd = '{0} SUPERUSER'.format(sub_cmd)
if replication:
sub_cmd = '{0} REPLICATION'.format(sub_cmd, )
sub_cmd = '{0} REPLICATION'.format(sub_cmd)
if groups:
sub_cmd = '{0} IN GROUP {1}'.format(sub_cmd, groups, )
sub_cmd = '{0} IN GROUP {1}'.format(sub_cmd, groups)
if sub_cmd.endswith('WITH'):
sub_cmd = sub_cmd.replace(' WITH', '')
@ -497,7 +512,7 @@ def _role_create(name,
cmd = _psql_cmd('-c', sub_cmd, host=host, user=user, port=port,
maintenance_db=maintenance_db, password=password)
return _run_psql(cmd, runas=runas, password=password, host=host,
run_cmd="cmd.run")
run_cmd='cmd.run')
def user_create(username,
@ -519,7 +534,9 @@ def user_create(username,
CLI Examples::
salt '*' postgres.user_create 'username' user='user' host='hostname' port='port' password='password' rolepassword='rolepassword'
salt '*' postgres.user_create 'username' user='user' \\
host='hostname' port='port' password='password' \\
rolepassword='rolepassword'
'''
return _role_create(username,
True,
@ -558,20 +575,20 @@ def _role_update(name,
# check if user exists
if not user_exists(name, user, host, port, maintenance_db, password,
runas=runas):
log.info('User \'{0}\' does not exist'.format(name,))
log.info('User {0!r} does not exist'.format(name))
return False
sub_cmd = 'ALTER ROLE {0} WITH'.format(name, )
sub_cmd = 'ALTER ROLE {0} WITH'.format(name)
if rolepassword is not None:
sub_cmd = '{0} PASSWORD \'{1}\''.format(sub_cmd, rolepassword)
sub_cmd = '{0} PASSWORD {1!r}'.format(sub_cmd, rolepassword)
if createdb:
sub_cmd = '{0} CREATEDB'.format(sub_cmd, )
sub_cmd = '{0} CREATEDB'.format(sub_cmd)
if createuser:
sub_cmd = '{0} CREATEUSER'.format(sub_cmd, )
sub_cmd = '{0} CREATEUSER'.format(sub_cmd)
if encrypted:
sub_cmd = '{0} ENCRYPTED'.format(sub_cmd, )
sub_cmd = '{0} ENCRYPTED'.format(sub_cmd)
if replication:
sub_cmd = '{0} REPLICATION'.format(sub_cmd, )
sub_cmd = '{0} REPLICATION'.format(sub_cmd)
if sub_cmd.endswith('WITH'):
sub_cmd = sub_cmd.replace(' WITH', '')
@ -583,7 +600,7 @@ def _role_update(name,
cmd = _psql_cmd('-c', sub_cmd, host=host, user=user, port=port,
maintenance_db=maintenance_db, password=password)
return _run_psql(cmd, runas=runas, password=password, host=host,
run_cmd="cmd.run")
run_cmd='cmd.run')
def user_update(username,
@ -604,7 +621,9 @@ def user_update(username,
CLI Examples::
salt '*' postgres.user_create 'username' user='user' host='hostname' port='port' password='password' rolepassword='rolepassword'
salt '*' postgres.user_create 'username' user='user' \\
host='hostname' port='port' password='password' \\
rolepassword='rolepassword'
'''
return _role_update(username,
user,
@ -630,20 +649,21 @@ def _role_remove(name, user=None, host=None, port=None, maintenance_db=None,
# check if user exists
if not user_exists(name, user, host, port, maintenance_db,
password=password, runas=runas):
log.info('User \'{0}\' does not exist'.format(name,))
log.info('User {0!r} does not exist'.format(name))
return False
# user exists, proceed
sub_cmd = 'DROP ROLE {0}'.format(name)
cmd = _psql_cmd('-c', sub_cmd, host=host, user=user, port=port,
maintenance_db=maintenance_db, password=password)
_run_psql(cmd, runas=runas, password=password, host=host,
run_cmd="cmd.run")
_run_psql(
cmd, runas=runas, password=password, host=host, run_cmd='cmd.run'
)
if not user_exists(name, user, host, port, maintenance_db,
password=password, runas=runas):
return True
else:
log.info('Failed to delete user \'{0}\'.'.format(name, ))
log.info('Failed to delete user {0!r}.'.format(name))
return False
@ -687,7 +707,9 @@ def group_create(groupname,
CLI Example::
salt '*' postgres.group_create 'groupname' user='user' host='hostname' port='port' password='password' rolepassword='rolepassword'
salt '*' postgres.group_create 'groupname' user='user' \\
host='hostname' port='port' password='password' \\
rolepassword='rolepassword'
'''
return _role_create(groupname,
False,
@ -724,7 +746,9 @@ def group_update(groupname,
CLI Examples::
salt '*' postgres.group_update 'username' user='user' host='hostname' port='port' password='password' rolepassword='rolepassword'
salt '*' postgres.group_update 'username' user='user' \\
host='hostname' port='port' password='password' \\
rolepassword='rolepassword'
'''
return _role_update(groupname,
user,
@ -758,13 +782,14 @@ def group_remove(groupname,
return _role_remove(groupname, user, host, port, maintenance_db,
password, runas)
def owner_to(dbname,
ownername,
user=None,
host=None,
port=None,
password=None,
runas=None):
ownername,
user=None,
host=None,
port=None,
password=None,
runas=None):
'''
Set the owner of all schemas, functions, tables, views and sequences to
the given username.
@ -776,54 +801,52 @@ def owner_to(dbname,
sqlfile = tempfile.NamedTemporaryFile()
sqlfile.write('begin;\n')
sqlfile.write('alter database {0} owner to {1};\n'.format(dbname, ownername))
queries = (
# schemas
(
'alter schema %(n)s owner to %(owner)s;',
'select quote_ident(schema_name) as n from information_schema.schemata;'
),
# tables and views
(
'alter table %(n)s owner to %(owner)s;',
"select quote_ident(table_schema)||'.'||quote_ident(table_name) as n " +
"from information_schema.tables where table_schema not in ('pg_catalog', 'information_schema');"
),
# functions
(
'alter function %(n)s owner to %(owner)s;',
"select p.oid::regprocedure::text as n from pg_catalog.pg_proc p " +
"join pg_catalog.pg_namespace ns on p.pronamespace=ns.oid where ns.nspname not in ('pg_catalog', 'information_schema') " +
" and not p.proisagg;"
),
# aggregate functions
(
'alter aggregate %(n)s owner to %(owner)s;',
"select p.oid::regprocedure::text as n from pg_catalog.pg_proc p " +
"join pg_catalog.pg_namespace ns on p.pronamespace=ns.oid where ns.nspname not in ('pg_catalog', 'information_schema') " +
" and p.proisagg;"
),
# sequences
(
'alter sequence %(n)s owner to %(owner)s;',
"select quote_ident(sequence_schema)||'.'||quote_ident(sequence_name) as n from information_schema.sequences;"
sqlfile.write(
'alter database {0} owner to {1};\n'.format(
dbname, ownername
)
)
queries = (
# schemas
('alter schema ${n} owner to ${owner};',
'select quote_ident(schema_name) as n from '
'information_schema.schemata;'),
# tables and views
('alter table ${n} owner to ${owner};',
'select quote_ident(table_schema)||\'.\'||quote_ident(table_name) as '
'n from information_schema.tables where table_schema not in '
'(\'pg_catalog\', \'information_schema\');'),
# functions
('alter function ${n} owner to ${owner};',
'select p.oid::regprocedure::text as n from pg_catalog.pg_proc p '
'join pg_catalog.pg_namespace ns on p.pronamespace=ns.oid where '
'ns.nspname not in (\'pg_catalog\', \'information_schema\') '
' and not p.proisagg;'),
# aggregate functions
('alter aggregate ${n} owner to ${owner};',
'select p.oid::regprocedure::text as n from pg_catalog.pg_proc p '
'join pg_catalog.pg_namespace ns on p.pronamespace=ns.oid where '
'ns.nspname not in (\'pg_catalog\', \'information_schema\') '
'and p.proisagg;'),
# sequences
('alter sequence ${n} owner to ${owner};',
'select quote_ident(sequence_schema)||\'.\'||'
'quote_ident(sequence_name) as n from information_schema.sequences;')
)
for fmt, query in queries:
ret = psql_query(query, user=user, host=host, port=port, maintenance_db=dbname,
password=password, runas=runas)
ret = psql_query(query, user=user, host=host, port=port,
maintenance_db=dbname, password=password, runas=runas)
for row in ret:
line = fmt % {'owner': ownername, 'n': row['n']}
sqlfile.write(line + "\n")
sqlfile.write(fmt.format(owner=ownername, n=row['n']) + '\n')
sqlfile.write('commit;\n')
sqlfile.flush()
os.chmod(sqlfile.name, 0644) # ensure psql can read the file
os.chmod(sqlfile.name, 0644) # ensure psql can read the file
# run the generated sqlfile in the db
cmd = _psql_cmd('-f', sqlfile.name, user=user, host=host, port=port,
password=password, maintenance_db=dbname)
password=password, maintenance_db=dbname)
cmdret = _run_psql(cmd, runas=runas, password=password)
return cmdret