def test_autocommit_true(self, m_ansible_module, monkeypatch, m_psycopg2): """ Test connect_to_db(), autocommit arg passed as True (the default is False). """ monkeypatch.setattr(pg, 'HAS_PSYCOPG2', True) # case 1: psycopg2.__version >= 2.4.2 (the default in m_psycopg2) monkeypatch.setattr(pg, 'psycopg2', m_psycopg2) conn_params = pg.get_conn_params(m_ansible_module, m_ansible_module.params) db_connection = pg.connect_to_db(m_ansible_module, conn_params, autocommit=True) cursor = db_connection.cursor() # if errors, db_connection returned as None: assert isinstance(db_connection, DbConnection) assert isinstance(cursor, Cursor) assert m_ansible_module.err_msg == '' # case 2: psycopg2.__version < 2.4.2 m_psycopg2.__version__ = '2.4.1' monkeypatch.setattr(pg, 'psycopg2', m_psycopg2) conn_params = pg.get_conn_params(m_ansible_module, m_ansible_module.params) db_connection = pg.connect_to_db(m_ansible_module, conn_params, autocommit=True) cursor = db_connection.cursor() # if errors, db_connection returned as None: assert isinstance(db_connection, DbConnection) assert isinstance(cursor, Cursor) assert 'psycopg2 must be at least 2.4.3' in m_ansible_module.err_msg
def main(): argument_spec = postgres_common_argument_spec() argument_spec.update(db=dict(type='str', aliases=['login_db']), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) # Set some default values: cursor = False db_connection = False result = dict( changed=False, is_available=False, server_version=dict(), ) conn_params = get_conn_params(module, module.params, warn_db_default=False) db_connection = connect_to_db(module, conn_params, fail_on_conn=False) if db_connection is not None: cursor = db_connection.cursor(cursor_factory=DictCursor) # Do job: pg_ping = PgPing(module, cursor) if cursor: # If connection established: result["is_available"], result["server_version"] = pg_ping.do() db_connection.rollback() module.exit_json(**result)
def main(): argument_spec = postgres_common_argument_spec() argument_spec.update( db=dict(type='str', aliases=['login_db']), filter=dict(type='list', elements='str'), session_role=dict(type='str'), schema=dict(type='str'), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) filter_ = module.params["filter"] schema = module.params["schema"] # Connect to DB and make cursor object: pg_conn_params = get_conn_params(module, module.params) # We don't need to commit anything, so, set it to False: db_connection = connect_to_db(module, pg_conn_params, autocommit=False) cursor = db_connection.cursor(cursor_factory=DictCursor) ############################ # Create object and do work: pg_obj_info = PgUserObjStatInfo(module, cursor) info_dict = pg_obj_info.collect(filter_, schema) # Clean up: cursor.close() db_connection.close() # Return information: module.exit_json(**info_dict)
def main(): argument_spec = postgres_common_argument_spec() argument_spec.update( groups=dict(type='list', elements='str', required=True, aliases=['group', 'source_role', 'source_roles']), target_roles=dict(type='list', elements='str', required=True, aliases=['target_role', 'user', 'users']), fail_on_role=dict(type='bool', default=True), state=dict(type='str', default='present', choices=['absent', 'present']), db=dict(type='str', aliases=['login_db']), session_role=dict(type='str'), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) groups = module.params['groups'] target_roles = module.params['target_roles'] fail_on_role = module.params['fail_on_role'] state = module.params['state'] conn_params = get_conn_params(module, module.params, warn_db_default=False) db_connection = connect_to_db(module, conn_params, autocommit=False) cursor = db_connection.cursor(cursor_factory=DictCursor) ############## # Create the object and do main job: pg_membership = PgMembership(module, cursor, groups, target_roles, fail_on_role) if state == 'present': pg_membership.grant() elif state == 'absent': pg_membership.revoke() # 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: return_dict = dict( changed=pg_membership.changed, state=state, groups=pg_membership.groups, target_roles=pg_membership.target_roles, queries=pg_membership.executed_queries, ) if state == 'present': return_dict['granted'] = pg_membership.granted elif state == 'absent': return_dict['revoked'] = pg_membership.revoked module.exit_json(**return_dict)
def connect(self): """Connect to a PostgreSQL database and return a cursor object. Note: connection parameters are passed by self.module object. """ conn_params = get_conn_params(self.module, self.module.params, warn_db_default=False) self.db_conn = connect_to_db(self.module, conn_params) return self.db_conn.cursor(cursor_factory=DictCursor)
def main(): argument_spec = postgres_common_argument_spec() argument_spec.update( new_owner=dict(type='str', required=True), obj_name=dict(type='str'), obj_type=dict(type='str', aliases=['type'], choices=[ 'database', 'function', 'matview', 'sequence', 'schema', 'table', 'tablespace', 'view']), reassign_owned_by=dict(type='list', elements='str'), fail_on_role=dict(type='bool', default=True), db=dict(type='str', aliases=['login_db']), session_role=dict(type='str'), ) module = AnsibleModule( argument_spec=argument_spec, mutually_exclusive=[ ['obj_name', 'reassign_owned_by'], ['obj_type', 'reassign_owned_by'], ['obj_name', 'fail_on_role'], ['obj_type', 'fail_on_role'], ], supports_check_mode=True, ) new_owner = module.params['new_owner'] obj_name = module.params['obj_name'] obj_type = module.params['obj_type'] reassign_owned_by = module.params['reassign_owned_by'] fail_on_role = module.params['fail_on_role'] conn_params = get_conn_params(module, module.params) db_connection = connect_to_db(module, conn_params, autocommit=False) cursor = db_connection.cursor(cursor_factory=DictCursor) ############## # Create the object and do main job: pg_ownership = PgOwnership(module, cursor, new_owner) # if we want to change ownership: if obj_name: pg_ownership.set_owner(obj_type, obj_name) # if we want to reassign objects owned by roles: elif reassign_owned_by: pg_ownership.reassign(reassign_owned_by, fail_on_role) # Rollback if it's possible and check_mode: if module.check_mode: db_connection.rollback() else: db_connection.commit() cursor.close() db_connection.close() module.exit_json( changed=pg_ownership.changed, queries=pg_ownership.executed_queries, )
def test_connect_to_db(self, m_ansible_module, monkeypatch, m_psycopg2): """Test connect_to_db(), common test.""" monkeypatch.setattr(pg, 'HAS_PSYCOPG2', True) monkeypatch.setattr(pg, 'psycopg2', m_psycopg2) conn_params = pg.get_conn_params(m_ansible_module, m_ansible_module.params) db_connection = pg.connect_to_db(m_ansible_module, conn_params) cursor = db_connection.cursor() # if errors, db_connection returned as None: assert isinstance(db_connection, DbConnection) assert isinstance(cursor, Cursor) assert m_ansible_module.err_msg == '' # The default behaviour, normal in this case: assert 'Database name has not been passed' in m_ansible_module.warn_msg
def test_fail_on_conn_true(self, m_ansible_module, monkeypatch, m_psycopg2): """ Test connect_to_db(), fail_on_conn arg passed as True (the default behavior). """ monkeypatch.setattr(pg, 'HAS_PSYCOPG2', True) monkeypatch.setattr(pg, 'psycopg2', m_psycopg2) m_ansible_module.params['login_user'] = '******' # causes Exception conn_params = pg.get_conn_params(m_ansible_module, m_ansible_module.params) db_connection = pg.connect_to_db(m_ansible_module, conn_params, fail_on_conn=True) assert 'unable to connect to database' in m_ansible_module.err_msg assert db_connection is None
def test_fail_on_conn_false(self, m_ansible_module, monkeypatch, m_psycopg2): """ Test connect_to_db(), fail_on_conn arg passed as False. """ monkeypatch.setattr(pg, 'HAS_PSYCOPG2', True) monkeypatch.setattr(pg, 'psycopg2', m_psycopg2) m_ansible_module.params['login_user'] = '******' # causes Exception conn_params = pg.get_conn_params(m_ansible_module, m_ansible_module.params) db_connection = pg.connect_to_db(m_ansible_module, conn_params, fail_on_conn=False) assert m_ansible_module.err_msg == '' assert 'PostgreSQL server is unavailable' in m_ansible_module.warn_msg assert db_connection is None
def main(): argument_spec = postgres_common_argument_spec() argument_spec.update( db=dict(type="str", aliases=["login_db"]), name=dict(type="str", required=True, aliases=["slot_name"]), slot_type=dict(type="str", default="physical", choices=["logical", "physical"]), immediately_reserve=dict(type="bool", default=False), session_role=dict(type="str"), output_plugin=dict(type="str", default="test_decoding"), state=dict(type="str", default="present", choices=["absent", "present"]), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) name = module.params["name"] slot_type = module.params["slot_type"] immediately_reserve = module.params["immediately_reserve"] state = module.params["state"] output_plugin = module.params["output_plugin"] if immediately_reserve and slot_type == 'logical': module.fail_json(msg="Module parameters immediately_reserve and slot_type=logical are mutually exclusive") # When slot_type is logical and parameter db is not passed, # the default database will be used to create the slot and # the user should know about this. # When the slot type is physical, # it doesn't matter which database will be used # because physical slots are global objects. if slot_type == 'logical': warn_db_default = True else: warn_db_default = False conn_params = get_conn_params(module, module.params, warn_db_default=warn_db_default) db_connection = connect_to_db(module, conn_params, autocommit=True) cursor = db_connection.cursor(cursor_factory=DictCursor) ################################## # Create an object and do main job pg_slot = PgSlot(module, cursor, name) changed = False if module.check_mode: if state == "present": if not pg_slot.exists: changed = True pg_slot.create(slot_type, immediately_reserve, output_plugin, just_check=True) elif state == "absent": if pg_slot.exists: changed = True else: if state == "absent": pg_slot.drop() elif state == "present": pg_slot.create(slot_type, immediately_reserve, output_plugin) changed = pg_slot.changed db_connection.close() module.exit_json(changed=changed, name=name, queries=pg_slot.executed_queries)
def main(): argument_spec = postgres_common_argument_spec() argument_spec.update( query=dict(type='str'), db=dict(type='str', aliases=['login_db']), positional_args=dict(type='list', elements='raw'), named_args=dict(type='dict'), session_role=dict(type='str'), path_to_script=dict(type='path'), autocommit=dict(type='bool', default=False), encoding=dict(type='str'), trust_input=dict(type='bool', default=True), search_path=dict(type='list', elements='str'), ) module = AnsibleModule( argument_spec=argument_spec, mutually_exclusive=(('positional_args', 'named_args'), ), supports_check_mode=True, ) query = module.params["query"] positional_args = module.params["positional_args"] named_args = module.params["named_args"] path_to_script = module.params["path_to_script"] autocommit = module.params["autocommit"] encoding = module.params["encoding"] session_role = module.params["session_role"] trust_input = module.params["trust_input"] search_path = module.params["search_path"] if not trust_input: # Check input for potentially dangerous elements: check_input(module, session_role) if autocommit and module.check_mode: module.fail_json( msg="Using autocommit is mutually exclusive with check_mode") if path_to_script and query: module.fail_json(msg="path_to_script is mutually exclusive with query") if positional_args: positional_args = convert_elements_to_pg_arrays(positional_args) elif named_args: named_args = convert_elements_to_pg_arrays(named_args) query_list = [] if path_to_script: try: with open(path_to_script, 'rb') as f: query = to_native(f.read()) if ';' in query: query_list = [q for q in query.split(';') if q != '\n'] else: query_list.append(query) except Exception as e: module.fail_json(msg="Cannot read file '%s' : %s" % (path_to_script, to_native(e))) else: query_list.append(query) conn_params = get_conn_params(module, module.params) db_connection = connect_to_db(module, conn_params, autocommit=autocommit) if encoding is not None: db_connection.set_client_encoding(encoding) cursor = db_connection.cursor(cursor_factory=DictCursor) if search_path: set_search_path(cursor, '%s' % ','.join([x.strip(' ') for x in search_path])) # Prepare args: if module.params.get("positional_args"): arguments = module.params["positional_args"] elif module.params.get("named_args"): arguments = module.params["named_args"] else: arguments = None # Set defaults: changed = False query_all_results = [] rowcount = 0 statusmessage = '' # Execute query: for query in query_list: try: cursor.execute(query, arguments) statusmessage = cursor.statusmessage if cursor.rowcount > 0: rowcount += cursor.rowcount try: query_result = [dict(row) for row in cursor.fetchall()] except Psycopg2ProgrammingError as e: if to_native(e) == 'no results to fetch': query_result = {} except Exception as e: module.fail_json(msg="Cannot fetch rows from cursor: %s" % to_native(e)) query_all_results.append(query_result) if 'SELECT' not in statusmessage: if 'UPDATE' in statusmessage or 'INSERT' in statusmessage or 'DELETE' in statusmessage: s = statusmessage.split() if len(s) == 3: if s[2] != '0': changed = True elif len(s) == 2: if s[1] != '0': changed = True else: changed = True else: changed = True except Exception as e: if not autocommit: db_connection.rollback() cursor.close() db_connection.close() module.fail_json( msg="Cannot execute SQL '%s' %s: %s, query list: %s" % (query, arguments, to_native(e), query_list)) if module.check_mode: db_connection.rollback() else: if not autocommit: db_connection.commit() kw = dict( changed=changed, query=cursor.query, query_list=query_list, statusmessage=statusmessage, query_result=query_result, query_all_results=query_all_results, rowcount=rowcount, ) cursor.close() db_connection.close() module.exit_json(**kw)
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', default=False), schema=dict(type='str', default='public'), cascade=dict(type='bool', default=False), 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: conn_params = get_conn_params(module, module.params) db_connection = connect_to_db(module, conn_params, 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)
def main(): argument_spec = postgres_common_argument_spec() argument_spec.update( name=dict(required=True), db=dict(type='str', aliases=['login_db']), state=dict(type='str', default='present', choices=['absent', 'present']), tables=dict(type='list', elements='str'), parameters=dict(type='dict'), owner=dict(type='str'), cascade=dict(type='bool', default=False), session_role=dict(type='str'), trust_input=dict(type='bool', default=True), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) # Parameters handling: name = module.params['name'] state = module.params['state'] tables = module.params['tables'] params = module.params['parameters'] owner = module.params['owner'] cascade = module.params['cascade'] session_role = module.params['session_role'] trust_input = module.params['trust_input'] if not trust_input: # Check input for potentially dangerous elements: if not params: params_list = None else: params_list = ['%s = %s' % (k, v) for k, v in iteritems(params)] check_input(module, name, tables, owner, session_role, params_list) if state == 'absent': if tables: module.warn('parameter "tables" is ignored when "state=absent"') if params: module.warn('parameter "parameters" is ignored when "state=absent"') if owner: module.warn('parameter "owner" is ignored when "state=absent"') if state == 'present' and cascade: module.warn('parameter "cascade" is ignored when "state=present"') # Connect to DB and make cursor object: conn_params = get_conn_params(module, module.params) # We check publication state without DML queries execution, so set autocommit: db_connection = connect_to_db(module, conn_params, autocommit=True) cursor = db_connection.cursor(cursor_factory=DictCursor) # Check version: if cursor.connection.server_version < SUPPORTED_PG_VERSION: module.fail_json(msg="PostgreSQL server version should be 10.0 or greater") # Nothing was changed by default: changed = False ################################### # Create object and do rock'n'roll: publication = PgPublication(module, cursor, name) if tables: tables = transform_tables_representation(tables) # If module.check_mode=True, nothing will be changed: if state == 'present': if not publication.exists: changed = publication.create(tables, params, owner, check_mode=module.check_mode) else: changed = publication.update(tables, params, owner, check_mode=module.check_mode) elif state == 'absent': changed = publication.drop(cascade=cascade, check_mode=module.check_mode) # Get final publication info: pub_fin_info = {} if state == 'present' or (state == 'absent' and module.check_mode): pub_fin_info = publication.get_info() elif state == 'absent' and not module.check_mode: publication.exists = False # Connection is not needed any more: cursor.close() db_connection.close() # Update publication info and return ret values: module.exit_json(changed=changed, queries=publication.executed_queries, exists=publication.exists, **pub_fin_info)
def main(): argument_spec = postgres_common_argument_spec() argument_spec.update(db=dict(type="str", required=True, aliases=["login_db"]), lang=dict(type="str", required=True, aliases=["name"]), state=dict(type="str", default="present", choices=["absent", "present"]), trust=dict(type="bool", default="no"), force_trust=dict(type="bool", default="no"), cascade=dict(type="bool", default="no"), fail_on_drop=dict(type="bool", default="yes"), session_role=dict(type="str"), owner=dict(type="str"), trust_input=dict(type="bool", default="yes")) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) db = module.params["db"] lang = module.params["lang"] state = module.params["state"] trust = module.params["trust"] force_trust = module.params["force_trust"] cascade = module.params["cascade"] fail_on_drop = module.params["fail_on_drop"] owner = module.params["owner"] session_role = module.params["session_role"] trust_input = module.params["trust_input"] if not trust_input: # Check input for potentially dangerous elements: check_input(module, lang, session_role, owner) conn_params = get_conn_params(module, module.params) db_connection = connect_to_db(module, conn_params, autocommit=False) cursor = db_connection.cursor() changed = False kw = {'db': db, 'lang': lang, 'trust': trust} if state == "present": if lang_exists(cursor, lang): lang_trusted = lang_istrusted(cursor, lang) if (lang_trusted and not trust) or (not lang_trusted and trust): if module.check_mode: changed = True else: changed = lang_altertrust(cursor, lang, trust) else: if module.check_mode: changed = True else: changed = lang_add(cursor, lang, trust) if force_trust: changed = lang_altertrust(cursor, lang, trust) else: if lang_exists(cursor, lang): if module.check_mode: changed = True kw['lang_dropped'] = True else: changed = lang_drop(cursor, lang, cascade) if fail_on_drop and not changed: msg = ( "unable to drop language, use cascade " "to delete dependencies or fail_on_drop=no to ignore") module.fail_json(msg=msg) kw['lang_dropped'] = changed if owner and state == 'present': if lang_exists(cursor, lang): if owner != get_lang_owner(cursor, lang): changed = set_lang_owner(cursor, lang, owner) if changed: if module.check_mode: db_connection.rollback() else: db_connection.commit() kw['changed'] = changed kw['queries'] = executed_queries db_connection.close() module.exit_json(**kw)
def main(): argument_spec = postgres_common_argument_spec() argument_spec.update( user=dict(type='str', required=True, aliases=['name']), password=dict(type='str', default=None, no_log=True), state=dict(type='str', default='present', choices=['absent', 'present']), priv=dict(type='str', default=None), db=dict(type='str', default='', aliases=['login_db']), fail_on_user=dict(type='bool', default='yes', aliases=['fail_on_role']), role_attr_flags=dict(type='str', default=''), encrypted=dict(type='bool', default='yes'), no_password_changes=dict(type='bool', default='no', no_log=False), expires=dict(type='str', default=None), conn_limit=dict(type='int', default=None), session_role=dict(type='str'), groups=dict(type='list', elements='str'), comment=dict(type='str', default=None), trust_input=dict(type='bool', default=True), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True ) user = module.params["user"] password = module.params["password"] state = module.params["state"] fail_on_user = module.params["fail_on_user"] if module.params['db'] == '' and module.params["priv"] is not None: module.fail_json(msg="privileges require a database to be specified") privs = parse_privs(module.params["priv"], module.params["db"]) no_password_changes = module.params["no_password_changes"] if module.params["encrypted"]: encrypted = "ENCRYPTED" else: encrypted = "UNENCRYPTED" expires = module.params["expires"] conn_limit = module.params["conn_limit"] role_attr_flags = module.params["role_attr_flags"] groups = module.params["groups"] if groups: groups = [e.strip() for e in groups] comment = module.params["comment"] session_role = module.params['session_role'] trust_input = module.params['trust_input'] if not trust_input: # Check input for potentially dangerous elements: check_input(module, user, password, privs, expires, role_attr_flags, groups, comment, session_role) conn_params = get_conn_params(module, module.params, warn_db_default=False) db_connection = connect_to_db(module, conn_params) cursor = db_connection.cursor(cursor_factory=DictCursor) try: role_attr_flags = parse_role_attrs(cursor, role_attr_flags) except InvalidFlagsError as e: module.fail_json(msg=to_native(e), exception=traceback.format_exc()) kw = dict(user=user) changed = False user_removed = False if state == "present": if user_exists(cursor, user): try: changed = user_alter(db_connection, module, user, password, role_attr_flags, encrypted, expires, no_password_changes, conn_limit) except SQLParseError as e: module.fail_json(msg=to_native(e), exception=traceback.format_exc()) else: try: changed = user_add(cursor, user, password, role_attr_flags, encrypted, expires, conn_limit) except psycopg2.ProgrammingError as e: module.fail_json(msg="Unable to add user with given requirement " "due to : %s" % to_native(e), exception=traceback.format_exc()) except SQLParseError as e: module.fail_json(msg=to_native(e), exception=traceback.format_exc()) try: changed = grant_privileges(cursor, user, privs) or changed except SQLParseError as e: module.fail_json(msg=to_native(e), exception=traceback.format_exc()) if groups: target_roles = [] target_roles.append(user) pg_membership = PgMembership(module, cursor, groups, target_roles) changed = pg_membership.grant() or changed executed_queries.extend(pg_membership.executed_queries) if comment is not None: try: changed = add_comment(cursor, user, comment) or changed except Exception as e: module.fail_json(msg='Unable to add comment on role: %s' % to_native(e), exception=traceback.format_exc()) else: if user_exists(cursor, user): if module.check_mode: changed = True kw['user_removed'] = True else: try: changed = revoke_privileges(cursor, user, privs) user_removed = user_delete(cursor, user) except SQLParseError as e: module.fail_json(msg=to_native(e), exception=traceback.format_exc()) changed = changed or user_removed if fail_on_user and not user_removed: msg = "Unable to remove user" module.fail_json(msg=msg) kw['user_removed'] = user_removed if changed: if module.check_mode: db_connection.rollback() else: db_connection.commit() kw['changed'] = changed kw['queries'] = executed_queries module.exit_json(**kw)
def main(): argument_spec = postgres_common_argument_spec() argument_spec.update( idxname=dict(type='str', required=True, aliases=['name']), db=dict(type='str', aliases=['login_db']), state=dict(type='str', default='present', choices=['absent', 'present']), concurrent=dict(type='bool', default=True), unique=dict(type='bool', default=False), table=dict(type='str'), idxtype=dict(type='str', aliases=['type']), columns=dict(type='list', elements='str', aliases=['column']), cond=dict(type='str'), session_role=dict(type='str'), tablespace=dict(type='str'), storage_params=dict(type='list', elements='str'), cascade=dict(type='bool', default=False), schema=dict(type='str'), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) idxname = module.params["idxname"] state = module.params["state"] concurrent = module.params["concurrent"] unique = module.params["unique"] table = module.params["table"] idxtype = module.params["idxtype"] columns = module.params["columns"] cond = module.params["cond"] tablespace = module.params["tablespace"] storage_params = module.params["storage_params"] cascade = module.params["cascade"] schema = module.params["schema"] if concurrent and cascade: module.fail_json(msg="Concurrent mode and cascade parameters are mutually exclusive") if unique and (idxtype and idxtype != 'btree'): module.fail_json(msg="Only btree currently supports unique indexes") if state == 'present': if not table: module.fail_json(msg="Table must be specified") if not columns: module.fail_json(msg="At least one column must be specified") else: if table or columns or cond or idxtype or tablespace: module.fail_json(msg="Index %s is going to be removed, so it does not " "make sense to pass a table name, columns, conditions, " "index type, or tablespace" % idxname) if cascade and state != 'absent': module.fail_json(msg="cascade parameter used only with state=absent") conn_params = get_conn_params(module, module.params) db_connection = connect_to_db(module, conn_params, autocommit=True) cursor = db_connection.cursor(cursor_factory=DictCursor) # Set defaults: changed = False # Do job: index = Index(module, cursor, schema, idxname) kw = index.get_info() kw['query'] = '' # # check_mode start if module.check_mode: if state == 'present' and index.exists: kw['changed'] = False module.exit_json(**kw) elif state == 'present' and not index.exists: kw['changed'] = True module.exit_json(**kw) elif state == 'absent' and not index.exists: kw['changed'] = False module.exit_json(**kw) elif state == 'absent' and index.exists: kw['changed'] = True module.exit_json(**kw) # check_mode end # if state == "present": if idxtype and idxtype.upper() not in VALID_IDX_TYPES: module.fail_json(msg="Index type '%s' of %s is not in valid types" % (idxtype, idxname)) columns = ','.join(columns) if storage_params: storage_params = ','.join(storage_params) changed = index.create(table, idxtype, columns, cond, tablespace, storage_params, concurrent, unique) if changed: kw = index.get_info() kw['state'] = 'present' kw['query'] = index.executed_query else: changed = index.drop(schema, cascade, concurrent) if changed: kw['state'] = 'absent' kw['query'] = index.executed_query if not kw['valid']: db_connection.rollback() module.warn("Index %s is invalid! ROLLBACK" % idxname) if not concurrent: db_connection.commit() kw['changed'] = changed db_connection.close() module.exit_json(**kw)
def main(): argument_spec = postgres_common_argument_spec() argument_spec.update( name=dict(type='str', required=True), db=dict(type='str', required=True, aliases=['login_db']), state=dict(type='str', default='present', choices=['absent', 'present', 'refresh']), publications=dict(type='list', elements='str'), connparams=dict(type='dict'), cascade=dict(type='bool', default=False), owner=dict(type='str'), subsparams=dict(type='dict'), session_role=dict(type='str'), trust_input=dict(type='bool', default=True), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) # Parameters handling: db = module.params['db'] name = module.params['name'] state = module.params['state'] publications = module.params['publications'] cascade = module.params['cascade'] owner = module.params['owner'] subsparams = module.params['subsparams'] connparams = module.params['connparams'] session_role = module.params['session_role'] trust_input = module.params['trust_input'] if not trust_input: # Check input for potentially dangerous elements: if not subsparams: subsparams_str = None else: subsparams_str = convert_subscr_params(subsparams) if not connparams: connparams_str = None else: connparams_str = convert_conn_params(connparams) check_input(module, name, publications, owner, session_role, connparams_str, subsparams_str) if state == 'present' and cascade: module.warn('parameter "cascade" is ignored when state is not absent') if state != 'present': if owner: module.warn("parameter 'owner' is ignored when state is not 'present'") if publications: module.warn("parameter 'publications' is ignored when state is not 'present'") if connparams: module.warn("parameter 'connparams' is ignored when state is not 'present'") if subsparams: module.warn("parameter 'subsparams' is ignored when state is not 'present'") # Connect to DB and make cursor object: pg_conn_params = get_conn_params(module, module.params) # We check subscription state without DML queries execution, so set autocommit: db_connection = connect_to_db(module, pg_conn_params, autocommit=True) cursor = db_connection.cursor(cursor_factory=DictCursor) # Check version: if cursor.connection.server_version < SUPPORTED_PG_VERSION: module.fail_json(msg="PostgreSQL server version should be 10.0 or greater") # Set defaults: changed = False initial_state = {} final_state = {} ################################### # Create object and do rock'n'roll: subscription = PgSubscription(module, cursor, name, db) if subscription.exists: initial_state = deepcopy(subscription.attrs) final_state = deepcopy(initial_state) if state == 'present': if not subscription.exists: if subsparams: subsparams = convert_subscr_params(subsparams) if connparams: connparams = convert_conn_params(connparams) changed = subscription.create(connparams, publications, subsparams, check_mode=module.check_mode) else: changed = subscription.update(connparams, publications, subsparams, check_mode=module.check_mode) if owner and subscription.attrs['owner'] != owner: changed = subscription.set_owner(owner, check_mode=module.check_mode) or changed elif state == 'absent': changed = subscription.drop(cascade, check_mode=module.check_mode) elif state == 'refresh': if not subscription.exists: module.fail_json(msg="Refresh failed: subscription '%s' does not exist" % name) # Always returns True: changed = subscription.refresh(check_mode=module.check_mode) # Get final subscription info: final_state = subscription.get_info() # Connection is not needed any more: cursor.close() db_connection.close() # Return ret values and exit: module.exit_json(changed=changed, name=name, exists=subscription.exists, queries=subscription.executed_queries, initial_state=initial_state, final_state=final_state)
def main(): argument_spec = postgres_common_argument_spec() argument_spec.update( db=dict(type="str", required=True, aliases=["login_db"]), ext=dict(type="str", required=True, aliases=["name"]), schema=dict(type="str"), state=dict(type="str", default="present", choices=["absent", "present"]), cascade=dict(type="bool", default=False), session_role=dict(type="str"), version=dict(type="str"), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) ext = module.params["ext"] schema = module.params["schema"] state = module.params["state"] cascade = module.params["cascade"] version = module.params["version"] changed = False if version and state == 'absent': module.warn("Parameter version is ignored when state=absent") conn_params = get_conn_params(module, module.params) db_connection = connect_to_db(module, conn_params, autocommit=True) cursor = db_connection.cursor(cursor_factory=DictCursor) try: # Get extension info and available versions: curr_version, available_versions = ext_get_versions(cursor, ext) if state == "present": if version == 'latest': if available_versions: version = available_versions[-1] else: version = '' if version: # If the specific version is passed and it is not available for update: if version not in available_versions: if not curr_version: module.fail_json(msg="Passed version '%s' is not available" % version) elif LooseVersion(curr_version) == LooseVersion(version): changed = False else: module.fail_json(msg="Passed version '%s' is lower than " "the current created version '%s' or " "the passed version is not available" % (version, curr_version)) # If the specific version is passed and it is higher that the current version: if curr_version and version: if LooseVersion(curr_version) < LooseVersion(version): if module.check_mode: changed = True else: changed = ext_update_version(cursor, ext, version) # If the specific version is passed and it is created now: if curr_version == version: changed = False # If the ext doesn't exist and installed: elif not curr_version and available_versions: if module.check_mode: changed = True else: changed = ext_create(cursor, ext, schema, cascade, version) # If version is not passed: else: if not curr_version: # If the ext doesn't exist and it's installed: if available_versions: if module.check_mode: changed = True else: changed = ext_create(cursor, ext, schema, cascade, version) # If the ext doesn't exist and not installed: else: module.fail_json(msg="Extension %s is not installed" % ext) elif state == "absent": if curr_version: if module.check_mode: changed = True else: changed = ext_delete(cursor, ext, cascade) else: changed = False except Exception as e: db_connection.close() module.fail_json(msg="Database query failed: %s" % to_native(e), exception=traceback.format_exc()) db_connection.close() module.exit_json(changed=changed, db=module.params["db"], ext=ext, queries=executed_queries)
def main(): argument_spec = postgres_common_argument_spec() argument_spec.update( schema=dict(type="str", required=True, aliases=['name']), owner=dict(type="str", default=""), database=dict(type="str", default="postgres", aliases=["db", "login_db"]), cascade_drop=dict(type="bool", default=False), state=dict(type="str", default="present", choices=["absent", "present"]), session_role=dict(type="str"), trust_input=dict(type="bool", default=True), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) schema = module.params["schema"] owner = module.params["owner"] state = module.params["state"] cascade_drop = module.params["cascade_drop"] session_role = module.params["session_role"] trust_input = module.params["trust_input"] if not trust_input: # Check input for potentially dangerous elements: check_input(module, schema, owner, session_role) changed = False conn_params = get_conn_params(module, module.params) db_connection = connect_to_db(module, conn_params, autocommit=True) cursor = db_connection.cursor(cursor_factory=DictCursor) try: if module.check_mode: if state == "absent": changed = not schema_exists(cursor, schema) elif state == "present": changed = not schema_matches(cursor, schema, owner) module.exit_json(changed=changed, schema=schema) if state == "absent": try: changed = schema_delete(cursor, schema, cascade_drop) except SQLParseError as e: module.fail_json(msg=to_native(e), exception=traceback.format_exc()) elif state == "present": try: changed = schema_create(cursor, schema, owner) except SQLParseError as e: module.fail_json(msg=to_native(e), exception=traceback.format_exc()) except NotSupportedError as e: module.fail_json(msg=to_native(e), exception=traceback.format_exc()) except SystemExit: # Avoid catching this on Python 2.4 raise except Exception as e: module.fail_json(msg="Database query failed: %s" % to_native(e), exception=traceback.format_exc()) db_connection.close() module.exit_json(changed=changed, schema=schema, queries=executed_queries)
def main(): argument_spec = postgres_common_argument_spec() argument_spec.update( tablespace=dict(type='str', required=True, aliases=['name']), state=dict(type='str', default="present", choices=["absent", "present"]), location=dict(type='path', aliases=['path']), owner=dict(type='str'), set=dict(type='dict'), rename_to=dict(type='str'), db=dict(type='str', aliases=['login_db']), session_role=dict(type='str'), ) module = AnsibleModule( argument_spec=argument_spec, mutually_exclusive=(('positional_args', 'named_args'), ), supports_check_mode=True, ) tablespace = module.params["tablespace"] state = module.params["state"] location = module.params["location"] owner = module.params["owner"] rename_to = module.params["rename_to"] settings = module.params["set"] if state == 'absent' and (location or owner or rename_to or settings): module.fail_json(msg="state=absent is mutually exclusive location, " "owner, rename_to, and set") conn_params = get_conn_params(module, module.params, warn_db_default=False) db_connection = connect_to_db(module, conn_params, autocommit=True) cursor = db_connection.cursor(cursor_factory=DictCursor) # Change autocommit to False if check_mode: if module.check_mode: if PSYCOPG2_VERSION >= '2.4.2': db_connection.set_session(autocommit=False) else: db_connection.set_isolation_level(READ_COMMITTED) # Set defaults: autocommit = False changed = False ############## # Create PgTablespace object and do main job: tblspace = PgTablespace(module, cursor, tablespace) # If tablespace exists with different location, exit: if tblspace.exists and location and location != tblspace.location: module.fail_json( msg="Tablespace '%s' exists with different location '%s'" % (tblspace.name, tblspace.location)) # Create new tablespace: if not tblspace.exists and state == 'present': if rename_to: module.fail_json( msg="Tablespace %s does not exist, nothing to rename" % tablespace) if not location: module.fail_json(msg="'location' parameter must be passed with " "state=present if the tablespace doesn't exist") # Because CREATE TABLESPACE can not be run inside the transaction block: autocommit = True if PSYCOPG2_VERSION >= '2.4.2': db_connection.set_session(autocommit=True) else: db_connection.set_isolation_level(AUTOCOMMIT) changed = tblspace.create(location) # Drop non-existing tablespace: elif not tblspace.exists and state == 'absent': # Nothing to do: module.fail_json(msg="Tries to drop nonexistent tablespace '%s'" % tblspace.name) # Drop existing tablespace: elif tblspace.exists and state == 'absent': # Because DROP TABLESPACE can not be run inside the transaction block: autocommit = True if PSYCOPG2_VERSION >= '2.4.2': db_connection.set_session(autocommit=True) else: db_connection.set_isolation_level(AUTOCOMMIT) changed = tblspace.drop() # Rename tablespace: elif tblspace.exists and rename_to: if tblspace.name != rename_to: changed = tblspace.rename(rename_to) if state == 'present': # Refresh information: tblspace.get_info() # Change owner and settings: if state == 'present' and tblspace.exists: if owner: changed = tblspace.set_owner(owner) if settings: changed = tblspace.set_settings(settings) tblspace.get_info() # Rollback if it's possible and check_mode: if not autocommit: 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', tablespace=tblspace.name, owner=tblspace.owner, queries=tblspace.executed_queries, options=tblspace.settings, location=tblspace.location, ) if state == 'present': kw['state'] = 'present' if tblspace.new_name: kw['newname'] = tblspace.new_name elif state == 'absent': kw['state'] = 'absent' module.exit_json(**kw)
def main(): argument_spec = postgres_common_argument_spec() argument_spec.update( name=dict(type='str', required=True), db=dict(type='str', aliases=['login_db']), value=dict(type='str'), reset=dict(type='bool'), session_role=dict(type='str'), trust_input=dict(type='bool', default=True), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) name = module.params['name'] value = module.params['value'] reset = module.params['reset'] session_role = module.params['session_role'] trust_input = module.params['trust_input'] if not trust_input: # Check input for potentially dangerous elements: check_input(module, name, value, session_role) # Allow to pass values like 1mb instead of 1MB, etc: if value: for unit in POSSIBLE_SIZE_UNITS: if value[:-2].isdigit() and unit in value[-2:]: value = value.upper() if value is not None and reset: module.fail_json(msg="%s: value and reset params are mutually exclusive" % name) if value is None and not reset: module.fail_json(msg="%s: at least one of value or reset param must be specified" % name) conn_params = get_conn_params(module, module.params, warn_db_default=False) db_connection = connect_to_db(module, conn_params, autocommit=True) cursor = db_connection.cursor(cursor_factory=DictCursor) kw = {} # Check server version (needs 9.4 or later): ver = db_connection.server_version if ver < PG_REQ_VER: module.warn("PostgreSQL is %s version but %s or later is required" % (ver, PG_REQ_VER)) kw = dict( changed=False, restart_required=False, value_pretty="", prev_val_pretty="", value={"value": "", "unit": ""}, ) kw['name'] = name db_connection.close() module.exit_json(**kw) # Set default returned values: restart_required = False changed = False kw['name'] = name kw['restart_required'] = False # Get info about param state: res = param_get(cursor, module, name) current_value = res[0] raw_val = res[1] unit = res[2] boot_val = res[3] context = res[4] if value == 'True': value = 'on' elif value == 'False': value = 'off' kw['prev_val_pretty'] = current_value kw['value_pretty'] = deepcopy(kw['prev_val_pretty']) kw['context'] = context # Do job if context == "internal": module.fail_json(msg="%s: cannot be changed (internal context). See " "https://www.postgresql.org/docs/current/runtime-config-preset.html" % name) if context == "postmaster": restart_required = True # If check_mode, just compare and exit: if module.check_mode: if pretty_to_bytes(value) == pretty_to_bytes(current_value): kw['changed'] = False else: kw['value_pretty'] = value kw['changed'] = True # Anyway returns current raw value in the check_mode: kw['value'] = dict( value=raw_val, unit=unit, ) kw['restart_required'] = restart_required module.exit_json(**kw) # Set param (value can be an empty string): if value is not None and value != current_value: changed = param_set(cursor, module, name, value, context) kw['value_pretty'] = value # Reset param: elif reset: if raw_val == boot_val: # nothing to change, exit: kw['value'] = dict( value=raw_val, unit=unit, ) module.exit_json(**kw) changed = param_set(cursor, module, name, boot_val, context) cursor.close() db_connection.close() # Reconnect and recheck current value: if context in ('sighup', 'superuser-backend', 'backend', 'superuser', 'user'): db_connection = connect_to_db(module, conn_params, autocommit=True) cursor = db_connection.cursor(cursor_factory=DictCursor) res = param_get(cursor, module, name) # f_ means 'final' f_value = res[0] f_raw_val = res[1] if raw_val == f_raw_val: changed = False else: changed = True kw['value_pretty'] = f_value kw['value'] = dict( value=f_raw_val, unit=unit, ) cursor.close() db_connection.close() kw['changed'] = changed kw['restart_required'] = restart_required if restart_required and changed: module.warn("Restart of PostgreSQL is required for setting %s" % name) module.exit_json(**kw)
def main(): argument_spec = postgres_common_argument_spec() argument_spec.update( table=dict(type='str', required=True, aliases=['name']), state=dict(type='str', default="present", choices=["absent", "present"]), db=dict(type='str', default='', aliases=['login_db']), tablespace=dict(type='str'), owner=dict(type='str'), unlogged=dict(type='bool', default=False), like=dict(type='str'), including=dict(type='str'), rename=dict(type='str'), truncate=dict(type='bool', default=False), columns=dict(type='list', elements='str'), storage_params=dict(type='list', elements='str'), session_role=dict(type='str'), cascade=dict(type='bool', default=False), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) table = module.params["table"] state = module.params["state"] tablespace = module.params["tablespace"] owner = module.params["owner"] unlogged = module.params["unlogged"] like = module.params["like"] including = module.params["including"] newname = module.params["rename"] storage_params = module.params["storage_params"] truncate = module.params["truncate"] columns = module.params["columns"] cascade = module.params["cascade"] if state == 'present' and cascade: module.warn("cascade=true is ignored when state=present") # Check mutual exclusive parameters: if state == 'absent' and (truncate or newname or columns or tablespace or like or storage_params or unlogged or owner or including): module.fail_json(msg="%s: state=absent is mutually exclusive with: " "truncate, rename, columns, tablespace, " "including, like, storage_params, unlogged, owner" % table) if truncate and (newname or columns or like or unlogged or storage_params or owner or tablespace or including): module.fail_json(msg="%s: truncate is mutually exclusive with: " "rename, columns, like, unlogged, including, " "storage_params, owner, tablespace" % table) if newname and (columns or like or unlogged or storage_params or owner or tablespace or including): module.fail_json(msg="%s: rename is mutually exclusive with: " "columns, like, unlogged, including, " "storage_params, owner, tablespace" % table) if like and columns: module.fail_json( msg="%s: like and columns params are mutually exclusive" % table) if including and not like: module.fail_json(msg="%s: including param needs like param specified" % table) conn_params = get_conn_params(module, module.params) db_connection = connect_to_db(module, conn_params, autocommit=False) cursor = db_connection.cursor(cursor_factory=DictCursor) if storage_params: storage_params = ','.join(storage_params) if columns: columns = ','.join(columns) ############## # Do main job: table_obj = Table(table, module, cursor) # Set default returned values: changed = False kw = {} kw['table'] = table kw['state'] = '' if table_obj.exists: kw = dict( table=table, state='present', owner=table_obj.info['owner'], tablespace=table_obj.info['tblspace'], storage_params=table_obj.info['storage_params'], ) if state == 'absent': changed = table_obj.drop(cascade=cascade) elif truncate: changed = table_obj.truncate() elif newname: changed = table_obj.rename(newname) q = table_obj.executed_queries table_obj = Table(newname, module, cursor) table_obj.executed_queries = q elif state == 'present' and not like: changed = table_obj.create(columns, storage_params, tablespace, unlogged, owner) elif state == 'present' and like: changed = table_obj.create_like(like, including, tablespace, unlogged, storage_params) if changed: if module.check_mode: db_connection.rollback() else: db_connection.commit() # Refresh table info for RETURN. # Note, if table has been renamed, it gets info by newname: table_obj.get_info() db_connection.commit() if table_obj.exists: kw = dict( table=table, state='present', owner=table_obj.info['owner'], tablespace=table_obj.info['tblspace'], storage_params=table_obj.info['storage_params'], ) else: # We just change the table state here # to keep other information about the dropped table: kw['state'] = 'absent' kw['queries'] = table_obj.executed_queries kw['changed'] = changed db_connection.close() module.exit_json(**kw)
def main(): argument_spec = postgres_common_argument_spec() argument_spec.update( copy_to=dict(type='path', aliases=['to']), copy_from=dict(type='path', aliases=['from']), src=dict(type='str', aliases=['source']), dst=dict(type='str', aliases=['destination']), columns=dict(type='list', elements='str', aliases=['column']), options=dict(type='dict'), program=dict(type='bool', default=False), db=dict(type='str', aliases=['login_db']), session_role=dict(type='str'), ) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, mutually_exclusive=[ ['copy_from', 'copy_to'], ['copy_from', 'src'], ['copy_to', 'dst'], ]) # Note: we don't need to check mutually exclusive params here, because they are # checked automatically by AnsibleModule (mutually_exclusive=[] list above). if module.params.get('copy_from') and not module.params.get('dst'): module.fail_json(msg='dst param is necessary with copy_from') elif module.params.get('copy_to') and not module.params.get('src'): module.fail_json(msg='src param is necessary with copy_to') # Connect to DB and make cursor object: conn_params = get_conn_params(module, module.params) db_connection = connect_to_db(module, conn_params, autocommit=False) cursor = db_connection.cursor(cursor_factory=DictCursor) ############## # Create the object and do main job: data = PgCopyData(module, cursor) # Note: parameters like dst, src, etc. are got # from module object into data object of PgCopyData class. # Therefore not need to pass args to the methods below. # Note: check mode is implemented inside the methods below # by checking passed module.check_mode arg. if module.params.get('copy_to'): data.copy_to() elif module.params.get('copy_from'): data.copy_from() # Finish: if module.check_mode: db_connection.rollback() else: db_connection.commit() cursor.close() db_connection.close() # Return some values: module.exit_json( changed=data.changed, queries=data.executed_queries, src=data.src, dst=data.dst, )