From 1f7ffe26195dbc9191a292465f80d1a2388ce408 Mon Sep 17 00:00:00 2001
From: Theron Savery <47454777+tsavery-DD@users.noreply.github.com>
Date: Mon, 25 Feb 2019 09:17:56 -0500
Subject: [PATCH] NSO - added validate_certs parameter to allow for ignoring of
 SSL certificates (#51981)

* added validate_certs paramter to allow for ignoring of SSL certificates

* formatting

* updated NSO unit tests with validate_certs variable

* fixed NSO tests
---
 lib/ansible/module_utils/network/nso/nso.py   | 12 +++++++----
 lib/ansible/plugins/doc_fragments/nso.py      |  5 +++++
 .../module_utils/network/nso/test_nso.py      | 20 +++++++++----------
 test/units/modules/network/nso/nso_module.py  |  2 +-
 .../modules/network/nso/test_nso_action.py    | 15 +++++++++-----
 .../modules/network/nso/test_nso_config.py    |  9 ++++++---
 .../modules/network/nso/test_nso_query.py     |  3 ++-
 .../modules/network/nso/test_nso_show.py      |  3 ++-
 .../modules/network/nso/test_nso_verify.py    |  3 ++-
 9 files changed, 46 insertions(+), 26 deletions(-)

diff --git a/lib/ansible/module_utils/network/nso/nso.py b/lib/ansible/module_utils/network/nso/nso.py
index e6c400a430..c62a9f91e6 100644
--- a/lib/ansible/module_utils/network/nso/nso.py
+++ b/lib/ansible/module_utils/network/nso/nso.py
@@ -23,6 +23,7 @@ nso_argument_spec = dict(
     username=dict(type='str', required=True, fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
     password=dict(type='str', required=True, no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
     timeout=dict(type='int', default=300),
+    validate_certs=dict(type='bool', default=False)
 )
 
 
@@ -52,10 +53,10 @@ class NsoException(Exception):
 
 
 class JsonRpc(object):
-    def __init__(self, url, timeout):
+    def __init__(self, url, timeout, validate_certs):
         self._url = url
         self._timeout = timeout
-
+        self._validate_certs = validate_certs
         self._id = 0
         self._trans = {}
         self._headers = {'Content-Type': 'application/json'}
@@ -224,7 +225,8 @@ class JsonRpc(object):
         data = json.dumps(payload)
         resp = open_url(
             self._url, timeout=self._timeout,
-            method='POST', data=data, headers=self._headers)
+            method='POST', data=data, headers=self._headers,
+            validate_certs=self._validate_certs)
         if resp.code != 200:
             raise NsoException(
                 'NSO returned HTTP code {0}, expected 200'.format(resp.status), {})
@@ -635,7 +637,9 @@ class ValueBuilder(object):
 
 
 def connect(params):
-    client = JsonRpc(params['url'], params['timeout'])
+    client = JsonRpc(params['url'],
+                     params['timeout'],
+                     params['validate_certs'])
     client.login(params['username'], params['password'])
     return client
 
diff --git a/lib/ansible/plugins/doc_fragments/nso.py b/lib/ansible/plugins/doc_fragments/nso.py
index 49a3b08e98..1f25eb7b2a 100644
--- a/lib/ansible/plugins/doc_fragments/nso.py
+++ b/lib/ansible/plugins/doc_fragments/nso.py
@@ -25,4 +25,9 @@ options:
     type: int
     default: 300
     version_added: "2.6"
+  validate_certs:
+    description: When set to true, validates the SSL certificate of NSO when
+                 using SSL
+    required: false
+    default: false
 '''
diff --git a/test/units/module_utils/network/nso/test_nso.py b/test/units/module_utils/network/nso/test_nso.py
index 567af586a5..a6ff445ead 100644
--- a/test/units/module_utils/network/nso/test_nso.py
+++ b/test/units/module_utils/network/nso/test_nso.py
@@ -331,7 +331,7 @@ class MockResponse(object):
         return self.body
 
 
-def mock_call(calls, url, timeout, data=None, headers=None, method=None):
+def mock_call(calls, url, timeout, validate_certs, data=None, headers=None, method=None):
     result = calls[0]
     del calls[0]
 
@@ -366,7 +366,7 @@ class TestJsonRpc(unittest.TestCase):
             MockResponse('exists', {'path': '/not-exists'}, 200, '{"result": {"exists": false}}')
         ]
         open_url_mock.side_effect = lambda *args, **kwargs: mock_call(calls, *args, **kwargs)
-        client = nso.JsonRpc('http://localhost:8080/jsonrpc', 10)
+        client = nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False)
         self.assertEquals(True, client.exists('/exists'))
         self.assertEquals(False, client.exists('/not-exists'))
 
@@ -379,7 +379,7 @@ class TestJsonRpc(unittest.TestCase):
             MockResponse('exists', {'path': '/list{missing-parent}/list{child}'}, 200, '{"error":{"type":"data.not_found"}}')
         ]
         open_url_mock.side_effect = lambda *args, **kwargs: mock_call(calls, *args, **kwargs)
-        client = nso.JsonRpc('http://localhost:8080/jsonrpc', 10)
+        client = nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False)
         self.assertEquals(False, client.exists('/list{missing-parent}/list{child}'))
 
         self.assertEqual(0, len(calls))
@@ -400,7 +400,7 @@ class TestValueBuilder(unittest.TestCase):
             SCHEMA_DATA['/an:id-name-leaf'])
         schema = schema_data['data']
 
-        vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10))
+        vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False))
         vb.build(parent, None, 'ansible-nso:id-two', schema)
         self.assertEquals(1, len(vb.values))
         value = vb.values[0]
@@ -425,7 +425,7 @@ class TestValueBuilder(unittest.TestCase):
             SCHEMA_DATA['/an:id-name-values/id-name-value'])
         schema = schema_data['data']
 
-        vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10))
+        vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False))
         vb.build(parent, 'id-name-value', [{'name': 'ansible-nso:id-one', 'value': '1'}], schema)
         self.assertEquals(1, len(vb.values))
         value = vb.values[0]
@@ -450,7 +450,7 @@ class TestValueBuilder(unittest.TestCase):
             SCHEMA_DATA['/test:test'])
         schema = schema_data['data']
 
-        vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10))
+        vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False))
         vb.build(parent, None, [{'name': 'direct', 'direct-child': 'direct-value'},
                                 {'name': 'nested', 'nested-child': 'nested-value'}], schema)
         self.assertEquals(2, len(vb.values))
@@ -480,7 +480,7 @@ class TestValueBuilder(unittest.TestCase):
             SCHEMA_DATA['/test:test'])
         schema = schema_data['data']
 
-        vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10))
+        vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False))
         vb.build(parent, None, {'device-list': ['one', 'two']}, schema)
         self.assertEquals(1, len(vb.values))
         value = vb.values[0]
@@ -503,7 +503,7 @@ class TestValueBuilder(unittest.TestCase):
             SCHEMA_DATA['/test:test'])
         schema = schema_data['data']
 
-        vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10))
+        vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False))
         vb.build(parent, None, {'device-list': ['one', 'two']}, schema)
         self.assertEquals(3, len(vb.values))
         value = vb.values[0]
@@ -537,7 +537,7 @@ class TestValueBuilder(unittest.TestCase):
             'c': '3',
         }
 
-        vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10))
+        vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False))
         vb.build(parent, None, values, schema)
         self.assertEquals(3, len(vb.values))
         value = vb.values[0]
@@ -570,7 +570,7 @@ class TestValueBuilder(unittest.TestCase):
             'b': '2'
         }
 
-        vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10))
+        vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False))
         vb.build(parent, None, values, schema)
         self.assertEquals(2, len(vb.values))
         value = vb.values[0]
diff --git a/test/units/modules/network/nso/nso_module.py b/test/units/modules/network/nso/nso_module.py
index 4b61cb731a..ac3cf0a657 100644
--- a/test/units/modules/network/nso/nso_module.py
+++ b/test/units/modules/network/nso/nso_module.py
@@ -55,7 +55,7 @@ class MockResponse(object):
         return self.body
 
 
-def mock_call(calls, url, timeout, data=None, headers=None, method=None):
+def mock_call(calls, url, timeout, validate_certs, data=None, headers=None, method=None):
     if len(calls) == 0:
         raise ValueError('no call mock for method {0}({1})'.format(
             url, data))
diff --git a/test/units/modules/network/nso/test_nso_action.py b/test/units/modules/network/nso/test_nso_action.py
index 7af5ace55e..5d7f34ec5d 100644
--- a/test/units/modules/network/nso/test_nso_action.py
+++ b/test/units/modules/network/nso/test_nso_action.py
@@ -48,7 +48,8 @@ class TestNsoAction(nso_module.TestNsoModule):
             'username': 'user', 'password': 'password',
             'url': 'http://localhost:8080/jsonrpc',
             'path': path,
-            'input': action_input
+            'input': action_input,
+            'validate_certs': False
         })
         self.execute_module(failed=True, msg='NSO get_schema invalid params. path = /ncs:devices/device{ce0}/missing')
 
@@ -72,7 +73,8 @@ class TestNsoAction(nso_module.TestNsoModule):
             'username': 'user', 'password': 'password',
             'url': 'http://localhost:8080/jsonrpc',
             'path': path,
-            'input': action_input
+            'input': action_input,
+            'validate_certs': False
         })
         self.execute_module(failed=True, msg='/ncs:devices/device{ce0}/description is not an action')
 
@@ -98,7 +100,8 @@ class TestNsoAction(nso_module.TestNsoModule):
             'username': 'user', 'password': 'password',
             'url': 'http://localhost:8080/jsonrpc',
             'path': path,
-            'input': action_input
+            'input': action_input,
+            'validate_certs': False
         })
         self.execute_module(changed=True, output=output)
 
@@ -126,7 +129,8 @@ class TestNsoAction(nso_module.TestNsoModule):
             'url': 'http://localhost:8080/jsonrpc',
             'path': path,
             'input': action_input,
-            'output_required': output
+            'output_required': output,
+            'validate_certs': False
         })
         self.execute_module(changed=True, output=output)
 
@@ -154,7 +158,8 @@ class TestNsoAction(nso_module.TestNsoModule):
             'url': 'http://localhost:8080/jsonrpc',
             'path': path,
             'input': action_input,
-            'output_required': output_mismatch
+            'output_required': output_mismatch,
+            'validate_certs': False
         })
         self.execute_module(failed=True, msg="version value mismatch. expected [{'name': 'v1'}, {'name': 'v3'}] got [{'name': 'v1'}, {'name': 'v2'}]")
 
diff --git a/test/units/modules/network/nso/test_nso_config.py b/test/units/modules/network/nso/test_nso_config.py
index 19bfb5eda0..11c744d3db 100644
--- a/test/units/modules/network/nso/test_nso_config.py
+++ b/test/units/modules/network/nso/test_nso_config.py
@@ -49,7 +49,8 @@ class TestNsoConfig(nso_module.TestNsoModule):
         data = nso_module.load_fixture('config_config.json')
         set_module_args({
             'username': 'user', 'password': 'password',
-            'url': 'http://localhost:8080/jsonrpc', 'data': data
+            'url': 'http://localhost:8080/jsonrpc', 'data': data,
+            'validate_certs': False
         })
         self.execute_module(failed=True)
 
@@ -77,7 +78,8 @@ class TestNsoConfig(nso_module.TestNsoModule):
         data = nso_module.load_fixture('config_empty_data.json')
         set_module_args({
             'username': 'user', 'password': 'password',
-            'url': 'http://localhost:8080/jsonrpc', 'data': data
+            'url': 'http://localhost:8080/jsonrpc', 'data': data,
+            'validate_certs': False
         })
         self.execute_module(changed=False, changes=[], diffs=[])
 
@@ -120,7 +122,8 @@ class TestNsoConfig(nso_module.TestNsoModule):
         data = nso_module.load_fixture('config_config.json')
         set_module_args({
             'username': 'user', 'password': 'password',
-            'url': 'http://localhost:8080/jsonrpc', 'data': data
+            'url': 'http://localhost:8080/jsonrpc', 'data': data,
+            'validate_certs': False
         })
         self.execute_module(changed=True, changes=[
             {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/ce-device', 'type': 'set', 'from': None, 'to': 'ce6'},
diff --git a/test/units/modules/network/nso/test_nso_query.py b/test/units/modules/network/nso/test_nso_query.py
index c3be7c04d0..02ee963654 100644
--- a/test/units/modules/network/nso/test_nso_query.py
+++ b/test/units/modules/network/nso/test_nso_query.py
@@ -48,7 +48,8 @@ class TestNsoQuery(nso_module.TestNsoModule):
             'username': 'user', 'password': 'password',
             'url': 'http://localhost:8080/jsonrpc',
             'xpath': xpath,
-            'fields': fields
+            'fields': fields,
+            'validate_certs': False
         })
         self.execute_module(changed=False, output=[["test", "1.0"]])
 
diff --git a/test/units/modules/network/nso/test_nso_show.py b/test/units/modules/network/nso/test_nso_show.py
index fa33f2fbf8..aa1abbc796 100644
--- a/test/units/modules/network/nso/test_nso_show.py
+++ b/test/units/modules/network/nso/test_nso_show.py
@@ -91,7 +91,8 @@ class TestNsoShow(nso_module.TestNsoModule):
             'username': 'user', 'password': 'password',
             'url': 'http://localhost:8080/jsonrpc',
             'path': path,
-            'operational': True
+            'operational': True,
+            'validate_certs': False
         })
         self.execute_module(changed=False, output={"data": {}})
 
diff --git a/test/units/modules/network/nso/test_nso_verify.py b/test/units/modules/network/nso/test_nso_verify.py
index 4a4a366a89..b39e9eef46 100644
--- a/test/units/modules/network/nso/test_nso_verify.py
+++ b/test/units/modules/network/nso/test_nso_verify.py
@@ -101,7 +101,8 @@ class TestNsoVerify(nso_module.TestNsoModule):
         data = nso_module.load_fixture('verify_violation_data.json')
         set_module_args({
             'username': 'user', 'password': 'password',
-            'url': 'http://localhost:8080/jsonrpc', 'data': data
+            'url': 'http://localhost:8080/jsonrpc', 'data': data,
+            'validate_certs': False
         })
         self.execute_module(changed=False)