EVOLUTION-MANAGER
Edit File: snow_record.py
#!/usr/bin/python # -*- coding: utf-8 -*- # Copyright: (c) 2017, Tim Rightnour <thegarbledone@gmail.com> # 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 = ''' --- module: snow_record short_description: Manage records in ServiceNow version_added: "2.5" description: - Creates, deletes and updates a single record in ServiceNow. options: table: description: - Table to query for records. required: false default: incident type: str state: description: - If C(present) is supplied with a C(number) argument, the module will attempt to update the record with the supplied data. - If no such record exists, a new one will be created. - C(absent) will delete a record. choices: [ present, absent ] required: true type: str data: description: - key, value pairs of data to load into the record. See Examples. - Required for C(state:present). type: dict number: description: - Record number to update. - Required for C(state:absent). required: false type: str lookup_field: description: - Changes the field that C(number) uses to find records. required: false default: number type: str attachment: description: - Attach a file to the record. required: false type: str requirements: - python pysnow (pysnow) author: - Tim Rightnour (@garbled1) extends_documentation_fragment: service_now.documentation ''' EXAMPLES = ''' - name: Grab a user record snow_record: username: ansible_test password: my_password instance: dev99999 state: present number: 62826bf03710200044e0bfc8bcbe5df1 table: sys_user lookup_field: sys_id - name: Grab a user record using OAuth snow_record: username: ansible_test password: my_password client_id: "1234567890abcdef1234567890abcdef" client_secret: "Password1!" instance: dev99999 state: present number: 62826bf03710200044e0bfc8bcbe5df1 table: sys_user lookup_field: sys_id - name: Create an incident snow_record: username: ansible_test password: my_password instance: dev99999 state: present data: short_description: "This is a test incident opened by Ansible" severity: 3 priority: 2 register: new_incident - name: Delete the record we just made snow_record: username: admin password: xxxxxxx instance: dev99999 state: absent number: "{{new_incident['record']['number']}}" - name: Delete a non-existant record snow_record: username: ansible_test password: my_password instance: dev99999 state: absent number: 9872354 failed_when: false - name: Update an incident snow_record: username: ansible_test password: my_password instance: dev99999 state: present number: INC0000055 data: work_notes : "Been working all day on this thing." - name: Attach a file to an incident snow_record: username: ansible_test password: my_password instance: dev99999 state: present number: INC0000055 attachment: README.md tags: attach ''' RETURN = ''' record: description: Record data from Service Now type: dict returned: when supported attached_file: description: Details of the file that was attached via C(attachment) type: dict returned: when supported ''' import os from ansible.module_utils.basic import AnsibleModule from ansible.module_utils._text import to_bytes, to_native from ansible.module_utils.service_now import ServiceNowClient try: # This is being handled by ServiceNowClient import pysnow except ImportError: pass def run_module(): # define the available arguments/parameters that a user can pass to # the module module_args = ServiceNowClient.snow_argument_spec() module_args.update( table=dict(type='str', required=False, default='incident'), state=dict(choices=['present', 'absent'], type='str', required=True), number=dict(default=None, required=False, type='str'), data=dict(default=None, required=False, type='dict'), lookup_field=dict(default='number', required=False, type='str'), attachment=dict(default=None, required=False, type='str') ) module_required_together = [ ['client_id', 'client_secret'] ] module_required_if = [ ['state', 'absent', ['number']], ] module = AnsibleModule( argument_spec=module_args, supports_check_mode=True, required_together=module_required_together, required_if=module_required_if ) # Connect to ServiceNow service_now_client = ServiceNowClient(module) service_now_client.login() conn = service_now_client.conn params = module.params instance = params['instance'] table = params['table'] state = params['state'] number = params['number'] data = params['data'] lookup_field = params['lookup_field'] result = dict( changed=False, instance=instance, table=table, number=number, lookup_field=lookup_field ) # check for attachments if params['attachment'] is not None: attach = params['attachment'] b_attach = to_bytes(attach, errors='surrogate_or_strict') if not os.path.exists(b_attach): module.fail_json(msg="Attachment {0} not found".format(attach)) result['attachment'] = attach else: attach = None # Deal with check mode if module.check_mode: # if we are in check mode and have no number, we would have created # a record. We can only partially simulate this if number is None: result['record'] = dict(data) result['changed'] = True # do we want to check if the record is non-existent? elif state == 'absent': try: record = conn.query(table=table, query={lookup_field: number}) res = record.get_one() result['record'] = dict(Success=True) result['changed'] = True except pysnow.exceptions.NoResults: result['record'] = None except Exception as detail: module.fail_json(msg="Unknown failure in query record: {0}".format(to_native(detail)), **result) # Let's simulate modification else: try: record = conn.query(table=table, query={lookup_field: number}) res = record.get_one() for key, value in data.items(): res[key] = value result['changed'] = True result['record'] = res except pysnow.exceptions.NoResults: snow_error = "Record does not exist" module.fail_json(msg=snow_error, **result) except Exception as detail: module.fail_json(msg="Unknown failure in query record: {0}".format(to_native(detail)), **result) module.exit_json(**result) # now for the real thing: (non-check mode) # are we creating a new record? if state == 'present' and number is None: try: record = conn.insert(table=table, payload=dict(data)) except pysnow.exceptions.UnexpectedResponseFormat as e: snow_error = "Failed to create record: {0}, details: {1}".format(e.error_summary, e.error_details) module.fail_json(msg=snow_error, **result) except pysnow.legacy_exceptions.UnexpectedResponse as e: module.fail_json(msg="Failed to create record due to %s" % to_native(e), **result) result['record'] = record result['changed'] = True # we are deleting a record elif state == 'absent': try: record = conn.query(table=table, query={lookup_field: number}) res = record.delete() except pysnow.exceptions.NoResults: res = dict(Success=True) except pysnow.exceptions.MultipleResults: snow_error = "Multiple record match" module.fail_json(msg=snow_error, **result) except pysnow.exceptions.UnexpectedResponseFormat as e: snow_error = "Failed to delete record: {0}, details: {1}".format(e.error_summary, e.error_details) module.fail_json(msg=snow_error, **result) except pysnow.legacy_exceptions.UnexpectedResponse as e: module.fail_json(msg="Failed to delete record due to %s" % to_native(e), **result) except Exception as detail: snow_error = "Failed to delete record: {0}".format(to_native(detail)) module.fail_json(msg=snow_error, **result) result['record'] = res result['changed'] = True # We want to update a record else: try: record = conn.query(table=table, query={lookup_field: number}) if data is not None: res = record.update(dict(data)) result['record'] = res result['changed'] = True else: res = record.get_one() result['record'] = res if attach is not None: res = record.attach(b_attach) result['changed'] = True result['attached_file'] = res except pysnow.exceptions.MultipleResults: snow_error = "Multiple record match" module.fail_json(msg=snow_error, **result) except pysnow.exceptions.NoResults: snow_error = "Record does not exist" module.fail_json(msg=snow_error, **result) except pysnow.exceptions.UnexpectedResponseFormat as e: snow_error = "Failed to update record: {0}, details: {1}".format(e.error_summary, e.error_details) module.fail_json(msg=snow_error, **result) except pysnow.legacy_exceptions.UnexpectedResponse as e: module.fail_json(msg="Failed to update record due to %s" % to_native(e), **result) except Exception as detail: snow_error = "Failed to update record: {0}".format(to_native(detail)) module.fail_json(msg=snow_error, **result) module.exit_json(**result) def main(): run_module() if __name__ == '__main__': main()