From 6531819172ca46e14746a4d9b0c845a46b2b82a6 Mon Sep 17 00:00:00 2001 From: n3pjk Date: Mon, 22 Jul 2019 10:01:04 -0400 Subject: [PATCH] snow: Fix token reference in basic authentication (#59315) * Fix OAUTHClient logic * Add Env variable support for snow modules Fixes: #59299 Signed-off-by: Paul Knight Signed-off-by: Abhijeet Kasurde --- .../rst/porting_guides/porting_guide_2.9.rst | 2 +- lib/ansible/module_utils/service_now.py | 25 +++++++++---------- .../modules/notification/snow_record.py | 18 +++++-------- .../modules/notification/snow_record_find.py | 7 ------ .../plugins/doc_fragments/service_now.py | 14 ++++++++--- 5 files changed, 30 insertions(+), 36 deletions(-) diff --git a/docs/docsite/rst/porting_guides/porting_guide_2.9.rst b/docs/docsite/rst/porting_guides/porting_guide_2.9.rst index b93c23aa3bf..4f3f948adb1 100644 --- a/docs/docsite/rst/porting_guides/porting_guide_2.9.rst +++ b/docs/docsite/rst/porting_guides/porting_guide_2.9.rst @@ -69,7 +69,7 @@ Noteworthy module changes * `vmware_dvswitch ` accepts `folder` parameter to place dvswitch in user defined folder. This option makes `datacenter` as an optional parameter. * `vmware_datastore_cluster ` accepts `folder` parameter to place datastore cluster in user defined folder. This option makes `datacenter` as an optional parameter. * `mysql_db ` returns new `db_list` parameter in addition to `db` parameter. This `db_list` parameter refers to list of database names. `db` parameter will be deprecated in version `2.13`. - +* `snow_record ` and `snow_record_find ` now takes environment variables for `instance`, `username` and `password` parameters. This change marks these parameters as optional. * The ``python_requirements_facts`` module was renamed to :ref:`python_requirements_info `. * The ``jenkins_job_facts`` module was renamed to :ref:`jenkins_job_info `. * The ``intersight_facts`` module was renamed to :ref:`intersight_info `. diff --git a/lib/ansible/module_utils/service_now.py b/lib/ansible/module_utils/service_now.py index 18b25fab54e..7c7fa7839cd 100644 --- a/lib/ansible/module_utils/service_now.py +++ b/lib/ansible/module_utils/service_now.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright: (c) 2019, Ansible Project # Copyright: (c) 2017, Tim Rightnour # Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause) @@ -8,7 +7,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type import traceback -from ansible.module_utils.basic import missing_required_lib +from ansible.module_utils.basic import env_fallback, missing_required_lib # Pull in pysnow HAS_PYSNOW = False @@ -51,14 +50,14 @@ class ServiceNowClient(object): 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) + 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']) + self.conn.set_token(self.session['token']) elif self.username is not None: try: self.conn = pysnow.Client(instance=self.instance, @@ -67,7 +66,7 @@ class ServiceNowClient(object): 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 or client_id/client_secret" + 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): @@ -87,9 +86,9 @@ class ServiceNowClient(object): @staticmethod def snow_argument_spec(): return dict( - instance=dict(type='str', required=True), - username=dict(type='str', required=True), - password=dict(type='str', required=True, no_log=True), + 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 index af21b18c317..a967343bed6 100644 --- a/lib/ansible/modules/notification/snow_record.py +++ b/lib/ansible/modules/notification/snow_record.py @@ -57,18 +57,6 @@ options: - Attach a file to the record. required: false type: str - client_id: - description: - - Client ID generated by ServiceNow. - required: false - type: str - version_added: "2.9" - client_secret: - description: - - Client Secret associated with client id. - required: false - type: str - version_added: "2.9" requirements: - python pysnow (pysnow) author: @@ -277,6 +265,8 @@ def run_module(): 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 @@ -293,6 +283,8 @@ def run_module(): 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) @@ -324,6 +316,8 @@ def run_module(): 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) diff --git a/lib/ansible/modules/notification/snow_record_find.py b/lib/ansible/modules/notification/snow_record_find.py index a9de154623c..a5bd12f1a74 100644 --- a/lib/ansible/modules/notification/snow_record_find.py +++ b/lib/ansible/modules/notification/snow_record_find.py @@ -130,13 +130,6 @@ try: except ImportError: pass -# OAuth Variables -module = None -client_id = None -client_secret = None -instance = None -session = {'token': None} - class BuildQuery(object): ''' diff --git a/lib/ansible/plugins/doc_fragments/service_now.py b/lib/ansible/plugins/doc_fragments/service_now.py index 2eeb42c4bb9..e890778da7b 100644 --- a/lib/ansible/plugins/doc_fragments/service_now.py +++ b/lib/ansible/plugins/doc_fragments/service_now.py @@ -13,28 +13,36 @@ options: instance: description: - The ServiceNow instance name, without the domain, service-now.com. - required: true + - 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. - required: true + - 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. - required: true + - 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 '''