diff --git a/lib/ansible/module_utils/utm_utils.py b/lib/ansible/module_utils/utm_utils.py index 30b362aa845..d83507be2aa 100644 --- a/lib/ansible/module_utils/utm_utils.py +++ b/lib/ansible/module_utils/utm_utils.py @@ -59,12 +59,13 @@ class UTMModule(AnsibleModule): mutually_exclusive=None, required_together=None, required_one_of=None, add_file_common_args=False, supports_check_mode=False, required_if=None): default_specs = dict( + headers=dict(type='dict', required=False, default={}), utm_host=dict(type='str', required=True), utm_port=dict(type='int', default=4444), utm_token=dict(type='str', required=True, no_log=True), utm_protocol=dict(type='str', required=False, default="https", choices=["https", "http"]), validate_certs=dict(type='bool', required=False, default=True), - state=dict(default='present', choices=['present', 'absent', 'info']) + state=dict(default='present', choices=['present', 'absent']) ) super(UTMModule, self).__init__(self._merge_specs(default_specs, argument_spec), bypass_checks, no_log, check_invalid_arguments, mutually_exclusive, required_together, required_one_of, @@ -132,6 +133,9 @@ class UTM: """ adds or updates a host object on utm """ + + combined_headers = self._combine_headers() + is_changed = False info, result = self._lookup_entry(self.module, self.request_url) if info["status"] >= 400: @@ -140,7 +144,7 @@ class UTM: data_as_json_string = self.module.jsonify(self.module.params) if result is None: response, info = fetch_url(self.module, self.request_url, method="POST", - headers={"Accept": "application/json", "Content-type": "application/json"}, + headers=combined_headers, data=data_as_json_string) if info["status"] >= 400: self.module.fail_json(msg=json.loads(info["body"])) @@ -149,8 +153,7 @@ class UTM: else: if self._is_object_changed(self.change_relevant_keys, self.module, result): response, info = fetch_url(self.module, self.request_url + result['_ref'], method="PUT", - headers={"Accept": "application/json", - "Content-type": "application/json"}, + headers=combined_headers, data=data_as_json_string) if info['status'] >= 400: self.module.fail_json(msg=json.loads(info["body"])) @@ -158,6 +161,19 @@ class UTM: result = self._clean_result(json.loads(response.read())) self.module.exit_json(result=result, changed=is_changed) + def _combine_headers(self): + """ + This will combine a header default with headers that come from the module declaration + :return: A combined headers dict + """ + default_headers = {"Accept": "application/json", "Content-type": "application/json"} + if self.module.params.get('headers') is not None: + result = default_headers.copy() + result.update(self.module.params.get('headers')) + else: + result = default_headers + return result + def _remove(self): """ removes an object from utm diff --git a/lib/ansible/utils/module_docs_fragments/utm.py b/lib/ansible/utils/module_docs_fragments/utm.py index 980d3ae76ca..92876f50b31 100644 --- a/lib/ansible/utils/module_docs_fragments/utm.py +++ b/lib/ansible/utils/module_docs_fragments/utm.py @@ -5,6 +5,11 @@ class ModuleDocFragment(object): DOCUMENTATION = """ options: + headers: + description: + - A dictionary of additional headers to be sent to POST and PUT requests. + - Is needed for some modules + required: false utm_host: description: - The REST Endpoint of the Sophos UTM. @@ -35,10 +40,8 @@ options: - The desired state of the object. - C(present) will create or update an object - C(absent) will delete an object if it was present - - C(info) will return the object details choices: - present - absent - - info default: present """ diff --git a/test/units/module_utils/test_utm_utils.py b/test/units/module_utils/test_utm_utils.py new file mode 100644 index 00000000000..5bad47ab88f --- /dev/null +++ b/test/units/module_utils/test_utm_utils.py @@ -0,0 +1,61 @@ +# This code is part of Ansible, but is an independent component. +# This particular file snippet, and this file snippet only, is BSD licensed. +# Modules you write using this snippet, which is embedded dynamically by Ansible +# still belong to the author of the module, and may assign their own license +# to the complete work. +# +# Copyright: (c) 2018, Johannes Brunswicker +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +from ansible.module_utils.utm_utils import UTM + + +class FakeModule: + def __init__(self, params): + self.params = params + + +def test_combine_headers_returns_only_default(): + expected = {"Accept": "application/json", "Content-type": "application/json"} + module = FakeModule( + params={'utm_protocol': 'utm_protocol', 'utm_host': 'utm_host', 'utm_port': 1234, 'utm_token': 'utm_token', + 'name': 'FakeName', 'headers': {}}) + result = UTM(module, "endpoint", [])._combine_headers() + assert result == expected + + +def test_combine_headers_returns_only_default2(): + expected = {"Accept": "application/json", "Content-type": "application/json"} + module = FakeModule( + params={'utm_protocol': 'utm_protocol', 'utm_host': 'utm_host', 'utm_port': 1234, 'utm_token': 'utm_token', + 'name': 'FakeName'}) + result = UTM(module, "endpoint", [])._combine_headers() + assert result == expected + + +def test_combine_headers_returns_combined(): + expected = {"Accept": "application/json", "Content-type": "application/json", + "extraHeader": "extraHeaderValue"} + module = FakeModule(params={'utm_protocol': 'utm_protocol', 'utm_host': 'utm_host', 'utm_port': 1234, + 'utm_token': 'utm_token', 'name': 'FakeName', + "headers": {"extraHeader": "extraHeaderValue"}}) + result = UTM(module, "endpoint", [])._combine_headers() + assert result == expected