diff --git a/lib/ansible/modules/network/fortimanager/fmgr_secprof_dns.py b/lib/ansible/modules/network/fortimanager/fmgr_secprof_dns.py new file mode 100644 index 00000000000..1f87a8df344 --- /dev/null +++ b/lib/ansible/modules/network/fortimanager/fmgr_secprof_dns.py @@ -0,0 +1,483 @@ +#!/usr/bin/python +# +# 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: fmgr_secprof_dns +version_added: "2.8" +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: Manage DNS security profiles in FortiManager +description: + - Manage DNS security profiles in FortiManager + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: false + default: root + + host: + description: + - The FortiManager's address. + required: true + + username: + description: + - The username associated with the account. + required: true + + password: + description: + - The password associated with the username account. + required: true + + mode: + description: + - Sets one of three modes for managing the object. + - Allows use of soft-adds instead of overwriting existing values. + choices: ['add', 'set', 'delete', 'update'] + required: false + default: add + + youtube_restrict: + type: str + description: + - Set safe search for YouTube restriction level. + - choice | strict | Enable strict safe seach for YouTube. + - choice | moderate | Enable moderate safe search for YouTube. + required: false + choices: ["strict", "moderate"] + + sdns_ftgd_err_log: + type: str + description: + - Enable/disable FortiGuard SDNS rating error logging. + - choice | disable | Disable FortiGuard SDNS rating error logging. + - choice | enable | Enable FortiGuard SDNS rating error logging. + required: false + choices: ["disable", "enable"] + + sdns_domain_log: + type: str + description: + - Enable/disable domain filtering and botnet domain logging. + - choice | disable | Disable domain filtering and botnet domain logging. + - choice | enable | Enable domain filtering and botnet domain logging. + required: false + choices: ["disable", "enable"] + + safe_search: + type: str + description: + - Enable/disable Google, Bing, and YouTube safe search. + - choice | disable | Disable Google, Bing, and YouTube safe search. + - choice | enable | Enable Google, Bing, and YouTube safe search. + required: false + choices: ["disable", "enable"] + + redirect_portal: + type: str + description: + - IP address of the SDNS redirect portal. + required: false + + name: + type: str + description: + - Profile name. + required: false + + log_all_domain: + type: str + description: + - Enable/disable logging of all domains visited (detailed DNS logging). + - choice | disable | Disable logging of all domains visited. + - choice | enable | Enable logging of all domains visited. + required: false + choices: ["disable", "enable"] + + external_ip_blocklist: + type: str + description: + - One or more external IP block lists. + required: false + + comment: + type: str + description: + - Comment for the security profile to show in the FortiManager GUI. + required: false + + block_botnet: + type: str + description: + - Enable/disable blocking botnet C&C; DNS lookups. + - choice | disable | Disable blocking botnet C&C; DNS lookups. + - choice | enable | Enable blocking botnet C&C; DNS lookups. + required: false + choices: ["disable", "enable"] + + block_action: + type: str + description: + - Action to take for blocked domains. + - choice | block | Return NXDOMAIN for blocked domains. + - choice | redirect | Redirect blocked domains to SDNS portal. + required: false + choices: ["block", "redirect"] + + domain_filter_domain_filter_table: + type: str + description: + - DNS domain filter table ID. + required: false + + ftgd_dns_options: + type: str + description: + - FortiGuard DNS filter options. + - FLAG Based Options. Specify multiple in list form. + - flag | error-allow | Allow all domains when FortiGuard DNS servers fail. + - flag | ftgd-disable | Disable FortiGuard DNS domain rating. + required: false + choices: ["error-allow", "ftgd-disable"] + + ftgd_dns_filters_action: + type: str + description: + - Action to take for DNS requests matching the category. + - choice | monitor | Allow DNS requests matching the category and log the result. + - choice | block | Block DNS requests matching the category. + required: false + choices: ["monitor", "block"] + + ftgd_dns_filters_category: + type: str + description: + - Category number. + required: false + + ftgd_dns_filters_log: + type: str + description: + - Enable/disable DNS filter logging for this DNS profile. + - choice | disable | Disable DNS filter logging. + - choice | enable | Enable DNS filter logging. + required: false + choices: ["disable", "enable"] + + +''' + +EXAMPLES = ''' + - name: DELETE Profile + fmgr_secprof_dns: + host: "{{inventory_hostname}}" + username: "{{ username }}" + password: "{{ password }}" + name: "Ansible_DNS_Profile" + comment: "Created by Ansible Module TEST" + mode: "delete" + + - name: CREATE Profile + fmgr_secprof_dns: + host: "{{inventory_hostname}}" + username: "{{ username }}" + password: "{{ password }}" + name: "Ansible_DNS_Profile" + comment: "Created by Ansible Module TEST" + mode: "set" + block_action: "block" + + +''' + +RETURN = """ +api_result: + description: full API response, includes status code and message + returned: always + type: string +""" + +from ansible.module_utils.basic import AnsibleModule, env_fallback +from ansible.module_utils.network.fortimanager.fortimanager import AnsibleFortiManager + +# check for pyFMG lib +try: + from pyFMG.fortimgr import FortiManager + + HAS_PYFMGR = True +except ImportError: + HAS_PYFMGR = False + + +############### +# START METHODS +############### + + +def fmgr_dnsfilter_profile_addsetdelete(fmg, paramgram): + """ + fmgr_dnsfilter_profile -- Your Description here, bruh + """ + + mode = paramgram["mode"] + adom = paramgram["adom"] + url = "" + datagram = {} + + response = (-100000, {"msg": "Illegal or malformed paramgram discovered. System Exception"}) + + # EVAL THE MODE PARAMETER FOR SET OR ADD + if mode in ['set', 'add', 'update']: + url = '/pm/config/adom/{adom}/obj/dnsfilter/profile'.format(adom=adom) + datagram = fmgr_del_none(fmgr_prepare_dict(paramgram)) + + # EVAL THE MODE PARAMETER FOR DELETE + elif mode == "delete": + # SET THE CORRECT URL FOR DELETE + url = '/pm/config/adom/{adom}/obj/dnsfilter/profile/{name}'.format(adom=adom, name=paramgram["name"]) + datagram = {} + + # IF MODE = SET -- USE THE 'SET' API CALL MODE + if mode == "set": + response = fmg.set(url, datagram) + # IF MODE = UPDATE -- USER THE 'UPDATE' API CALL MODE + elif mode == "update": + response = fmg.update(url, datagram) + # IF MODE = ADD -- USE THE 'ADD' API CALL MODE + elif mode == "add": + response = fmg.add(url, datagram) + # IF MODE = DELETE -- USE THE DELETE URL AND API CALL MODE + elif mode == "delete": + response = fmg.delete(url, datagram) + + return response + + +# ADDITIONAL COMMON FUNCTIONS +# FUNCTION/METHOD FOR LOGGING OUT AND ANALYZING ERROR CODES +def fmgr_logout(fmg, module, msg="NULL", results=(), good_codes=(0,), logout_on_fail=True, logout_on_success=False): + """ + THIS METHOD CONTROLS THE LOGOUT AND ERROR REPORTING AFTER AN METHOD OR FUNCTION RUNS + """ + + # VALIDATION ERROR (NO RESULTS, JUST AN EXIT) + if msg != "NULL" and len(results) == 0: + try: + fmg.logout() + except BaseException: + pass + module.fail_json(msg=msg) + + # SUBMISSION ERROR + if len(results) > 0: + if msg == "NULL": + try: + msg = results[1]['status']['message'] + except BaseException: + msg = "No status message returned from pyFMG. Possible that this was a GET with a tuple result." + + if results[0] not in good_codes: + if logout_on_fail: + fmg.logout() + module.fail_json(msg=msg, **results[1]) + else: + return msg + else: + if logout_on_success: + fmg.logout() + module.exit_json(msg=msg, **results[1]) + else: + return msg + + +# FUNCTION/METHOD FOR CONVERTING CIDR TO A NETMASK +# DID NOT USE IP ADDRESS MODULE TO KEEP INCLUDES TO A MINIMUM +def fmgr_cidr_to_netmask(cidr): + cidr = int(cidr) + mask = (0xffffffff >> (32 - cidr)) << (32 - cidr) + return (str((0xff000000 & mask) >> 24) + '.' + + str((0x00ff0000 & mask) >> 16) + '.' + + str((0x0000ff00 & mask) >> 8) + '.' + + str((0x000000ff & mask))) + + +# utility function: removing keys wih value of None, nothing in playbook for that key +def fmgr_del_none(obj): + if isinstance(obj, dict): + return type(obj)((fmgr_del_none(k), fmgr_del_none(v)) + for k, v in obj.items() if k is not None and (v is not None and not fmgr_is_empty_dict(v))) + else: + return obj + + +# utility function: remove keys that are need for the logic but the FMG API won't accept them +def fmgr_prepare_dict(obj): + list_of_elems = ["mode", "adom", "host", "username", "password"] + if isinstance(obj, dict): + obj = dict((key, fmgr_prepare_dict(value)) for (key, value) in obj.items() if key not in list_of_elems) + return obj + + +def fmgr_is_empty_dict(obj): + return_val = False + if isinstance(obj, dict): + if len(obj) > 0: + for k, v in obj.items(): + if isinstance(v, dict): + if len(v) == 0: + return_val = True + elif len(v) > 0: + for k1, v1 in v.items(): + if v1 is None: + return_val = True + elif v1 is not None: + return_val = False + return return_val + elif v is None: + return_val = True + elif v is not None: + return_val = False + return return_val + elif len(obj) == 0: + return_val = True + + return return_val + + +def fmgr_split_comma_strings_into_lists(obj): + if isinstance(obj, dict): + if len(obj) > 0: + for k, v in obj.items(): + if isinstance(v, str): + new_list = list() + if "," in v: + new_items = v.split(",") + for item in new_items: + new_list.append(item.strip()) + obj[k] = new_list + + return obj + + +############# +# END METHODS +############# + + +def main(): + argument_spec = dict( + adom=dict(type="str", default="root"), + host=dict(required=True, type="str"), + password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True, required=True), + username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"]), no_log=True, required=True), + mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"), + + youtube_restrict=dict(required=False, type="str", choices=["strict", "moderate"]), + sdns_ftgd_err_log=dict(required=False, type="str", choices=["disable", "enable"]), + sdns_domain_log=dict(required=False, type="str", choices=["disable", "enable"]), + safe_search=dict(required=False, type="str", choices=["disable", "enable"]), + redirect_portal=dict(required=False, type="str"), + name=dict(required=False, type="str"), + log_all_domain=dict(required=False, type="str", choices=["disable", "enable"]), + external_ip_blocklist=dict(required=False, type="str"), + comment=dict(required=False, type="str"), + block_botnet=dict(required=False, type="str", choices=["disable", "enable"]), + block_action=dict(required=False, type="str", choices=["block", "redirect"]), + + domain_filter_domain_filter_table=dict(required=False, type="str"), + + ftgd_dns_options=dict(required=False, type="str", choices=["error-allow", "ftgd-disable"]), + + ftgd_dns_filters_action=dict(required=False, type="str", choices=["monitor", "block"]), + ftgd_dns_filters_category=dict(required=False, type="str"), + ftgd_dns_filters_log=dict(required=False, type="str", choices=["disable", "enable"]), + + ) + + module = AnsibleModule(argument_spec, supports_check_mode=False) + + # MODULE PARAMGRAM + paramgram = { + "mode": module.params["mode"], + "adom": module.params["adom"], + "youtube-restrict": module.params["youtube_restrict"], + "sdns-ftgd-err-log": module.params["sdns_ftgd_err_log"], + "sdns-domain-log": module.params["sdns_domain_log"], + "safe-search": module.params["safe_search"], + "redirect-portal": module.params["redirect_portal"], + "name": module.params["name"], + "log-all-domain": module.params["log_all_domain"], + "external-ip-blocklist": module.params["external_ip_blocklist"], + "comment": module.params["comment"], + "block-botnet": module.params["block_botnet"], + "block-action": module.params["block_action"], + "domain-filter": { + "domain-filter-table": module.params["domain_filter_domain_filter_table"], + }, + "ftgd-dns": { + "options": module.params["ftgd_dns_options"], + "filters": { + "action": module.params["ftgd_dns_filters_action"], + "category": module.params["ftgd_dns_filters_category"], + "log": module.params["ftgd_dns_filters_log"], + } + } + } + + # CHECK IF THE HOST/USERNAME/PW EXISTS, AND IF IT DOES, LOGIN. + host = module.params["host"] + password = module.params["password"] + username = module.params["username"] + if host is None or username is None or password is None: + module.fail_json(msg="Host and username and password are required") + + # CHECK IF LOGIN FAILED + fmg = AnsibleFortiManager(module, module.params["host"], module.params["username"], module.params["password"]) + + response = fmg.login() + if response[1]['status']['code'] != 0: + module.fail_json(msg="Connection to FortiManager Failed") + + results = fmgr_dnsfilter_profile_addsetdelete(fmg, paramgram) + if results[0] != 0: + fmgr_logout(fmg, module, results=results, good_codes=[0]) + + fmg.logout() + + if results is not None: + return module.exit_json(**results[1]) + else: + return module.exit_json(msg="No results were returned from the API call.") + + +if __name__ == "__main__": + main() diff --git a/lib/ansible/modules/network/fortimanager/fmgr_sys_proxy.py b/lib/ansible/modules/network/fortimanager/fmgr_sys_proxy.py deleted file mode 100644 index 988b898fbb7..00000000000 --- a/lib/ansible/modules/network/fortimanager/fmgr_sys_proxy.py +++ /dev/null @@ -1,192 +0,0 @@ -#!/usr/bin/python -# -# 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: fmgr_sys_proxy -version_added: "2.8" -author: Andrew Welsh -short_description: Make FortiGate API calls via the FortiMananger -description: - - The FMG proxies FOS API calls via the FMG. Review FortiGate API documentation to ensure you are passing correct - parameters for both the FortiManager and FortiGate - -options: - adom: - description: - - The administrative domain (admon) the configuration belongs to - required: true - host: - description: - - The FortiManager's Address. - required: true - username: - description: - - The username to log into the FortiManager - required: true - password: - description: - - The password associated with the username account. - required: false - - action: - description: - - Specify HTTP action for the request. Either 'get' or 'post' - required: True - payload: - description: - - JSON payload of the request. The payload will be URL-encoded and becomes the "json" field in the query string for both GET and POST request. - required: False - resource: - description: - - URL on the remote device to be accessed, string - required: True - target: - description: - - FOS datasource, either device or group object - required: True - -''' - -EXAMPLES = ''' -- name: Proxy FOS requests via FMG - hosts: FortiManager - connection: local - gather_facts: False - - tasks: - - - name: Get upgrade path for FGT1 - fmgr_provision: - host: "{{ inventory_hostname }}" - username: "{{ username }}" - password: "{{ password }}" - adom: "root" - action: "get" - resource: "/api/v2/monitor/system/firmware/upgrade-paths?vdom=root" - target: ["/adom/root/device/FGT1"] - - name: Upgrade firmware of FGT1 - fmgr_provision: - host: "{{ inventory_hostname }}" - username: "{{ username }}" - password: "{{ password }}" - adom: "root" - action: "post" - payload: {source: upload, file_content: b64_encoded_string, file_name: file_name} - resource: "/api/v2/monitor/system/firmware/upgrade?vdom=vdom" - target: ["/adom/root/device/FGT1"] - -''' - -RETURN = """ -api_result: - description: full API response, includes status code and message - returned: always - type: string -""" - - -from ansible.module_utils.basic import AnsibleModule, env_fallback -from ansible.module_utils.network.fortimanager.fortimanager import AnsibleFortiManager - - -# check for pyFMG lib -try: - from pyFMG.fortimgr import FortiManager - HAS_PYFMGR = True -except ImportError: - HAS_PYFMGR = False - - -def fos_request(fmg, action, resource, target, payload, adom='root'): - - datagram = { - "data": { - # get or post - "action": action, - # dictionary of data - "payload": payload, - # FOS API URL including vdom params - "resource": resource, - # FMG device to make API calls to - "target": target - }, - - } - url = "/sys/proxy/json" - - status, response = fmg.execute(url, datagram) - return status, response - - -def main(): - - argument_spec = dict( - adom=dict(required=False, type="str"), - host=dict(required=True, type="str"), - password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True), - username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"]), no_log=True), - - action=dict(required=False, type="str"), - resource=dict(required=False, type="str"), - target=dict(required=False, type="str"), - payload=dict(required=False, type="str"), - ) - - module = AnsibleModule(argument_spec, supports_check_mode=True, ) - - action = module.params["action"] - resource = module.params["resource"] - target = module.params["target"] - payload = module.params["payload"] - - # check if params are set - if module.params["host"] is None or module.params["username"] is None: - module.fail_json(msg="Host and username are required for connection") - - # check if login failed - fmg = AnsibleFortiManager(module, module.params["host"], module.params["username"], module.params["password"]) - response = fmg.login() - - if response[1]['status']['code'] != 0: - module.fail_json(msg="Connection to FortiManager Failed") - else: - if module.params["adom"] is None: - module.params["adom"] = 'root' - - status, result = fos_request(fmg, action, resource, target, payload, module.params["adom"]) - - if not status == 0: - module.fail_json(msg="Failure showing upgrade path", **result) - - fmg.logout() - - # results is returned as a tuple - return module.exit_json(changed=True, **result) - - -if __name__ == "__main__": - main() diff --git a/test/units/modules/network/fortimanager/fixtures/test_fmgr_secprof_dns.json b/test/units/modules/network/fortimanager/fixtures/test_fmgr_secprof_dns.json new file mode 100644 index 00000000000..eac142b6e12 --- /dev/null +++ b/test/units/modules/network/fortimanager/fixtures/test_fmgr_secprof_dns.json @@ -0,0 +1,76 @@ +{ + "fmgr_dnsfilter_profile_addsetdelete": [ + { + "paramgram_used": { + "comment": "Created by Ansible Module TEST", + "ftgd-dns": { + "options": null, + "filters": { + "action": null, + "category": null, + "log": null + } + }, + "name": "Ansible_DNS_Profile", + "adom": "root", + "redirect-portal": null, + "sdns-ftgd-err-log": null, + "youtube-restrict": null, + "sdns-domain-log": null, + "domain-filter": { + "domain-filter-table": null + }, + "log-all-domain": null, + "mode": "delete", + "block-botnet": null, + "safe-search": null, + "external-ip-blocklist": null, + "block-action": null + }, + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/pm/config/adom/root/obj/dnsfilter/profile/Ansible_DNS_Profile" + }, + "post_method": "delete" + }, + { + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/pm/config/adom/root/obj/dnsfilter/profile" + }, + "paramgram_used": { + "comment": "Created by Ansible Module TEST", + "ftgd-dns": { + "options": null, + "filters": { + "action": null, + "category": null, + "log": null + } + }, + "adom": "root", + "youtube-restrict": null, + "sdns-domain-log": null, + "block-botnet": null, + "external-ip-blocklist": null, + "block-action": "block", + "name": "Ansible_DNS_Profile", + "redirect-portal": null, + "sdns-ftgd-err-log": null, + "safe-search": null, + "domain-filter": { + "domain-filter-table": null + }, + "log-all-domain": null, + "mode": "set" + }, + "post_method": "set" + } + ] +} diff --git a/test/units/modules/network/fortimanager/test_fmgr_secprof_dns.py b/test/units/modules/network/fortimanager/test_fmgr_secprof_dns.py new file mode 100644 index 00000000000..f621bbcff42 --- /dev/null +++ b/test/units/modules/network/fortimanager/test_fmgr_secprof_dns.py @@ -0,0 +1,94 @@ +# Copyright 2018 Fortinet, Inc. +# +# This program 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. +# +# This program 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 . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import json +from pyFMG.fortimgr import FortiManager +import pytest + +try: + from ansible.modules.network.fortimanager import fmgr_secprof_dns +except ImportError: + pytest.skip("Could not load required modules for testing", allow_module_level=True) + +fmg_instance = FortiManager("1.1.1.1", "admin", "") + + +def load_fixtures(): + fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format( + filename=os.path.splitext(os.path.basename(__file__))[0]) + try: + with open(fixture_path, "r") as fixture_file: + fixture_data = json.load(fixture_file) + except IOError: + return [] + return [fixture_data] + + +@pytest.fixture(scope="function", params=load_fixtures()) +def fixture_data(request): + func_name = request.function.__name__.replace("test_", "") + return request.param.get(func_name, None) + + +def test_fmgr_dnsfilter_profile_addsetdelete(fixture_data, mocker): + mocker.patch("pyFMG.fortimgr.FortiManager._post_request", side_effect=fixture_data) + # Fixture sets used:########################### + + ################################################## + # comment: Created by Ansible Module TEST + # ftgd-dns: {'options': None, 'filters': {'action': None, 'category': None, 'log': None}} + # name: Ansible_DNS_Profile + # adom: root + # redirect-portal: None + # sdns-ftgd-err-log: None + # youtube-restrict: None + # sdns-domain-log: None + # domain-filter: {'domain-filter-table': None} + # log-all-domain: None + # mode: delete + # block-botnet: None + # safe-search: None + # external-ip-blocklist: None + # block-action: None + ################################################## + ################################################## + # comment: Created by Ansible Module TEST + # ftgd-dns: {'options': None, 'filters': {'action': None, 'category': None, 'log': None}} + # adom: root + # youtube-restrict: None + # sdns-domain-log: None + # block-botnet: None + # external-ip-blocklist: None + # block-action: block + # name: Ansible_DNS_Profile + # redirect-portal: None + # sdns-ftgd-err-log: None + # safe-search: None + # domain-filter: {'domain-filter-table': None} + # log-all-domain: None + # mode: set + ################################################## + + # Test using fixture 1 # + output = fmgr_secprof_dns.fmgr_dnsfilter_profile_addsetdelete(fmg_instance, fixture_data[0]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0 + # Test using fixture 2 # + output = fmgr_secprof_dns.fmgr_dnsfilter_profile_addsetdelete(fmg_instance, fixture_data[1]['paramgram_used']) + assert output['raw_response']['status']['code'] == 0