From b4ce4e15716b9d6dbb951295097e36675e1deb85 Mon Sep 17 00:00:00 2001 From: ftntcorecse <43451990+ftntcorecse@users.noreply.github.com> Date: Fri, 30 Nov 2018 03:24:41 -0700 Subject: [PATCH] Fortinet FortiManager Device Group Module (#46086) * fmgr_device_group PR candidate * fgmr_device_group PR candidate * PR candidate * PR candidate * Fixing Edits. * Fixing Edits. * Fixing Authors * Removed State Parameter and replaced with Mode, per request of justjais --- .../network/fortimanager/fmgr_device_group.py | 379 ++++++++++++++++++ .../fixtures/test_fmgr_device_group.json | 226 +++++++++++ .../fortimanager/test_fmgr_device_group.py | 271 +++++++++++++ 3 files changed, 876 insertions(+) create mode 100644 lib/ansible/modules/network/fortimanager/fmgr_device_group.py create mode 100644 test/units/modules/network/fortimanager/fixtures/test_fmgr_device_group.json create mode 100644 test/units/modules/network/fortimanager/test_fmgr_device_group.py diff --git a/lib/ansible/modules/network/fortimanager/fmgr_device_group.py b/lib/ansible/modules/network/fortimanager/fmgr_device_group.py new file mode 100644 index 0000000000..f1e656d916 --- /dev/null +++ b/lib/ansible/modules/network/fortimanager/fmgr_device_group.py @@ -0,0 +1,379 @@ +#!/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 = { + "metadata_version": "1.1", + "status": ["preview"], + "supported_by": "community" +} + +DOCUMENTATION = ''' +--- +module: fmgr_device_group +version_added: "2.8" +author: + - Luke Weighall (@lweighall) + - Andrew Welsh (@Ghilli3) + - Jim Huber (@p4r4n0y1ng) +short_description: Alter FortiManager device groups. +description: + - Add or edit device groups and assign devices to device groups FortiManager Device Manager using JSON RPC API. + +options: + adom: + description: + - The ADOM the configuration should belong to. + required: false + default: root + + vdom: + description: + - The VDOM of the Fortigate you want to add, must match the device in FMGR. Usually root. + required: false + default: root + + 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 + + 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 + + grp_name: + description: + - The name of the device group. + required: false + + grp_desc: + description: + - The description of the device group. + required: false + + grp_members: + description: + - A comma separated list of device names or device groups to be added as members to the device group. + - If Group Members are defined, and mode="delete", only group members will be removed. + - If you want to delete a group itself, you must omit this parameter from the task in playbook. + required: false + +''' + + +EXAMPLES = ''' +- name: CREATE DEVICE GROUP + fmgr_device_group: + host: "{{inventory_hostname}}" + username: "{{ username }}" + password: "{{ password }}" + grp_name: "TestGroup" + grp_desc: "CreatedbyAnsible" + adom: "ansible" + mode: "add" + +- name: CREATE DEVICE GROUP 2 + fmgr_device_group: + host: "{{inventory_hostname}}" + username: "{{ username }}" + password: "{{ password }}" + grp_name: "AnsibleGroup" + grp_desc: "CreatedbyAnsible" + adom: "ansible" + mode: "add" + +- name: ADD DEVICES TO DEVICE GROUP + fmgr_device_group: + host: "{{inventory_hostname}}" + username: "{{ username }}" + password: "{{ password }}" + mode: "add" + grp_name: "TestGroup" + grp_members: "FGT1,FGT2" + adom: "ansible" + vdom: "root" + +- name: REMOVE DEVICES TO DEVICE GROUP + fmgr_device_group: + host: "{{inventory_hostname}}" + username: "{{ username }}" + password: "{{ password }}" + mode: "delete" + grp_name: "TestGroup" + grp_members: "FGT1,FGT2" + adom: "ansible" + +- name: DELETE DEVICE GROUP + fmgr_device_group: + host: "{{inventory_hostname}}" + username: "{{ username }}" + password: "{{ password }}" + grp_name: "AnsibleGroup" + grp_desc: "CreatedbyAnsible" + mode: "delete" + adom: "ansible" +''' + +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 get_groups(fmg, paramgram): + """ + This method is used GET the HA PEERS of a FortiManager Node + """ + + datagram = { + "method": "get" + } + + url = '/dvmdb/adom/{adom}/group'.format(adom=paramgram["adom"]) + response = fmg.get(url, datagram) + return response + + +def add_device_group(fmg, paramgram): + """ + This method is used to add device groups + """ + # INIT A BASIC OBJECTS + response = (-100000, {"msg": "Illegal or malformed paramgram discovered. System Exception"}) + url = "" + mode = paramgram["mode"] + + datagram = { + "name": paramgram["grp_name"], + "desc": paramgram["grp_desc"], + "os_type": "fos" + } + + url = '/dvmdb/adom/{adom}/group'.format(adom=paramgram["adom"]) + + # 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) + + return response + + +def delete_device_group(fmg, paramgram): + """ + This method is used to add devices to the FMGR + """ + # INIT A BASIC OBJECTS + response = (-100000, {"msg": "Illegal or malformed paramgram discovered. System Exception"}) + url = "" + + datagram = { + "adom": paramgram["adom"], + "name": paramgram["grp_name"] + } + + url = '/dvmdb/adom/{adom}/group/{grp_name}'.format(adom=paramgram["adom"], grp_name=paramgram["grp_name"]) + response = fmg.delete(url, datagram) + return response + + +def add_group_member(fmg, paramgram): + """ + This method is used to update device groups add members + """ + # INIT A BASIC OBJECTS + response = (-100000, {"msg": "Illegal or malformed paramgram discovered. System Exception"}) + url = "" + device_member_list = paramgram["grp_members"].replace(' ', '') + device_member_list = device_member_list.split(',') + + for dev_name in device_member_list: + datagram = {'name': dev_name, 'vdom': paramgram["vdom"]} + + url = '/dvmdb/adom/{adom}/group/{grp_name}/object member'.format(adom=paramgram["adom"], + grp_name=paramgram["grp_name"]) + response = fmg.add(url, datagram) + + return response + + +def delete_group_member(fmg, paramgram): + """ + This method is used to update device groups add members + """ + # INIT A BASIC OBJECTS + response = (-100000, {"msg": "Illegal or malformed paramgram discovered. System Exception"}) + url = "" + device_member_list = paramgram["grp_members"].replace(' ', '') + device_member_list = device_member_list.split(',') + + for dev_name in device_member_list: + datagram = {'name': dev_name, 'vdom': paramgram["vdom"]} + + url = '/dvmdb/adom/{adom}/group/{grp_name}/object member'.format(adom=paramgram["adom"], + grp_name=paramgram["grp_name"]) + response = fmg.delete(url, datagram) + + return response + + +# 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: + pass + module.fail_json(msg=msg) + + # SUBMISSION ERROR + if len(results) > 0: + if msg == "NULL": + try: + msg = results[1]['status']['message'] + except: + 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 = msg + " -- LOGOUT ON FAIL IS OFF, MOVING ON" + return return_msg + else: + if logout_on_success: + fmg.logout() + module.exit_json(msg=msg, **results[1]) + else: + return_msg = msg + " -- LOGOUT ON SUCCESS IS OFF, MOVING ON TO REST OF CODE" + return return_msg + + +def main(): + argument_spec = dict( + adom=dict(required=False, type="str", default="root"), + vdom=dict(required=False, type="str", default="root"), + host=dict(required=True, type="str"), + username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"])), + password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True), + mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"), + grp_desc=dict(required=False, type="str"), + grp_name=dict(required=True, type="str"), + grp_members=dict(required=False, type="str"), + ) + + module = AnsibleModule(argument_spec, supports_check_mode=True, ) + + # handle params passed via provider and insure they are represented as the data type expected by fortimanager + paramgram = { + "mode": module.params["mode"], + "grp_name": module.params["grp_name"], + "grp_desc": module.params["grp_desc"], + "grp_members": module.params["grp_members"], + "adom": module.params["adom"], + "vdom": module.params["vdom"] + } + + # validate required arguments are passed; not used in argument_spec to allow params to be called from provider + # check if params are set + if module.params["host"] is None or module.params["username"] is None or module.params["password"] 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: + # START SESSION LOGIC + + # PROCESS THE GROUP ADDS FIRST + if paramgram["grp_name"] is not None and paramgram["mode"] in ["add", "set", "update"]: + # add device group + results = add_device_group(fmg, paramgram) + if results[0] != 0 and results[0] != -2: + fmgr_logout(fmg, module, msg="Failed to Add Device Group", results=results, good_codes=[0]) + + # PROCESS THE GROUP MEMBER ADDS + if paramgram["grp_members"] is not None and paramgram["mode"] in ["add", "set", "update"]: + # assign devices to device group + results = add_group_member(fmg, paramgram) + if results[0] != 0 and results[0] != -2: + fmgr_logout(fmg, module, msg="Failed to Add Group Member(s)", results=results, good_codes=[0]) + + # PROCESS THE GROUP MEMBER DELETES + if paramgram["grp_members"] is not None and paramgram["mode"] == "delete": + # remove devices grom a group + results = delete_group_member(fmg, paramgram) + if results[0] != 0: + fmgr_logout(fmg, module, msg="Failed to Delete Group Member(s)", results=results, good_codes=[0]) + + # PROCESS THE GROUP DELETES, ONLY IF GRP_MEMBERS IS NOT NULL TOO + if paramgram["grp_name"] is not None and paramgram["mode"] == "delete" and paramgram["grp_members"] is None: + # delete device group + results = delete_device_group(fmg, paramgram) + if results[0] != 0: + fmgr_logout(fmg, module, msg="Failed to Delete Device Group", results=results, good_codes=[0]) + + # RETURN THE RESULTS + return module.exit_json(**results[1]) + + +if __name__ == "__main__": + main() diff --git a/test/units/modules/network/fortimanager/fixtures/test_fmgr_device_group.json b/test/units/modules/network/fortimanager/fixtures/test_fmgr_device_group.json new file mode 100644 index 0000000000..1b25817d0e --- /dev/null +++ b/test/units/modules/network/fortimanager/fixtures/test_fmgr_device_group.json @@ -0,0 +1,226 @@ +{ + "add_group_member": [ + { + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/dvmdb/adom/ansible/group/TestGroup/object member" + }, + "paramgram_used": { + "grp_desc": null, + "adom": "ansible", + "grp_members": "FGT1,FGT2", + "state": "present", + "grp_name": "TestGroup", + "vdom": "root" + }, + "post_method": "add" + }, + { + "paramgram_used": { + "grp_desc": null, + "adom": "ansible", + "grp_members": "FGT1,FGT2", + "state": "present", + "grp_name": "TestGroup", + "vdom": "root" + }, + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/dvmdb/adom/ansible/group/TestGroup/object member" + }, + "post_method": "add" + }, + { + "paramgram_used": { + "grp_desc": null, + "adom": "ansible", + "grp_members": "FGT3", + "state": "present", + "grp_name": "testtest", + "vdom": "root" + }, + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/dvmdb/adom/ansible/group/testtest/object member" + }, + "post_method": "add" + } + ], + "delete_device_group": [ + { + "paramgram_used": { + "grp_desc": "CreatedbyAnsible", + "adom": "ansible", + "grp_members": null, + "state": "absent", + "grp_name": "TestGroup", + "vdom": "root" + }, + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/dvmdb/adom/ansible/group/TestGroup" + }, + "post_method": "delete" + }, + { + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/dvmdb/adom/ansible/group/testtest" + }, + "paramgram_used": { + "grp_desc": "CreatedbyAnsible", + "adom": "ansible", + "grp_members": null, + "state": "absent", + "grp_name": "testtest", + "vdom": "root" + }, + "post_method": "delete" + } + ], + "add_device_group": [ + { + "paramgram_used": { + "grp_desc": "CreatedbyAnsible", + "adom": "ansible", + "grp_members": null, + "state": "present", + "grp_name": "TestGroup", + "vdom": "root" + }, + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/dvmdb/adom/ansible/group" + }, + "post_method": "add" + }, + { + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/dvmdb/adom/ansible/group" + }, + "paramgram_used": { + "grp_desc": "CreatedbyAnsible", + "adom": "ansible", + "grp_members": null, + "state": "present", + "grp_name": "testtest", + "vdom": "root" + }, + "post_method": "add" + }, + { + "paramgram_used": { + "grp_desc": null, + "adom": "ansible", + "grp_members": "FGT1,FGT2", + "state": "present", + "grp_name": "TestGroup", + "vdom": "root" + }, + "raw_response": { + "status": { + "message": "Object already exists", + "code": -2 + }, + "url": "/dvmdb/adom/ansible/group" + }, + "post_method": "add" + }, + { + "raw_response": { + "status": { + "message": "Object already exists", + "code": -2 + }, + "url": "/dvmdb/adom/ansible/group" + }, + "paramgram_used": { + "grp_desc": null, + "adom": "ansible", + "grp_members": "FGT3", + "state": "present", + "grp_name": "testtest", + "vdom": "root" + }, + "post_method": "add" + } + ], + "delete_group_member": [ + { + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/dvmdb/adom/ansible/group/testtest/object member" + }, + "paramgram_used": { + "grp_desc": null, + "adom": "ansible", + "grp_members": "FGT3", + "state": "absent", + "grp_name": "testtest", + "vdom": "root" + }, + "post_method": "delete" + }, + { + "paramgram_used": { + "grp_desc": null, + "adom": "ansible", + "grp_members": "FGT1,FGT2", + "state": "absent", + "grp_name": "TestGroup", + "vdom": "root" + }, + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/dvmdb/adom/ansible/group/TestGroup/object member" + }, + "post_method": "delete" + }, + { + "raw_response": { + "status": { + "message": "OK", + "code": 0 + }, + "url": "/dvmdb/adom/ansible/group/TestGroup/object member" + }, + "paramgram_used": { + "grp_desc": null, + "adom": "ansible", + "grp_members": "FGT1,FGT2", + "state": "absent", + "grp_name": "TestGroup", + "vdom": "root" + }, + "post_method": "delete" + } + ] +} diff --git a/test/units/modules/network/fortimanager/test_fmgr_device_group.py b/test/units/modules/network/fortimanager/test_fmgr_device_group.py new file mode 100644 index 0000000000..0e7a50bb2a --- /dev/null +++ b/test/units/modules/network/fortimanager/test_fmgr_device_group.py @@ -0,0 +1,271 @@ +# 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_device_group +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_add_device_group(fixture_data, mocker): + mocker.patch( + "pyFMG.fortimgr.FortiManager._post_request", + side_effect=fixture_data) + + paramgram_used = { + 'grp_desc': 'CreatedbyAnsible', + 'adom': 'ansible', + 'grp_members': None, + 'state': 'present', + 'grp_name': 'TestGroup', + 'vdom': 'root', + 'mode': 'add'} + output = fmgr_device_group.add_device_group(fmg_instance, paramgram_used) + # + # grp_desc: CreatedbyAnsible + # adom: ansible + # grp_members: None + # state: present + # grp_name: TestGroup + # vdom: root + # mode: add + # + assert output['raw_response']['status']['code'] == 0 + paramgram_used = { + 'grp_desc': 'CreatedbyAnsible', + 'adom': 'ansible', + 'grp_members': None, + 'state': 'present', + 'grp_name': 'testtest', + 'vdom': 'root', + 'mode': 'add'} + output = fmgr_device_group.add_device_group(fmg_instance, paramgram_used) + # + # grp_desc: CreatedbyAnsible + # adom: ansible + # grp_members: None + # state: present + # grp_name: testtest + # vdom: root + # mode: add + # + assert output['raw_response']['status']['code'] == 0 + paramgram_used = { + 'grp_desc': None, + 'adom': 'ansible', + 'grp_members': 'FGT1,FGT2', + 'state': 'present', + 'grp_name': 'TestGroup', + 'vdom': 'root', + 'mode': 'add'} + output = fmgr_device_group.add_device_group(fmg_instance, paramgram_used) + # + # grp_desc: None + # adom: ansible + # grp_members: FGT1,FGT2 + # state: present + # grp_name: TestGroup + # vdom: root + # mode: add + # + assert output['raw_response']['status']['code'] == -2 + paramgram_used = { + 'grp_desc': None, + 'adom': 'ansible', + 'grp_members': 'FGT3', + 'state': 'present', + 'grp_name': 'testtest', + 'vdom': 'root', + 'mode': 'add'} + output = fmgr_device_group.add_device_group(fmg_instance, paramgram_used) + # + # grp_desc: None + # adom: ansible + # grp_members: FGT3 + # state: present + # grp_name: testtest + # vdom: root + # mode: add + # + assert output['raw_response']['status']['code'] == -2 + + +def test_delete_device_group(fixture_data, mocker): + mocker.patch( + "pyFMG.fortimgr.FortiManager._post_request", + side_effect=fixture_data) + + paramgram_used = { + 'grp_desc': 'CreatedbyAnsible', + 'adom': 'ansible', + 'grp_members': None, + 'state': 'absent', + 'grp_name': 'TestGroup', + 'vdom': 'root', + 'mode': 'delete'} + output = fmgr_device_group.delete_device_group( + fmg_instance, paramgram_used) + # + # grp_desc: CreatedbyAnsible + # adom: ansible + # grp_members: None + # state: absent + # grp_name: TestGroup + # vdom: root + # mode: delete + # + assert output['raw_response']['status']['code'] == 0 + paramgram_used = { + 'grp_desc': 'CreatedbyAnsible', + 'adom': 'ansible', + 'grp_members': None, + 'state': 'absent', + 'grp_name': 'testtest', + 'vdom': 'root', + 'mode': 'delete'} + output = fmgr_device_group.delete_device_group( + fmg_instance, paramgram_used) + # + # grp_desc: CreatedbyAnsible + # adom: ansible + # grp_members: None + # state: absent + # grp_name: testtest + # vdom: root + # mode: delete + # + assert output['raw_response']['status']['code'] == 0 + + +def test_add_group_member(fixture_data, mocker): + mocker.patch( + "pyFMG.fortimgr.FortiManager._post_request", + side_effect=fixture_data) + + paramgram_used = { + 'grp_desc': None, + 'adom': 'ansible', + 'grp_members': 'FGT1,FGT2', + 'state': 'present', + 'grp_name': 'TestGroup', + 'vdom': 'root', + 'mode': 'add'} + output = fmgr_device_group.add_group_member(fmg_instance, paramgram_used) + # + # grp_desc: None + # adom: ansible + # grp_members: FGT1,FGT2 + # state: present + # grp_name: TestGroup + # vdom: root + # mode: add + # + + assert output['raw_response']['status']['code'] == 0 + paramgram_used = { + 'grp_desc': None, + 'adom': 'ansible', + 'grp_members': 'FGT3', + 'state': 'present', + 'grp_name': 'testtest', + 'vdom': 'root', + 'mode': 'add'} + output = fmgr_device_group.add_group_member(fmg_instance, paramgram_used) + # + # grp_desc: None + # adom: ansible + # grp_members: FGT3 + # state: present + # grp_name: testtest + # vdom: root + # mode: add + # + assert output['raw_response']['status']['code'] == 0 + + +def test_delete_group_member(fixture_data, mocker): + mocker.patch( + "pyFMG.fortimgr.FortiManager._post_request", + side_effect=fixture_data) + + paramgram_used = { + 'grp_desc': None, + 'adom': 'ansible', + 'grp_members': 'FGT3', + 'state': 'absent', + 'grp_name': 'testtest', + 'vdom': 'root', + 'mode': 'delete'} + output = fmgr_device_group.delete_group_member( + fmg_instance, paramgram_used) + # + # grp_desc: None + # adom: ansible + # grp_members: FGT3 + # state: absent + # grp_name: testtest + # vdom: root + # mode: delete + # + assert output['raw_response']['status']['code'] == 0 + paramgram_used = { + 'grp_desc': None, + 'adom': 'ansible', + 'grp_members': 'FGT1,FGT2', + 'state': 'absent', + 'grp_name': 'TestGroup', + 'vdom': 'root', + 'mode': 'delete'} + output = fmgr_device_group.delete_group_member( + fmg_instance, paramgram_used) + # + # grp_desc: None + # adom: ansible + # grp_members: FGT1,FGT2 + # state: absent + # grp_name: TestGroup + # vdom: root + # mode: delete + #