New module postgresql_sequence (#55027)

* postgresql_sequence: initial commit with new module and tests

* change return variables and adjust tests

* fix sanity checks

* fix linter errors

* change formatting functions and put params alphabetically

* add new examples and remove restrict option
* remove restrict option
* remove `required: false`
* add links to documentation
* change some minor parts in documentation
* add new integration tests for
** drop cascade
** change owner

* change usage of owner and created a test case for set owner during creation

* remove some documents and use docsfragments

* add aliases for minvalue and maxvalue

* change to warn if sequence not exists but should be removed

* use connect_to_db from module_utils/postgres.py

* add checkmode for several tests

* fix psycopg2 import and connect_to_db

* add a test for drop nonexistent sequence

* change get_info funcrtion to use only one SQL statement

* rewrite the module for cleaner code
* remove psycopg2
* change check_mode behavior
* add docstrings for class and methods
* add test for create sequence with owner in check_mode

* fix typo in set_schema()

* fix docu and cleanup the code
* adjust documentation for state, schema and newschema
* remove mutually_exclusive for 'absent'
* remove unused code comments
* remove warning for drop non-exicsting sequence
* change autocommit condition

* adjust state documentation
pull/57549/head
tcraxs 5 years ago committed by Felix Fontein
parent 03d64cd9ea
commit 07d446825a

@ -38,7 +38,7 @@ class UnclosedQuoteError(SQLParseError):
# maps a type of identifier to the maximum number of dot levels that are
# allowed to specify that identifier. For example, a database column can be
# specified by up to 4 levels: database.schema.table.column
_PG_IDENTIFIER_TO_DOT_LEVEL = dict(database=1, schema=2, table=3, column=4, role=1, tablespace=1)
_PG_IDENTIFIER_TO_DOT_LEVEL = dict(database=1, schema=2, table=3, column=4, role=1, tablespace=1, sequence=3)
_MYSQL_IDENTIFIER_TO_DOT_LEVEL = dict(database=1, table=2, column=3, role=1, vars=1)

@ -0,0 +1,621 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Tobias Birkefeld (@tcraxs) <t@craxs.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = r'''
---
module: postgresql_sequence
short_description: Create, drop, or alter a PostgreSQL sequence
description:
- Allows to create, drop or change the definition of a sequence generator
U(https://www.postgresql.org/docs/current/sql-createsequence.html).
version_added: '2.9'
options:
sequence:
description:
- The name of the sequence.
required: true
type: str
aliases:
- name
state:
description:
- The sequence state.
- If I(state=absent) other options will be ignored except of I(name) and
I(schema).
default: present
choices: [ absent, present ]
type: str
data_type:
description:
- Specifies the data type of the sequence. Valid types are bigint, integer,
and smallint. bigint is the default. The data type determines the default
minimum and maximum values of the sequence. For more info see the
documention
U(https://www.postgresql.org/docs/current/sql-createsequence.html).
- Supported from PostgreSQL 10.
choices: [ bigint, integer, smallint ]
type: str
increment:
description:
- Increment specifies which value is added to the current sequence value
to create a new value.
- A positive value will make an ascending sequence, a negative one a
descending sequence. The default value is 1.
type: int
minvalue:
description:
- Minvalue determines the minimum value a sequence can generate. The
default for an ascending sequence is 1. The default for a descending
sequence is the minimum value of the data type.
type: int
aliases:
- min
maxvalue:
description:
- Maxvalue determines the maximum value for the sequence. The default for
an ascending sequence is the maximum
value of the data type. The default for a descending sequence is -1.
type: int
aliases:
- max
start:
description:
- Start allows the sequence to begin anywhere. The default starting value
is I(minvalue) for ascending sequences and I(maxvalue) for descending
ones.
type: int
cache:
description:
- Cache specifies how many sequence numbers are to be preallocated and
stored in memory for faster access. The minimum value is 1 (only one
value can be generated at a time, i.e., no cache), and this is also
the default.
type: int
cycle:
description:
- The cycle option allows the sequence to wrap around when the I(maxvalue)
or I(minvalue) has been reached by an ascending or descending sequence
respectively. If the limit is reached, the next number generated will be
the minvalue or maxvalue, respectively.
- If C(false) (NO CYCLE) is specified, any calls to nextval after the sequence
has reached its maximum value will return an error. False (NO CYCLE) is
the default.
type: bool
cascade:
description:
- Automatically drop objects that depend on the sequence, and in turn all
objects that depend on those objects.
- Ignored if I(state=present).
- Only used with I(state=absent).
type: bool
rename_to:
description:
- The new name for the I(sequence).
- Works only for existing sequences.
type: str
owner:
description:
- Set the owner for the I(sequence).
type: str
schema:
description:
- The schema of the I(sequence). This is be used to create and relocate
a I(sequence) in the given schema.
default: public
type: str
newschema:
description:
- The new schema for the I(sequence). Will be used for moving a
I(sequence) to another I(schema).
- Works only for existing sequences.
type: str
session_role:
description:
- Switch to session_role after connecting. The specified I(session_role)
must be a role that the current I(login_user) is a member of.
- Permissions checking for SQL commands is carried out as though
the I(session_role) were the one that had logged in originally.
type: str
db:
description:
- Name of database to connect to and run queries against.
type: str
aliases:
- database
- login_db
notes:
- If you do not pass db parameter, sequence will be created in the database
named postgres.
author:
- Tobias Birkefeld (@tcraxs)
extends_documentation_fragment: postgres
'''
EXAMPLES = r'''
- name: Create an ascending bigint sequence called foobar in the default
database
postgresql_sequence:
name: foobar
- name: Create an ascending integer sequence called foobar, starting at 101
postgresql_sequence:
name: foobar
data_type: integer
start: 101
- name: Create an descending sequence called foobar, starting at 101 and
preallocated 10 sequence numbers in cache
postgresql_sequence:
name: foobar
increment: -1
cache: 10
start: 101
- name: Create an ascending sequence called foobar, which cycle between 1 to 10
postgresql_sequence:
name: foobar
cycle: yes
min: 1
max: 10
- name: Create an ascending bigint sequence called foobar in the default
database with owner foobar
postgresql_sequence:
name: foobar
owner: foobar
- name: Rename an existing sequence named foo to bar
postgresql_sequence:
name: foo
rename_to: bar
- name: Change the schema of an existing sequence to foobar
postgresql_sequence:
name: foobar
newschema: foobar
- name: Change the owner of an existing sequence to foobar
postgresql_sequence:
name: foobar
owner: foobar
- name: Drop a sequence called foobar
postgresql_sequence:
name: foobar
state: absent
- name: Drop a sequence called foobar with cascade
postgresql_sequence:
name: foobar
cascade: yes
state: absent
'''
RETURN = r'''
state:
description: Sequence state at the end of execution.
returned: always
type: str
sample: 'present'
sequence:
description: Sequence name.
returned: always
type: str
sample: 'foobar'
queries:
description: List of queries that was tried to be executed.
returned: always
type: str
sample: [ "CREATE SEQUENCE \"foo\"" ]
schema:
description: Name of the schema of the sequence
returned: always
type: str
sample: 'foo'
data_type:
description: Shows the current data type of the sequence.
returned: always
type: str
sample: 'bigint'
increment:
description: The value of increment of the sequence. A positive value will
make an ascending sequence, a negative one a descending
sequence.
returned: always
type: int
sample: '-1'
minvalue:
description: The value of minvalue of the sequence.
returned: always
type: int
sample: '1'
maxvalue:
description: The value of maxvalue of the sequence.
returned: always
type: int
sample: '9223372036854775807'
start:
description: The value of start of the sequence.
returned: always
type: int
sample: '12'
cycle:
description: Shows if the sequence cycle or not.
returned: always
type: str
sample: 'NO'
owner:
description: Shows the current owner of the sequence
after the successful run of the task.
returned: always
type: str
sample: 'postgres'
newname:
description: Shows the new sequence name after rename.
returned: on success
type: str
sample: 'barfoo'
newschema:
description: Shows the new schema of the sequence after schema change.
returned: on success
type: str
sample: 'foobar'
'''
try:
from psycopg2.extras import DictCursor
except ImportError:
# psycopg2 is checked by connect_to_db()
# from ansible.module_utils.postgres
pass
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.database import pg_quote_identifier
from ansible.module_utils.postgres import connect_to_db, postgres_common_argument_spec
from ansible.module_utils._text import to_native
def exec_sql(obj, query, ddl=False, add_to_executed=True):
"""Execute SQL.
Auxiliary function for PostgreSQL user classes.
Returns a query result if possible or True/False if ddl=True arg was passed.
It necessary for statements that don't return any result (like DDL queries).
Arguments:
obj (obj) -- must be an object of a user class.
The object must have module (AnsibleModule class object) and
cursor (psycopg cursor object) attributes
query (str) -- SQL query to execute
ddl (bool) -- must return True or False instead of rows (typical for DDL queries)
(default False)
add_to_executed (bool) -- append the query to obj.executed_queries attribute
"""
try:
obj.cursor.execute(query)
if add_to_executed:
obj.executed_queries.append(query)
if not ddl:
res = obj.cursor.fetchall()
return res
return True
except Exception as e:
obj.module.fail_json(msg="Cannot execute SQL '%s': %s" % (query, to_native(e)))
return False
class Sequence(object):
"""Implements behavior of CREATE, ALTER or DROP SEQUENCE PostgreSQL command.
Arguments:
module (AnsibleModule) -- object of AnsibleModule class
cursor (cursor) -- cursor objec of psycopg2 library
Attributes:
module (AnsibleModule) -- object of AnsibleModule class
cursor (cursor) -- cursor objec of psycopg2 library
changed (bool) -- something was changed after execution or not
executed_queries (list) -- executed queries
name (str) -- name of the sequence
owner (str) -- name of the owner of the sequence
schema (str) -- name of the schema (default: public)
data_type (str) -- data type of the sequence
start_value (int) -- value of the sequence start
minvalue (int) -- minimum value of the sequence
maxvalue (int) -- maximum value of the sequence
increment (int) -- increment value of the sequence
cycle (bool) -- sequence can cycle or not
new_name (str) -- name of the renamed sequence
new_schema (str) -- name of the new schema
exists (bool) -- sequence exists or not
"""
def __init__(self, module, cursor):
self.module = module
self.cursor = cursor
self.executed_queries = []
self.name = self.module.params['sequence']
self.owner = ''
self.schema = self.module.params['schema']
self.data_type = ''
self.start_value = ''
self.minvalue = ''
self.maxvalue = ''
self.increment = ''
self.cycle = ''
self.new_name = ''
self.new_schema = ''
self.exists = False
# Collect info
self.get_info()
def get_info(self):
"""Getter to refresh and get sequence info"""
query = ("SELECT "
"s.sequence_schema AS schemaname, "
"s.sequence_name AS sequencename, "
"pg_get_userbyid(c.relowner) AS sequenceowner, "
"s.data_type::regtype AS data_type, "
"s.start_value AS start_value, "
"s.minimum_value AS min_value, "
"s.maximum_value AS max_value, "
"s.increment AS increment_by, "
"s.cycle_option AS cycle "
"FROM information_schema.sequences s "
"JOIN pg_class c ON c.relname = s.sequence_name "
"LEFT JOIN pg_namespace n ON n.oid = c.relnamespace "
"WHERE NOT pg_is_other_temp_schema(n.oid) "
"AND c.relkind = 'S'::\"char\" "
"AND sequence_name = '%s' "
"AND sequence_schema = '%s'" % (self.name,
self.schema))
res = exec_sql(self, query, add_to_executed=False)
if not res:
self.exists = False
return False
if res:
self.exists = True
self.schema = res[0]['schemaname']
self.name = res[0]['sequencename']
self.owner = res[0]['sequenceowner']
self.data_type = res[0]['data_type']
self.start_value = res[0]['start_value']
self.minvalue = res[0]['min_value']
self.maxvalue = res[0]['max_value']
self.increment = res[0]['increment_by']
self.cycle = res[0]['cycle']
def create(self):
"""Implements CREATE SEQUENCE command behavior."""
query = ['CREATE SEQUENCE']
query.append(self.__add_schema())
if self.module.params.get('data_type'):
query.append('AS %s' % self.module.params['data_type'])
if self.module.params.get('increment'):
query.append('INCREMENT BY %s' % self.module.params['increment'])
if self.module.params.get('minvalue'):
query.append('MINVALUE %s' % self.module.params['minvalue'])
if self.module.params.get('maxvalue'):
query.append('MAXVALUE %s' % self.module.params['maxvalue'])
if self.module.params.get('start'):
query.append('START WITH %s' % self.module.params['start'])
if self.module.params.get('cache'):
query.append('CACHE %s' % self.module.params['cache'])
if self.module.params.get('cycle'):
query.append('CYCLE')
return exec_sql(self, ' '.join(query), ddl=True)
def drop(self):
"""Implements DROP SEQUENCE command behavior."""
query = ['DROP SEQUENCE']
query.append(self.__add_schema())
if self.module.params.get('cascade'):
query.append('CASCADE')
return exec_sql(self, ' '.join(query), ddl=True)
def rename(self):
"""Implements ALTER SEQUENCE RENAME TO command behavior."""
query = ['ALTER SEQUENCE']
query.append(self.__add_schema())
query.append('RENAME TO %s' % pg_quote_identifier(self.module.params['rename_to'], 'sequence'))
return exec_sql(self, ' '.join(query), ddl=True)
def set_owner(self):
"""Implements ALTER SEQUENCE OWNER TO command behavior."""
query = ['ALTER SEQUENCE']
query.append(self.__add_schema())
query.append('OWNER TO %s' % pg_quote_identifier(self.module.params['owner'], 'role'))
return exec_sql(self, ' '.join(query), ddl=True)
def set_schema(self):
"""Implements ALTER SEQUENCE SET SCHEMA command behavior."""
query = ['ALTER SEQUENCE']
query.append(self.__add_schema())
query.append('SET SCHEMA %s' % pg_quote_identifier(self.module.params['newschema'], 'schema'))
return exec_sql(self, ' '.join(query), ddl=True)
def __add_schema(self):
return '.'.join([pg_quote_identifier(self.schema, 'schema'),
pg_quote_identifier(self.name, 'sequence')])
# ===========================================
# Module execution.
#
def main():
argument_spec = postgres_common_argument_spec()
argument_spec.update(
sequence=dict(type='str', required=True, aliases=['name']),
state=dict(type='str', default='present', choices=['absent', 'present']),
data_type=dict(type='str', choices=['bigint', 'integer', 'smallint']),
increment=dict(type='int'),
minvalue=dict(type='int', aliases=['min']),
maxvalue=dict(type='int', aliases=['max']),
start=dict(type='int'),
cache=dict(type='int'),
cycle=dict(type='bool'),
schema=dict(type='str', default='public'),
cascade=dict(type='bool'),
rename_to=dict(type='str'),
owner=dict(type='str'),
newschema=dict(type='str'),
db=dict(type='str', default='', aliases=['login_db', 'database']),
session_role=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
mutually_exclusive=[
['rename_to', 'data_type'],
['rename_to', 'increment'],
['rename_to', 'minvalue'],
['rename_to', 'maxvalue'],
['rename_to', 'start'],
['rename_to', 'cache'],
['rename_to', 'cycle'],
['rename_to', 'cascade'],
['rename_to', 'owner'],
['rename_to', 'newschema'],
['cascade', 'data_type'],
['cascade', 'increment'],
['cascade', 'minvalue'],
['cascade', 'maxvalue'],
['cascade', 'start'],
['cascade', 'cache'],
['cascade', 'cycle'],
['cascade', 'owner'],
['cascade', 'newschema'],
]
)
# Note: we don't need to check mutually exclusive params here, because they are
# checked automatically by AnsibleModule (mutually_exclusive=[] list above).
# Change autocommit to False if check_mode:
autocommit = not module.check_mode
# Connect to DB and make cursor object:
db_connection = connect_to_db(module, autocommit=autocommit)
cursor = db_connection.cursor(cursor_factory=DictCursor)
##############
# Create the object and do main job:
data = Sequence(module, cursor)
# Set defaults:
changed = False
# Create new sequence
if not data.exists and module.params['state'] == 'present':
if module.params.get('rename_to'):
module.fail_json(msg="Sequence '%s' does not exist, nothing to rename" % module.params['sequence'])
if module.params.get('newschema'):
module.fail_json(msg="Sequence '%s' does not exist, change of schema not possible" % module.params['sequence'])
changed = data.create()
# Drop non-existing sequence
elif not data.exists and module.params['state'] == 'absent':
# Nothing to do
changed = False
# Drop existing sequence
elif data.exists and module.params['state'] == 'absent':
changed = data.drop()
# Rename sequence
if data.exists and module.params.get('rename_to'):
if data.name != module.params['rename_to']:
changed = data.rename()
if changed:
data.new_name = module.params['rename_to']
# Refresh information
if module.params['state'] == 'present':
data.get_info()
# Change owner, schema and settings
if module.params['state'] == 'present' and data.exists:
# change owner
if module.params.get('owner'):
if data.owner != module.params['owner']:
changed = data.set_owner()
# Set schema
if module.params.get('newschema'):
if data.schema != module.params['newschema']:
changed = data.set_schema()
if changed:
data.new_schema = module.params['newschema']
# Rollback if it's possible and check_mode:
if module.check_mode:
db_connection.rollback()
else:
db_connection.commit()
cursor.close()
db_connection.close()
# Make return values:
kw = dict(
changed=changed,
state='present',
sequence=data.name,
queries=data.executed_queries,
schema=data.schema,
data_type=data.data_type,
increment=data.increment,
minvalue=data.minvalue,
maxvalue=data.maxvalue,
start=data.start_value,
cycle=data.cycle,
owner=data.owner,
)
if module.params['state'] == 'present':
if data.new_name:
kw['newname'] = data.new_name
if data.new_schema:
kw['newschema'] = data.new_schema
elif module.params['state'] == 'absent':
kw['state'] = 'absent'
module.exit_json(**kw)
if __name__ == '__main__':
main()

@ -837,6 +837,10 @@
- include: postgresql_copy.yml
when: postgres_version_resp.stdout is version('9.4', '>=')
# Test postgresql_sequence module
- include: postgresql_sequence.yml
when: postgres_version_resp.stdout is version('9.0', '>=')
# Test postgresql_ext.
# pg_extension system view is available from PG 9.1.
# The tests are restricted by Fedora because there will be errors related with

@ -0,0 +1,696 @@
# Copyright: (c) 2019, Tobias Birkefeld (@tcraxs) <t@craxs.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# Preparation for tests.
- name: postgresql_sequence - create DB
become_user: "{{ pg_user }}"
become: yes
postgresql_db:
state: present
name: "{{ db_name }}"
owner: "{{ db_user1 }}"
login_user: "{{ pg_user }}"
- name: postgresql_sequence - create a user to be owner of a database
become_user: "{{ pg_user }}"
become: yes
postgresql_user:
name: "{{ db_user1 }}"
state: present
encrypted: yes
password: password
role_attr_flags: LOGIN
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
- name: Create a user to be owner of a sequence
become_user: "{{ pg_user }}"
become: yes
postgresql_user:
name: "{{ db_user2 }}"
state: present
encrypted: yes
password: password
role_attr_flags: LOGIN
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
- name: postgresql_sequence - create a schema
become_user: "{{ pg_user }}"
become: yes
postgresql_schema:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
name: foobar_schema
####################
# Test: create sequence in checkmode
- name: postgresql_sequence - create a new seqeunce with name "foobar" in check_mode
become_user: "{{ pg_user }}"
become: yes
check_mode: yes
postgresql_sequence:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
name: foobar
register: result
# Checks
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.changed == True
- result.sequence == 'foobar'
- result.queries == ["CREATE SEQUENCE \"public\".\"foobar\""]
# Real SQL check
- name: postgresql_sequence - check that the new seqeunce "foobar" not exists
become: yes
become_user: "{{ pg_user }}"
postgresql_query:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
query: "SELECT sequence_name FROM information_schema.sequences WHERE sequence_name = 'foobar'"
register: result
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.rowcount == 0
- result.statusmessage == 'SELECT 0'
####################
# Test: create sequence
- name: postgresql_sequence - create a new seqeunce with name "foobar"
become_user: "{{ pg_user }}"
become: yes
postgresql_sequence:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
name: foobar
register: result
# Checks
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.changed == True
- result.sequence == 'foobar'
- result.queries == ["CREATE SEQUENCE \"public\".\"foobar\""]
# Real SQL check
- name: postgresql_sequence - check that the new seqeunce "foobar" exists
become_user: "{{ pg_user }}"
become: yes
postgresql_query:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
query: "SELECT sequence_name FROM information_schema.sequences WHERE sequence_name = 'foobar'"
register: result
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.rowcount == 1
####################
# Test: drop sequence in checkmode
- name: postgresql_sequence - drop a sequence called foobar
become_user: "{{ pg_user }}"
become: yes
check_mode: yes
postgresql_sequence:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
name: foobar
state: absent
register: result
# Checks
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.changed == True
- result.sequence == 'foobar'
- result.queries == ["DROP SEQUENCE \"public\".\"foobar\""]
# Real SQL check
- name: postgresql_sequence - check that the seqeunce "foobar" still exists
become_user: "{{ pg_user }}"
become: yes
postgresql_query:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
query: "SELECT sequence_name FROM information_schema.sequences WHERE sequence_name = 'foobar'"
register: result
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.rowcount == 1
####################
# Test: drop sequence
- name: postgresql_sequence - drop a sequence called foobar
become_user: "{{ pg_user }}"
become: yes
postgresql_sequence:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
name: foobar
state: absent
register: result
# Checks
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.changed == True
- result.sequence == 'foobar'
- result.queries == ["DROP SEQUENCE \"public\".\"foobar\""]
# Real SQL check
- name: postgresql_sequence - check that the seqeunce "foobar" not exists
become_user: "{{ pg_user }}"
become: yes
postgresql_query:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
query: "SELECT sequence_name FROM information_schema.sequences WHERE sequence_name = 'foobar'"
register: result
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.rowcount == 0
####################
# Test: drop nonexistent sequence
- name: postgresql_sequence - drop a sequence called foobar which does not exists
become_user: "{{ pg_user }}"
become: yes
postgresql_sequence:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
name: foobar
state: absent
register: result
# Checks
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.changed == False
- result.sequence == 'foobar'
- result.queries == []
# Real SQL check
- name: postgresql_sequence - check that the seqeunce "foobar" not exists
become_user: "{{ pg_user }}"
become: yes
postgresql_query:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
query: "SELECT sequence_name FROM information_schema.sequences WHERE sequence_name = 'foobar'"
register: result
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.rowcount == 0
####################
# Test: create sequence with options
- name: postgresql_sequence - create an descending sequence called foobar_desc, starting at 101 and which cycle between 1 to 1000
become_user: "{{ pg_user }}"
become: yes
postgresql_sequence:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
name: foobar_desc
increment: -1
start: 101
minvalue: 1
maxvalue: 1000
cycle: yes
register: result
# Checks
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.changed == True
- result.sequence == 'foobar_desc'
- result.increment == '-1'
- result.minvalue == '1'
- result.maxvalue == '1000'
- result.cycle == 'YES'
- result.queries == ["CREATE SEQUENCE \"public\".\"foobar_desc\" INCREMENT BY -1 MINVALUE 1 MAXVALUE 1000 START WITH 101 CYCLE"]
# Real SQL check
- name: postgresql_sequence - check that the new seqeunce "foobar_desc" exists
postgresql_query:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
query: "SELECT sequence_name FROM information_schema.sequences WHERE sequence_name = 'foobar_desc'"
register: result
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.rowcount == 1
####################
# Test: rename a sequence in checkmode
- name: postgresql_sequence - rename an existing sequence named foobar_desc to foobar_with_options
become_user: "{{ pg_user }}"
become: yes
check_mode: yes
postgresql_sequence:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
name: foobar_desc
rename_to: foobar_with_options
register: result
# Checks
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.changed == True
- result.sequence == 'foobar_desc'
- result.newname == 'foobar_with_options'
- result.queries == ["ALTER SEQUENCE \"public\".\"foobar_desc\" RENAME TO \"foobar_with_options\""]
# Real SQL check
- name: postgresql_sequence - check that the seqeunce "foobar_desc" still exists and is not renamed
become_user: "{{ pg_user }}"
become: yes
postgresql_query:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
query: "SELECT sequence_name FROM information_schema.sequences WHERE sequence_name = 'foobar_desc'"
register: result
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.rowcount == 1
####################
# Test: rename a sequence
- name: postgresql_sequence - rename an existing sequence named foobar_desc to foobar_with_options
become_user: "{{ pg_user }}"
become: yes
postgresql_sequence:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
name: foobar_desc
rename_to: foobar_with_options
register: result
# Checks
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.changed == True
- result.sequence == 'foobar_desc'
- result.newname == 'foobar_with_options'
- result.queries == ["ALTER SEQUENCE \"public\".\"foobar_desc\" RENAME TO \"foobar_with_options\""]
# Real SQL check
- name: postgresql_sequence - check that the renamed seqeunce "foobar_with_options" exists
become_user: "{{ pg_user }}"
become: yes
postgresql_query:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
query: "SELECT sequence_name FROM information_schema.sequences WHERE sequence_name = 'foobar_with_options'"
register: result
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.rowcount == 1
####################
# Test: change schema of a sequence in checkmode
- name: postgresql_sequence - change schema of an existing sequence from public to foobar_schema
become_user: "{{ pg_user }}"
become: yes
check_mode: yes
postgresql_sequence:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
name: foobar_with_options
newschema: foobar_schema
register: result
# Checks
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.changed == True
- result.sequence == 'foobar_with_options'
- result.schema == 'public'
- result.newschema == 'foobar_schema'
- result.queries == ["ALTER SEQUENCE \"public\".\"foobar_with_options\" SET SCHEMA \"foobar_schema\""]
# Real SQL check
- name: postgresql_sequence - check that the seqeunce "foobar_with_options" still exists in the old schema
become_user: "{{ pg_user }}"
become: yes
postgresql_query:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
query: "SELECT sequence_name,sequence_schema FROM information_schema.sequences WHERE sequence_name = 'foobar_with_options' AND sequence_schema = 'public'"
register: result
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.rowcount == 1
####################
# Test: change schema of a sequence
- name: postgresql_sequence - change schema of an existing sequence from public to foobar_schema
become_user: "{{ pg_user }}"
become: yes
postgresql_sequence:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
name: foobar_with_options
newschema: foobar_schema
register: result
# Checks
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.changed == True
- result.sequence == 'foobar_with_options'
- result.schema == 'public'
- result.newschema == 'foobar_schema'
- result.queries == ["ALTER SEQUENCE \"public\".\"foobar_with_options\" SET SCHEMA \"foobar_schema\""]
# Real SQL check
- name: postgresql_sequence - check that the seqeunce "foobar_with_options" exists in new schema
become_user: "{{ pg_user }}"
become: yes
postgresql_query:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
query: "SELECT sequence_name,sequence_schema FROM information_schema.sequences WHERE sequence_name = 'foobar_with_options' AND sequence_schema = 'foobar_schema'"
register: result
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.rowcount == 1
####################
# Test: change owner of a sequence in checkmode
- name: postgresql_sequence - change owner of an existing sequence from "{{ pg_user }}" to "{{ db_user1 }}"
become_user: "{{ pg_user }}"
become: yes
check_mode: yes
postgresql_sequence:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
name: foobar_with_options
schema: foobar_schema
owner: "{{ db_user1 }}"
register: result
# Checks
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.changed == True
- result.sequence == 'foobar_with_options'
- result.owner == "{{ pg_user }}"
- result.queries == ["ALTER SEQUENCE \"foobar_schema\".\"foobar_with_options\" OWNER TO \"{{ db_user1 }}\""]
# Real SQL check
- name: postgresql_sequence - check that the seqeunce "foobar_with_options" has still the old owner
become_user: "{{ pg_user }}"
become: yes
postgresql_query:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
query: "SELECT c.relname,a.rolname,n.nspname
FROM pg_class as c
JOIN pg_authid as a on (c.relowner = a.oid)
JOIN pg_namespace as n on (c.relnamespace = n.oid)
WHERE c.relkind = 'S' and
c.relname = 'foobar_with_options' and
n.nspname = 'foobar_schema' and
a.rolname = '{{ pg_user }}'"
register: result
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.rowcount == 1
####################
# Test: change owner of a sequence
- name: postgresql_sequence - change owner of an existing sequence from "{{ pg_user }}" to "{{ db_user1 }}"
become_user: "{{ pg_user }}"
become: yes
postgresql_sequence:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
name: foobar_with_options
schema: foobar_schema
owner: "{{ db_user1 }}"
register: result
# Checks
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.changed == True
- result.sequence == 'foobar_with_options'
- result.owner == "{{ pg_user }}"
- result.queries == ["ALTER SEQUENCE \"foobar_schema\".\"foobar_with_options\" OWNER TO \"{{ db_user1 }}\""]
# Real SQL check
- name: postgresql_sequence - check that the seqeunce "foobar_with_options" has a new owner
become_user: "{{ pg_user }}"
become: yes
postgresql_query:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
query: "SELECT c.relname,a.rolname,n.nspname
FROM pg_class as c
JOIN pg_authid as a on (c.relowner = a.oid)
JOIN pg_namespace as n on (c.relnamespace = n.oid)
WHERE c.relkind = 'S' and
c.relname = 'foobar_with_options' and
n.nspname = 'foobar_schema' and
a.rolname = '{{ db_user1 }}'"
register: result
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.rowcount == 1
####################
# Test: drop seqeunce with cascade
# CREATE SEQUENCE seq1;
# CREATE TABLE t1 (f1 INT NOT NULL DEFAULT nextval('seq1'));
# DROP SEQUENCE seq1 CASCADE;
- name: postgresql_sequence - create sequence for drop cascade test
become_user: "{{ pg_user }}"
become: yes
postgresql_sequence:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
name: seq1
- name: postgresql_sequence - create table which use seqeunce for drop cascade test
become_user: "{{ pg_user }}"
become: yes
postgresql_table:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
name: t1
columns:
- f1 INT NOT NULL DEFAULT nextval('seq1')
####################
# Test: drop seqeunce with cascade in checkmode
- name: postgresql_sequence - drop with cascade a sequence called seq1
become_user: "{{ pg_user }}"
become: yes
check_mode: yes
postgresql_sequence:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
name: seq1
state: absent
cascade: yes
register: result
# Checks
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.changed == True
- result.sequence == 'seq1'
- result.queries == ["DROP SEQUENCE \"public\".\"seq1\" CASCADE"]
# Real SQL check
- name: postgresql_sequence - check that the seqeunce "seq1" still exists
become_user: "{{ pg_user }}"
become: yes
postgresql_query:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
query: "SELECT sequence_name FROM information_schema.sequences WHERE sequence_name = 'seq1'"
register: result
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.rowcount == 1
####################
# Test: drop seqeunce with cascade
- name: postgresql_sequence - drop with cascade a sequence called seq1
become_user: "{{ pg_user }}"
become: yes
postgresql_sequence:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
name: seq1
state: absent
cascade: yes
register: result
# Checks
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.changed == True
- result.sequence == 'seq1'
- result.queries == ["DROP SEQUENCE \"public\".\"seq1\" CASCADE"]
# Real SQL check
- name: postgresql_sequence - check that the seqeunce "seq1" not exists
become_user: "{{ pg_user }}"
become: yes
postgresql_query:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
query: "SELECT sequence_name FROM information_schema.sequences WHERE sequence_name = 'seq1'"
register: result
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.rowcount == 0
####################
# Test: create sequence with owner in checkmode
- name: postgresql_sequence - create a new seqeunce with name "foobar2" with owner "{{ db_user2 }}"
become_user: "{{ pg_user }}"
become: yes
check_mode: yes
postgresql_sequence:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
name: foobar2
owner: "{{ db_user2 }}"
register: result
# Checks
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.changed == True
- result.sequence == 'foobar2'
- result.queries == ["CREATE SEQUENCE \"public\".\"foobar2\"", "ALTER SEQUENCE \"public\".\"foobar2\" OWNER TO \"ansible_db_user2\""]
# Real SQL check
- name: postgresql_sequence - check that the new seqeunce "foobar2" does not exists
become_user: "{{ pg_user }}"
become: yes
postgresql_query:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
query: "SELECT sequence_name FROM information_schema.sequences WHERE sequence_name = 'foobar2'"
register: result
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.rowcount == 0
####################
# Test: create sequence with owner
- name: postgresql_sequence - create a new seqeunce with name "foobar2" with owner "{{ db_user2 }}"
become_user: "{{ pg_user }}"
become: yes
postgresql_sequence:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
name: foobar2
owner: "{{ db_user2 }}"
register: result
# Checks
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.changed == True
- result.sequence == 'foobar2'
- result.queries == ["CREATE SEQUENCE \"public\".\"foobar2\"", "ALTER SEQUENCE \"public\".\"foobar2\" OWNER TO \"ansible_db_user2\""]
# Real SQL check
- name: postgresql_sequence - check that the new seqeunce "foobar2" exists
become_user: "{{ pg_user }}"
become: yes
postgresql_query:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
query: "SELECT sequence_name FROM information_schema.sequences WHERE sequence_name = 'foobar2'"
register: result
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.rowcount == 1
- name: postgresql_sequence - check that the seqeunce "foobar2" has owner "{{ db_user2 }}"
become_user: "{{ pg_user }}"
become: yes
postgresql_query:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
query: "SELECT c.relname,a.rolname,n.nspname
FROM pg_class as c
JOIN pg_authid as a on (c.relowner = a.oid)
JOIN pg_namespace as n on (c.relnamespace = n.oid)
WHERE c.relkind = 'S' and
c.relname = 'foobar2' and
n.nspname = 'public' and
a.rolname = '{{ db_user2 }}'"
register: result
- name: postgresql_sequence - check with assert the output
assert:
that:
- result.rowcount == 1
# Cleanup
- name: postgresql_sequence - destroy DB
become_user: "{{ pg_user }}"
become: yes
postgresql_db:
state: absent
name: "{{ db_name }}"
login_user: "{{ pg_user }}"
Loading…
Cancel
Save