summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnsible Core Team <info@ansible.com>2020-03-09 09:40:31 +0000
committerAnsible Core Team <info@ansible.com>2020-03-09 09:40:31 +0000
commitab5942a760c399a1b3a47e6afaf38cac44522be9 (patch)
treee5d867c7a75f5e2aa55582534f04c1229d48c229
parent7d65b281899668aff08e78c12aeceb13b15d2d97 (diff)
downloadansible-ab5942a760c399a1b3a47e6afaf38cac44522be9.tar.gz
Migrated to servicenow.servicenow
-rw-r--r--lib/ansible/module_utils/service_now.py94
-rw-r--r--lib/ansible/modules/notification/snow_record.py333
-rw-r--r--lib/ansible/modules/notification/snow_record_find.py273
-rw-r--r--lib/ansible/plugins/doc_fragments/service_now.py48
-rw-r--r--test/sanity/ignore.txt1
5 files changed, 0 insertions, 749 deletions
diff --git a/lib/ansible/module_utils/service_now.py b/lib/ansible/module_utils/service_now.py
deleted file mode 100644
index 7c7fa7839c..0000000000
--- a/lib/ansible/module_utils/service_now.py
+++ /dev/null
@@ -1,94 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright: (c) 2019, Ansible Project
-# Copyright: (c) 2017, Tim Rightnour <thegarbledone@gmail.com>
-# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-import traceback
-from ansible.module_utils.basic import env_fallback, missing_required_lib
-
-# Pull in pysnow
-HAS_PYSNOW = False
-PYSNOW_IMP_ERR = None
-try:
- import pysnow
- HAS_PYSNOW = True
-except ImportError:
- PYSNOW_IMP_ERR = traceback.format_exc()
-
-
-class ServiceNowClient(object):
- def __init__(self, module):
- """
- Constructor
- """
- if not HAS_PYSNOW:
- module.fail_json(msg=missing_required_lib('pysnow'), exception=PYSNOW_IMP_ERR)
-
- self.module = module
- self.params = module.params
- self.client_id = self.params['client_id']
- self.client_secret = self.params['client_secret']
- self.username = self.params['username']
- self.password = self.params['password']
- self.instance = self.params['instance']
- self.session = {'token': None}
- self.conn = None
-
- def login(self):
- result = dict(
- changed=False
- )
-
- if self.params['client_id'] is not None:
- try:
- self.conn = pysnow.OAuthClient(client_id=self.client_id,
- client_secret=self.client_secret,
- token_updater=self.updater,
- instance=self.instance)
- except Exception as detail:
- self.module.fail_json(msg='Could not connect to ServiceNow: {0}'.format(str(detail)), **result)
- if not self.session['token']:
- # No previous token exists, Generate new.
- try:
- self.session['token'] = self.conn.generate_token(self.username, self.password)
- except pysnow.exceptions.TokenCreateError as detail:
- self.module.fail_json(msg='Unable to generate a new token: {0}'.format(str(detail)), **result)
-
- self.conn.set_token(self.session['token'])
- elif self.username is not None:
- try:
- self.conn = pysnow.Client(instance=self.instance,
- user=self.username,
- password=self.password)
- except Exception as detail:
- self.module.fail_json(msg='Could not connect to ServiceNow: {0}'.format(str(detail)), **result)
- else:
- snow_error = "Must specify username/password. Also client_id/client_secret if using OAuth."
- self.module.fail_json(msg=snow_error, **result)
-
- def updater(self, new_token):
- self.session['token'] = new_token
- self.conn = pysnow.OAuthClient(client_id=self.client_id,
- client_secret=self.client_secret,
- token_updater=self.updater,
- instance=self.instance)
- try:
- self.conn.set_token(self.session['token'])
- except pysnow.exceptions.MissingToken:
- snow_error = "Token is missing"
- self.module.fail_json(msg=snow_error)
- except Exception as detail:
- self.module.fail_json(msg='Could not refresh token: {0}'.format(str(detail)))
-
- @staticmethod
- def snow_argument_spec():
- return dict(
- instance=dict(type='str', required=False, fallback=(env_fallback, ['SN_INSTANCE'])),
- username=dict(type='str', required=False, fallback=(env_fallback, ['SN_USERNAME'])),
- password=dict(type='str', required=False, no_log=True, fallback=(env_fallback, ['SN_PASSWORD'])),
- client_id=dict(type='str', no_log=True),
- client_secret=dict(type='str', no_log=True),
- )
diff --git a/lib/ansible/modules/notification/snow_record.py b/lib/ansible/modules/notification/snow_record.py
deleted file mode 100644
index a967343bed..0000000000
--- a/lib/ansible/modules/notification/snow_record.py
+++ /dev/null
@@ -1,333 +0,0 @@
-#!/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()
diff --git a/lib/ansible/modules/notification/snow_record_find.py b/lib/ansible/modules/notification/snow_record_find.py
deleted file mode 100644
index f6abf1caa6..0000000000
--- a/lib/ansible/modules/notification/snow_record_find.py
+++ /dev/null
@@ -1,273 +0,0 @@
-#!/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_find
-short_description: Search for multiple records from ServiceNow
-version_added: "2.9"
-description:
- - Gets multiple records from a specified table from ServiceNow based on a query dictionary.
-options:
- table:
- description:
- - Table to query for records.
- type: str
- required: false
- default: incident
- query:
- description:
- - Dict to query for records.
- type: dict
- required: true
- max_records:
- description:
- - Maximum number of records to return.
- type: int
- required: false
- default: 20
- order_by:
- description:
- - Field to sort the results on.
- - Can prefix with "-" or "+" to change descending or ascending sort order.
- type: str
- default: "-created_on"
- required: false
- return_fields:
- description:
- - Fields of the record to return in the json.
- - By default, all fields will be returned.
- type: list
- required: false
-requirements:
- - python pysnow (pysnow)
-author:
- - Tim Rightnour (@garbled1)
-extends_documentation_fragment: service_now.documentation
-'''
-
-EXAMPLES = '''
-- name: Search for incident assigned to group, return specific fields
- snow_record_find:
- username: ansible_test
- password: my_password
- instance: dev99999
- table: incident
- query:
- assignment_group: d625dccec0a8016700a222a0f7900d06
- return_fields:
- - number
- - opened_at
-
-- name: Using OAuth, search for incident assigned to group, return specific fields
- snow_record_find:
- username: ansible_test
- password: my_password
- client_id: "1234567890abcdef1234567890abcdef"
- client_secret: "Password1!"
- instance: dev99999
- table: incident
- query:
- assignment_group: d625dccec0a8016700a222a0f7900d06
- return_fields:
- - number
- - opened_at
-
-- name: Find open standard changes with my template
- snow_record_find:
- username: ansible_test
- password: my_password
- instance: dev99999
- table: change_request
- query:
- AND:
- equals:
- active: "True"
- type: "standard"
- u_change_stage: "80"
- contains:
- u_template: "MY-Template"
- return_fields:
- - sys_id
- - number
- - sys_created_on
- - sys_updated_on
- - u_template
- - active
- - type
- - u_change_stage
- - sys_created_by
- - description
- - short_description
-'''
-
-RETURN = '''
-record:
- description: The full contents of the matching ServiceNow records as a list of records.
- type: dict
- returned: always
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.service_now import ServiceNowClient
-from ansible.module_utils._text import to_native
-
-try:
- # This is being managed by ServiceNowClient
- import pysnow
-except ImportError:
- pass
-
-
-class BuildQuery(object):
- '''
- This is a BuildQuery manipulation class that constructs
- a pysnow.QueryBuilder object based on data input.
- '''
-
- def __init__(self, module):
- self.module = module
- self.logic_operators = ["AND", "OR", "NQ"]
- self.condition_operator = {
- 'equals': self._condition_closure,
- 'not_equals': self._condition_closure,
- 'contains': self._condition_closure,
- 'not_contains': self._condition_closure,
- 'starts_with': self._condition_closure,
- 'ends_with': self._condition_closure,
- 'greater_than': self._condition_closure,
- 'less_than': self._condition_closure,
- }
- self.accepted_cond_ops = self.condition_operator.keys()
- self.append_operator = False
- self.simple_query = True
- self.data = module.params['query']
-
- def _condition_closure(self, cond, query_field, query_value):
- self.qb.field(query_field)
- getattr(self.qb, cond)(query_value)
-
- def _iterate_fields(self, data, logic_op, cond_op):
- if isinstance(data, dict):
- for query_field, query_value in data.items():
- if self.append_operator:
- getattr(self.qb, logic_op)()
- self.condition_operator[cond_op](cond_op, query_field, query_value)
- self.append_operator = True
- else:
- self.module.fail_json(msg='Query is not in a supported format')
-
- def _iterate_conditions(self, data, logic_op):
- if isinstance(data, dict):
- for cond_op, fields in data.items():
- if (cond_op in self.accepted_cond_ops):
- self._iterate_fields(fields, logic_op, cond_op)
- else:
- self.module.fail_json(msg='Supported conditions: {0}'.format(str(self.condition_operator.keys())))
- else:
- self.module.fail_json(msg='Supported conditions: {0}'.format(str(self.condition_operator.keys())))
-
- def _iterate_operators(self, data):
- if isinstance(data, dict):
- for logic_op, cond_op in data.items():
- if (logic_op in self.logic_operators):
- self.simple_query = False
- self._iterate_conditions(cond_op, logic_op)
- elif self.simple_query:
- self.condition_operator['equals']('equals', logic_op, cond_op)
- break
- else:
- self.module.fail_json(msg='Query is not in a supported format')
- else:
- self.module.fail_json(msg='Supported operators: {0}'.format(str(self.logic_operators)))
-
- def build_query(self):
- self.qb = pysnow.QueryBuilder()
- self._iterate_operators(self.data)
- return (self.qb)
-
-
-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'),
- query=dict(type='dict', required=True),
- max_records=dict(default=20, type='int', required=False),
- order_by=dict(default='-created_on', type='str', required=False),
- return_fields=dict(default=None, type='list', required=False)
- )
- module_required_together = [
- ['client_id', 'client_secret']
- ]
-
- module = AnsibleModule(
- argument_spec=module_args,
- supports_check_mode=True,
- required_together=module_required_together
- )
-
- # 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']
- query = params['query']
- max_records = params['max_records']
- return_fields = params['return_fields']
-
- result = dict(
- changed=False,
- instance=instance,
- table=table,
- query=query,
- max_records=max_records,
- return_fields=return_fields
- )
-
- # Do the lookup
- try:
- bq = BuildQuery(module)
- qb = bq.build_query()
- record = conn.query(table=module.params['table'],
- query=qb)
- if module.params['return_fields'] is not None:
- res = record.get_multiple(fields=module.params['return_fields'],
- limit=module.params['max_records'],
- order_by=[module.params['order_by']])
- else:
- res = record.get_multiple(limit=module.params['max_records'],
- order_by=[module.params['order_by']])
- except Exception as detail:
- module.fail_json(msg='Failed to find record: {0}'.format(to_native(detail)), **result)
-
- try:
- result['record'] = list(res)
- except pysnow.exceptions.NoResults:
- result['record'] = []
-
- module.exit_json(**result)
-
-
-def main():
- run_module()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/plugins/doc_fragments/service_now.py b/lib/ansible/plugins/doc_fragments/service_now.py
deleted file mode 100644
index e890778da7..0000000000
--- a/lib/ansible/plugins/doc_fragments/service_now.py
+++ /dev/null
@@ -1,48 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright: (c) 2019, Ansible Project
-# 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
-
-
-class ModuleDocFragment(object):
- # Parameters for Service Now modules
- DOCUMENTATION = r'''
-options:
- instance:
- description:
- - The ServiceNow instance name, without the domain, service-now.com.
- - If the value is not specified in the task, the value of environment variable C(SN_INSTANCE) will be used instead.
- - Environment variable support added in Ansible 2.9.
- required: false
- type: str
- username:
- description:
- - Name of user for connection to ServiceNow.
- - Required whether using Basic or OAuth authentication.
- - If the value is not specified in the task, the value of environment variable C(SN_USERNAME) will be used instead.
- - Environment variable support added in Ansible 2.9.
- required: false
- type: str
- password:
- description:
- - Password for username.
- - Required whether using Basic or OAuth authentication.
- - If the value is not specified in the task, the value of environment variable C(SN_PASSWORD) will be used instead.
- - Environment variable support added in Ansible 2.9.
- required: false
- type: str
- client_id:
- description:
- - Client ID generated by ServiceNow.
- required: false
- version_added: "2.9"
- type: str
- client_secret:
- description:
- - Client Secret associated with client id.
- required: false
- version_added: "2.9"
- type: str
-'''
diff --git a/test/sanity/ignore.txt b/test/sanity/ignore.txt
index 37c3182fdf..e6bf7868ed 100644
--- a/test/sanity/ignore.txt
+++ b/test/sanity/ignore.txt
@@ -3530,7 +3530,6 @@ lib/ansible/modules/network/vyos/vyos_vlan.py validate-modules:missing-suboption
lib/ansible/modules/network/vyos/vyos_vlan.py validate-modules:parameter-list-no-elements
lib/ansible/modules/network/vyos/vyos_vlan.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/network/vyos/vyos_vlan.py validate-modules:undocumented-parameter
-lib/ansible/modules/notification/snow_record_find.py validate-modules:parameter-list-no-elements
lib/ansible/modules/packaging/language/pip.py pylint:blacklisted-name
lib/ansible/modules/packaging/language/pip.py validate-modules:doc-elements-mismatch
lib/ansible/modules/packaging/language/pip.py validate-modules:invalid-ansiblemodule-schema