From 9fe20123cf63df29bb286786eb5c0020c674946d Mon Sep 17 00:00:00 2001 From: Ingate Systems <44266467+ingatesystems@users.noreply.github.com> Date: Fri, 26 Oct 2018 06:17:58 +0200 Subject: [PATCH] modules: network: Add initial support for Ingate modules (#47494) * modules: network: Add initial support for Ingate modules * modules: network: Add ingate module ig_unit_information * module_utils: network: ingate: Use default 'v1' for version * modules: network: ingate: Remove unused code --- .../module_utils/network/ingate/__init__.py | 0 .../module_utils/network/ingate/common.py | 98 ++++++++++ .../modules/network/ingate/__init__.py | 0 .../network/ingate/ig_unit_information.py | 172 ++++++++++++++++++ .../utils/module_docs_fragments/ingate.py | 68 +++++++ test/units/modules/network/ingate/__init__.py | 0 .../fixtures/test_ig_unit_information.json | 21 +++ .../modules/network/ingate/ingate_module.py | 83 +++++++++ .../ingate/test_ig_unit_information.py | 62 +++++++ 9 files changed, 504 insertions(+) create mode 100644 lib/ansible/module_utils/network/ingate/__init__.py create mode 100644 lib/ansible/module_utils/network/ingate/common.py create mode 100644 lib/ansible/modules/network/ingate/__init__.py create mode 100644 lib/ansible/modules/network/ingate/ig_unit_information.py create mode 100644 lib/ansible/utils/module_docs_fragments/ingate.py create mode 100644 test/units/modules/network/ingate/__init__.py create mode 100644 test/units/modules/network/ingate/fixtures/test_ig_unit_information.json create mode 100644 test/units/modules/network/ingate/ingate_module.py create mode 100644 test/units/modules/network/ingate/test_ig_unit_information.py diff --git a/lib/ansible/module_utils/network/ingate/__init__.py b/lib/ansible/module_utils/network/ingate/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ansible/module_utils/network/ingate/common.py b/lib/ansible/module_utils/network/ingate/common.py new file mode 100644 index 00000000000..25674013a47 --- /dev/null +++ b/lib/ansible/module_utils/network/ingate/common.py @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2018, Ingate Systems AB +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +try: + from ingate import ingatesdk + HAS_INGATESDK = True +except ImportError: + HAS_INGATESDK = False + + +def ingate_argument_spec(**kwargs): + client_options = dict( + version=dict(choices=['v1'], default='v1'), + scheme=dict(choices=['http', 'https'], required=True), + address=dict(type='str', required=True), + username=dict(type='str', required=True), + password=dict(type='str', required=True, no_log=True), + port=dict(type='int'), + timeout=dict(type='int'), + verify_ssl=dict(default=True, type='bool'), + ) + argument_spec = dict( + client=dict(type='dict', required=True, + options=client_options), + ) + argument_spec.update(kwargs) + return argument_spec + + +def ingate_create_client(**kwargs): + if not HAS_INGATESDK: + raise ImportError("The Ingate Python SDK module is required") + + client_params = kwargs['client'] + + # Create API client. + api_client = ingatesdk.Client(client_params['version'], + client_params['scheme'], + client_params['address'], + client_params['username'], + client_params['password'], + port=client_params['port'], + timeout=client_params['timeout']) + + # Check if we should skip SSL Certificate verification. + verify_ssl = client_params.get('verify_ssl') + if verify_ssl is not None and not verify_ssl: + api_client.skip_verify_certificate() + + # Authenticate and get hold of a security token. + api_client.authenticate() + + # Return the client. + return api_client + + +def ingate_create_client_noauth(**kwargs): + if not HAS_INGATESDK: + raise ImportError("The Ingate Python SDK module is required") + + client_params = kwargs['client'] + + # Create API client. + api_client = ingatesdk.Client(client_params['version'], + client_params['scheme'], + client_params['address'], + client_params['username'], + client_params['password'], + port=client_params['port'], + timeout=client_params['timeout']) + + # Check if we should skip SSL Certificate verification. + verify_ssl = client_params.get('verify_ssl') + if verify_ssl and not verify_ssl: + api_client.skip_verify_certificate() + + # Return the client. + return api_client diff --git a/lib/ansible/modules/network/ingate/__init__.py b/lib/ansible/modules/network/ingate/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ansible/modules/network/ingate/ig_unit_information.py b/lib/ansible/modules/network/ingate/ig_unit_information.py new file mode 100644 index 00000000000..46aa0bab59d --- /dev/null +++ b/lib/ansible/modules/network/ingate/ig_unit_information.py @@ -0,0 +1,172 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright (c) 2018, Ingate Systems AB +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +ANSIBLE_METADATA = {'status': ['preview'], + 'supported_by': 'community', + 'metadata_version': '1.1'} + +DOCUMENTATION = ''' +--- +module: ig_unit_information +short_description: Get unit information from an Ingate SBC. +description: + - Get unit information from an Ingate SBC. +version_added: 2.8 +extends_documentation_fragment: ingate +author: + - Ingate Systems AB (@ingatesystems) +''' + +EXAMPLES = ''' +- name: Get unit information + ig_unit_information: + client: + version: v1 + scheme: http + address: 192.168.1.1 + username: alice + password: foobar +''' + +RETURN = ''' +unit-information: + description: Information about the unit + returned: success + type: complex + contains: + installid: + description: The installation identifier + returned: success + type: string + sample: any + interfaces: + description: List of interface names + returned: success + type: string + sample: eth0 eth1 eth2 eth3 eth4 eth5 + lang: + description: The unit's language + returned: success + type: string + sample: en + lic_email: + description: License email information + returned: success + type: string + sample: example@example.com + lic_mac: + description: License MAC information + returned: success + type: string + sample: any + lic_name: + description: License name information + returned: success + type: string + sample: Example Inc + macaddr: + description: The MAC address of the first interface + returned: success + type: string + sample: 52:54:00:4c:e2:07 + mode: + description: Operational mode of the unit + returned: success + type: string + sample: Siparator + modules: + description: Installed module licenses + returned: success + type: string + sample: failover vpn sip qturn ems qos rsc voipsm + patches: + description: Installed patches on the unit + returned: success + type: list + sample: [] + product: + description: The product name + returned: success + type: string + sample: Software SIParator/Firewall + serial: + description: The serial number of the unit + returned: success + type: string + sample: IG-200-839-2008-0 + systemid: + description: The system identifier of the unit + returned: success + type: string + sample: IG-200-839-2008-0 + unitname: + description: The name of the unit + returned: success + type: string + sample: Testname + version: + description: Firmware version + returned: success + type: string + sample: 6.2.0-beta2 +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.network.ingate.common import (ingate_argument_spec, + ingate_create_client) + +try: + from ingate import ingatesdk + HAS_INGATESDK = True +except ImportError: + HAS_INGATESDK = False + + +def make_request(module): + # Create client and authenticate. + api_client = ingate_create_client(**module.params) + + # Get unit information. + response = api_client.unit_information() + return response + + +def main(): + argument_spec = ingate_argument_spec() + module = AnsibleModule(argument_spec=argument_spec, + supports_check_mode=False) + if not HAS_INGATESDK: + module.fail_json(msg='The Ingate Python SDK module is required') + + result = dict(changed=False) + try: + response = make_request(module) + result.update(response[0]) + except ingatesdk.SdkError as e: + module.fail_json(msg=str(e)) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/lib/ansible/utils/module_docs_fragments/ingate.py b/lib/ansible/utils/module_docs_fragments/ingate.py new file mode 100644 index 00000000000..1b07d2dd5f6 --- /dev/null +++ b/lib/ansible/utils/module_docs_fragments/ingate.py @@ -0,0 +1,68 @@ +# Copyright (c) 2018, Ingate Systems AB +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + + +class ModuleDocFragment(object): + DOCUMENTATION = ''' +options: + client: + description: + - A dict object containing connection details. + suboptions: + version: + description: + - REST API version. + choices: [v1] + default: v1 + required: true + scheme: + description: + - Which HTTP protocol to use. + choices: [http, https] + required: true + address: + description: + - The hostname or IP address to the unit. + required: true + username: + description: + - The username of the REST API user. + required: true + password: + description: + - The password for the REST API user. + required: true + port: + description: + - Which HTTP(S) port to connect to. + required: false + timeout: + description: + - The timeout (in seconds) for REST API requests. + required: false + verify_ssl: + description: + - Verify the unit's HTTPS certificate. + default: true + required: false +notes: + - This module requires that the Ingate Python SDK is installed on the + host. To install the SDK use the pip command from your shell + C(pip install ingatesdk). +requirements: + - ingatesdk >= 1.0.6 +''' diff --git a/test/units/modules/network/ingate/__init__.py b/test/units/modules/network/ingate/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/units/modules/network/ingate/fixtures/test_ig_unit_information.json b/test/units/modules/network/ingate/fixtures/test_ig_unit_information.json new file mode 100644 index 00000000000..dc5e451c17c --- /dev/null +++ b/test/units/modules/network/ingate/fixtures/test_ig_unit_information.json @@ -0,0 +1,21 @@ +[ + { + "unit-information": { + "lic_email": "dev@ingate.com", + "lang": "en", + "product": "Software SIParator/Firewall", + "installid": "any", + "patches": [], + "lic_mac": "any", + "unitname": "testname", + "interfaces": "eth0 eth1 eth2 eth3 eth4 eth5", + "modules": "failover vpn sip qturn ems qos rsc voipsm idsips siptrunk sipswitch", + "lic_name": "Ingate", + "macaddr": "52:54:00:4c:e2:07", + "version": "6.2.0-erik", + "systemid": "IG-200-840-5001-0", + "mode": "Firewall", + "serial": "IG-200-840-5001-0" + } + } +] diff --git a/test/units/modules/network/ingate/ingate_module.py b/test/units/modules/network/ingate/ingate_module.py new file mode 100644 index 00000000000..6e11cadbdcf --- /dev/null +++ b/test/units/modules/network/ingate/ingate_module.py @@ -0,0 +1,83 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2018, Ingate Systems AB +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json + +from units.modules.utils import AnsibleExitJson, AnsibleFailJson, ModuleTestCase + + +fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') +fixture_data = {} + + +def load_fixture(name): + path = os.path.join(fixture_path, name) + + if path in fixture_data: + return fixture_data[path] + + with open(path) as file_desc: + data = file_desc.read() + + try: + data = json.loads(data) + except: + pass + + fixture_data[path] = data + return data + + +class TestIngateModule(ModuleTestCase): + + def execute_module(self, failed=False, changed=False, fixture=None): + + self.load_fixtures(fixture) + + if failed: + result = self.failed() + self.assertTrue(result['failed'], result) + else: + result = self.changed(changed) + self.assertEqual(result['changed'], changed, result) + + return result + + def failed(self): + with self.assertRaises(AnsibleFailJson) as exc: + self.module.main() + + result = exc.exception.args[0] + self.assertTrue(result['failed'], result) + return result + + def changed(self, changed=False): + with self.assertRaises(AnsibleExitJson) as exc: + self.module.main() + + result = exc.exception.args[0] + self.assertEqual(result['changed'], changed, result) + return result + + def load_fixtures(self, module_name=None): + pass diff --git a/test/units/modules/network/ingate/test_ig_unit_information.py b/test/units/modules/network/ingate/test_ig_unit_information.py new file mode 100644 index 00000000000..4c32aa09407 --- /dev/null +++ b/test/units/modules/network/ingate/test_ig_unit_information.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2018, Ingate Systems AB +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os + +from units.compat.mock import patch +from ansible.modules.network.ingate import ig_unit_information +from units.modules.utils import set_module_args +from .ingate_module import TestIngateModule, load_fixture + + +class TestUnitInformationModule(TestIngateModule): + + module = ig_unit_information + + def setUp(self): + super(TestUnitInformationModule, self).setUp() + + self.mock_make_request = patch('ansible.modules.network.ingate.' + 'ig_unit_information.make_request') + self.make_request = self.mock_make_request.start() + # ATM the Ingate Python SDK is not needed in this unit test. + self.module.HAS_INGATESDK = True + + def tearDown(self): + super(TestUnitInformationModule, self).tearDown() + self.mock_make_request.stop() + + def load_fixtures(self, fixture=None): + self.make_request.side_effect = [load_fixture(fixture)] + + def test_ig_unit_information(self): + set_module_args(dict( + client=dict( + version='v1', + address='127.0.0.1', + scheme='http', + username='alice', + password='foobar' + ))) + fixture = '%s.%s' % (os.path.basename(__file__).split('.')[0], 'json') + result = self.execute_module(fixture=fixture) + self.assertTrue('unit-information' in result)