Repository: ansible-collections/community.vmware

Issue:
vmware_host_firewall_manager: Remove deprecated functionality
##### SUMMARY
There's a deprecation in `vmware_host_firewall_manager` that we should address in version 3.

##### ISSUE TYPE
- Feature Idea

##### COMPONENT NAME
vmware_host_firewall_manager

##### ADDITIONAL INFORMATION
https://github.com/ansible-collections/community.vmware/blob/67b9506a306da2caec9a2eda60003fd54a9df71e/plugins/modules/vmware_host_firewall_manager.py#L402-L410


Discussion:

Resolving patch:
diff --git a/plugins/modules/vmware_host_firewall_manager.py b/plugins/modules/vmware_host_firewall_manager.py
--- a/plugins/modules/vmware_host_firewall_manager.py
+++ b/plugins/modules/vmware_host_firewall_manager.py
@@ -41,6 +41,39 @@
     default: []
     type: list
     elements: dict
+    suboptions:
+        name:
+            description:
+            - Rule set name.
+            type: str
+            required: true
+        enabled:
+            description:
+            - Whether the rule set is enabled or not.
+            type: bool
+            required: true
+        allowed_hosts:
+            description:
+            - Define the allowed hosts for this rule set.
+            type: dict
+            suboptions:
+                all_ip:
+                    description:
+                    - Whether all hosts should be allowed or not.
+                    type: bool
+                    required: true
+                ip_address:
+                    description:
+                    - List of allowed IP addresses.
+                    type: list
+                    elements: str
+                    default: []
+                ip_network:
+                    description:
+                    - List of allowed IP networks.
+                    type: list
+                    elements: str
+                    default: []
 extends_documentation_fragment:
 - community.vmware.vmware.documentation
 
@@ -221,35 +254,27 @@ def check_params(self):
 
         for rule_option in self.rule_options:
             rule_name = rule_option.get('name')
-            if rule_name is None:
-                self.module.fail_json(msg="Please specify rule.name for rule set"
-                                          " as it is required parameter.")
             hosts_with_rule_name = [h for h, r in rules_by_host.items() if rule_name in r]
             hosts_without_rule_name = set([i.name for i in self.hosts]) - set(hosts_with_rule_name)
             if hosts_without_rule_name:
                 self.module.fail_json(msg="rule named '%s' wasn't found on hosts: %s" % (
                     rule_name, hosts_without_rule_name))
 
-            if 'enabled' not in rule_option:
-                self.module.fail_json(msg="Please specify rules.enabled for rule set"
-                                          " %s as it is required parameter." % rule_name)
-
-            allowed_hosts = rule_option.get('allowed_hosts', {})
-            ip_addresses = allowed_hosts.get('ip_address', [])
-            ip_networks = allowed_hosts.get('ip_network', [])
-            for ip_address in ip_addresses:
-                try:
-                    is_ipaddress(ip_address)
-                except ValueError:
-                    self.module.fail_json(msg="The provided IP address %s is not a valid IP"
-                                              " for the rule %s" % (ip_address, rule_name))
-
-            for ip_network in ip_networks:
-                try:
-                    is_ipaddress(ip_network)
-                except ValueError:
-                    self.module.fail_json(msg="The provided IP network %s is not a valid network"
-                                              " for the rule %s" % (ip_network, rule_name))
+            allowed_hosts = rule_option.get('allowed_hosts')
+            if allowed_hosts is not None:
+                for ip_address in allowed_hosts.get('ip_address'):
+                    try:
+                        is_ipaddress(ip_address)
+                    except ValueError:
+                        self.module.fail_json(msg="The provided IP address %s is not a valid IP"
+                                                  " for the rule %s" % (ip_address, rule_name))
+
+                for ip_network in allowed_hosts.get('ip_network'):
+                    try:
+                        is_ipaddress(ip_network)
+                    except ValueError:
+                        self.module.fail_json(msg="The provided IP network %s is not a valid network"
+                                                  " for the rule %s" % (ip_network, rule_name))
 
     def ensure(self):
         """
@@ -297,10 +322,10 @@ def ensure(self):
                 rule_allowed_ips = set(permitted_networking['allowed_hosts']['ip_address'])
                 rule_allowed_networks = set(permitted_networking['allowed_hosts']['ip_network'])
 
-                allowed_hosts = rule_option.get('allowed_hosts', {})
-                playbook_allows_all = allowed_hosts.get('all_ip', False)
-                playbook_allowed_ips = set(allowed_hosts.get('ip_address', []))
-                playbook_allowed_networks = set(allowed_hosts.get('ip_network', []))
+                allowed_hosts = rule_option.get('allowed_hosts')
+                playbook_allows_all = False if allowed_hosts is None else allowed_hosts.get('all_ip')
+                playbook_allowed_ips = set([]) if allowed_hosts is None else set(allowed_hosts.get('ip_address'))
+                playbook_allowed_networks = set([]) if allowed_hosts is None else set(allowed_hosts.get('ip_network'))
 
                 # compare what is configured on the firewall rule with what the playbook provides
                 allowed_all_ips_different = bool(rule_allows_all != playbook_allows_all)
@@ -371,7 +396,24 @@ def main():
     argument_spec.update(
         cluster_name=dict(type='str', required=False),
         esxi_hostname=dict(type='str', required=False),
-        rules=dict(type='list', default=list(), required=False, elements='dict'),
+        rules=dict(
+            type='list',
+            default=list(),
+            required=False,
+            elements='dict',
+            options=dict(
+                name=dict(type='str', required=True),
+                enabled=dict(type='bool', required=True),
+                allowed_hosts=dict(
+                    type='dict',
+                    options=dict(
+                        all_ip=dict(type='bool', required=True),
+                        ip_address=dict(type='list', elements='str', default=list()),
+                        ip_network=dict(type='list', elements='str', default=list()),
+                    ),
+                ),
+            ),
+        ),
     )
 
     module = AnsibleModule(
@@ -382,29 +424,6 @@ def main():
         supports_check_mode=True
     )
 
-    for rule_option in module.params.get("rules", []):
-        if 'allowed_hosts' in rule_option:
-            if isinstance(rule_option['allowed_hosts'], list):
-                if len(rule_option['allowed_hosts']) == 1:
-                    allowed_hosts = rule_option['allowed_hosts'][0]
-                    rule_option['allowed_hosts'] = allowed_hosts
-                    module.deprecate(
-                        msg='allowed_hosts should be a dict, not a list',
-                        version='3.0.0',
-                        collection_name='community.vmware'
-                    )
-        if not rule_option.get("enabled"):
-            continue
-        try:
-            isinstance(rule_option["allowed_hosts"]["all_ip"], bool)
-        except (KeyError, IndexError):
-            module.deprecate(
-                msg=('Please adjust your playbook to ensure the `allowed_hosts` '
-                     'entries come with an `all_ip` key (boolean).'),
-                version='3.0.0',
-                collection_name='community.vmware'
-            )
-
     vmware_firewall_manager = VmwareFirewallManager(module)
     vmware_firewall_manager.check_params()
     vmware_firewall_manager.ensure()


Test patch:
diff --git a/tests/integration/targets/vmware_host_firewall_manager/tasks/main.yml b/tests/integration/targets/vmware_host_firewall_manager/tasks/main.yml
--- a/tests/integration/targets/vmware_host_firewall_manager/tasks/main.yml
+++ b/tests/integration/targets/vmware_host_firewall_manager/tasks/main.yml
@@ -6,234 +6,255 @@
   vars:
     setup_attach_host: true
 
-- name: Enable vvold rule set on all hosts of {{ ccr1 }}
-  vmware_host_firewall_manager:
-    hostname: "{{ vcenter_hostname }}"
-    username: "{{ vcenter_username }}"
-    password: "{{ vcenter_password }}"
-    validate_certs: false
-    cluster_name: "{{ ccr1 }}"
-    rules:
-      - name: vvold
-        enabled: true
-        allowed_hosts:
-          all_ip: true
-  register: all_hosts_result
-- debug: msg="{{ all_hosts_result }}"
-- name: ensure everything is changed for all hosts of {{ ccr1 }}
-  assert:
-    that:
-        - all_hosts_result.changed
-        - all_hosts_result.rule_set_state is defined
-
-- name: ensure info are gathered for all hosts of {{ ccr1 }}
-  assert:
-    that:
-        - all_hosts_result.rule_set_state[item]['vvold']['current_state'] == true
-        - all_hosts_result.rule_set_state[item]['vvold']['desired_state'] == true
-        - all_hosts_result.rule_set_state[item]['vvold']['previous_state'] == False
-  with_items:
-    - '{{ esxi1 }}'
-    - '{{ esxi2 }}'
-
-- name: Disable vvold for {{ host1 }}
-  vmware_host_firewall_manager:
-    hostname: "{{ vcenter_hostname }}"
-    username: "{{ vcenter_username }}"
-    password: "{{ vcenter_password }}"
-    validate_certs: false
-    esxi_hostname: '{{ esxi1 }}'
-    rules:
-      - name: vvold
-        enabled: false
-  register: host_result
-- debug: msg="{{ host_result }}"
-- name: ensure vvold is disabled for {{ host1 }}
-  assert:
-    that:
-        - host_result.changed
-        - host_result.rule_set_state is defined
-
-- name: ensure info are gathered for {{ host1 }}
-  assert:
-    that:
-        - host_result.rule_set_state[item]['vvold']['current_state'] == False
-        - host_result.rule_set_state[item]['vvold']['desired_state'] == False
-        - host_result.rule_set_state[item]['vvold']['previous_state'] == true
-  with_items:
-    - '{{ esxi1 }}'
-
-- name: Enable vvold rule set on all hosts of {{ ccr1 }} in check mode
-  vmware_host_firewall_manager:
-    hostname: "{{ vcenter_hostname }}"
-    username: "{{ vcenter_username }}"
-    password: "{{ vcenter_password }}"
-    validate_certs: false
-    cluster_name: "{{ ccr1 }}"
-    rules:
-      - name: vvold
-        enabled: true
-        allowed_hosts:
-          all_ip: true
-  register: all_hosts_result_check_mode
-  check_mode: true
-- debug: var=all_hosts_result_check_mode
-- name: ensure everything is changed for all hosts of {{ ccr1 }}
-  assert:
-    that:
-        - all_hosts_result_check_mode.changed
-        - all_hosts_result_check_mode.rule_set_state is defined
-
-- name: ensure info are gathered for all hosts of {{ ccr1 }}
-  assert:
-    that:
-        - all_hosts_result_check_mode.rule_set_state[esxi1]['vvold']['current_state'] == true
-        - all_hosts_result_check_mode.rule_set_state[esxi2]['vvold']['current_state'] == true
-        - all_hosts_result_check_mode.rule_set_state[esxi2]['vvold']['desired_state'] == true
-
-- name: Disable vvold for {{ host1 }} in check mode
-  vmware_host_firewall_manager:
-    hostname: "{{ vcenter_hostname }}"
-    username: "{{ vcenter_username }}"
-    password: "{{ vcenter_password }}"
-    validate_certs: false
-    esxi_hostname: '{{ esxi1 }}'
-    rules:
-      - name: vvold
-        enabled: false
-  register: host_result_check_mode
-  check_mode: true
-- debug: msg="{{ host_result_check_mode }}"
-- name: ensure vvold is disabled for {{ host1 }}
-  assert:
+- name: Run tests and clean up
+  block:
+    - name: Enable vvold rule set on all hosts of {{ ccr1 }}
+      community.vmware.vmware_host_firewall_manager:
+        hostname: "{{ vcenter_hostname }}"
+        username: "{{ vcenter_username }}"
+        password: "{{ vcenter_password }}"
+        validate_certs: false
+        cluster_name: "{{ ccr1 }}"
+        rules:
+          - name: vvold
+            enabled: true
+            allowed_hosts:
+              all_ip: true
+      register: all_hosts_result
+
+    - debug: msg="{{ all_hosts_result }}"
+
+    - name: ensure everything is changed for all hosts of {{ ccr1 }}
+      assert:
+        that:
+          - all_hosts_result.changed
+          - all_hosts_result.rule_set_state is defined
+
+    - name: ensure info are gathered for all hosts of {{ ccr1 }}
+      assert:
+        that:
+          - all_hosts_result.rule_set_state[item]['vvold']['current_state'] == true
+          - all_hosts_result.rule_set_state[item]['vvold']['desired_state'] == true
+          - all_hosts_result.rule_set_state[item]['vvold']['previous_state'] == False
+      with_items:
+        - '{{ esxi1 }}'
+        - '{{ esxi2 }}'
+
+    - name: Disable vvold for {{ host1 }}
+      community.vmware.vmware_host_firewall_manager:
+        hostname: "{{ vcenter_hostname }}"
+        username: "{{ vcenter_username }}"
+        password: "{{ vcenter_password }}"
+        validate_certs: false
+        esxi_hostname: '{{ esxi1 }}'
+        rules:
+          - name: vvold
+            enabled: false
+      register: host_result
+
+    - debug: msg="{{ host_result }}"
+
+    - name: ensure vvold is disabled for {{ host1 }}
+      assert:
+        that:
+          - host_result.changed
+          - host_result.rule_set_state is defined
+
+    - name: ensure info are gathered for {{ host1 }}
+      assert:
+        that:
+          - host_result.rule_set_state[item]['vvold']['current_state'] == False
+          - host_result.rule_set_state[item]['vvold']['desired_state'] == False
+          - host_result.rule_set_state[item]['vvold']['previous_state'] == true
+      with_items:
+        - '{{ esxi1 }}'
+
+    - name: Enable vvold rule set on all hosts of {{ ccr1 }} in check mode
+      community.vmware.vmware_host_firewall_manager:
+        hostname: "{{ vcenter_hostname }}"
+        username: "{{ vcenter_username }}"
+        password: "{{ vcenter_password }}"
+        validate_certs: false
+        cluster_name: "{{ ccr1 }}"
+        rules:
+          - name: vvold
+            enabled: true
+            allowed_hosts:
+              all_ip: true
+      register: all_hosts_result_check_mode
+      check_mode: true
+
+    - debug: var=all_hosts_result_check_mode
+
+    - name: ensure everything is changed for all hosts of {{ ccr1 }}
+      assert:
+        that:
+          - all_hosts_result_check_mode.changed
+          - all_hosts_result_check_mode.rule_set_state is defined
+
+    - name: ensure info are gathered for all hosts of {{ ccr1 }}
+      assert:
+        that:
+          - all_hosts_result_check_mode.rule_set_state[esxi1]['vvold']['current_state'] == true
+          - all_hosts_result_check_mode.rule_set_state[esxi2]['vvold']['current_state'] == true
+          - all_hosts_result_check_mode.rule_set_state[esxi2]['vvold']['desired_state'] == true
+
+    - name: Disable vvold for {{ host1 }} in check mode
+      community.vmware.vmware_host_firewall_manager:
+        hostname: "{{ vcenter_hostname }}"
+        username: "{{ vcenter_username }}"
+        password: "{{ vcenter_password }}"
+        validate_certs: false
+        esxi_hostname: '{{ esxi1 }}'
+        rules:
+          - name: vvold
+            enabled: false
+      register: host_result_check_mode
+      check_mode: true
+
+    - debug: msg="{{ host_result_check_mode }}"
+
+    - name: ensure vvold is disabled for {{ host1 }}
+      assert:
         that:
-        - host_result_check_mode.changed == False
-        - host_result_check_mode.rule_set_state is defined
-
-- name: ensure info are gathered for {{ host1 }}
-  assert:
-    that:
-        - host_result_check_mode.rule_set_state[item]['vvold']['current_state'] == False
-        - host_result_check_mode.rule_set_state[item]['vvold']['desired_state'] == False
-        - host_result_check_mode.rule_set_state[item]['vvold']['previous_state'] == False
-  with_items:
-    - '{{ esxi1 }}'
-
-- name: Configure CIMHttpServer rule set on all hosts of {{ ccr1 }}
-  vmware_host_firewall_manager:
-    hostname: "{{ vcenter_hostname }}"
-    username: "{{ vcenter_username }}"
-    password: "{{ vcenter_password }}"
-    validate_certs: false
-    cluster_name: "{{ ccr1 }}"
-    rules:
-      - name: CIMHttpServer
-        enabled: true
-        allowed_hosts:
-          all_ip: false
-          ip_address:
-            - "192.168.100.11"
-            - "192.168.100.12"
-          ip_network:
-            - "192.168.200.0/24"
-  register: all_hosts_ip_specific
-- debug: var=all_hosts_ip_specific
-- name: ensure everything is changed for all hosts of {{ ccr1 }}
-  assert:
-    that:
-      - all_hosts_ip_specific.changed
-      - all_hosts_ip_specific.rule_set_state is defined
-
-- name: ensure CIMHttpServer is configured for all hosts in {{ ccr1 }}
-  assert:
-    that:
-      - all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['current_state'] == true
-      - all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['desired_state'] == true
-      - all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['previous_state'] == true
-      - all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['allowed_hosts']['current_allowed_all'] == False
-      - all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['allowed_hosts']['previous_allowed_all'] == true
-      - all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['allowed_hosts']['desired_allowed_all'] == False
-      - "'192.168.100.11' in all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['allowed_hosts']['current_allowed_ip']"
-      - "'192.168.100.12' in all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['allowed_hosts']['current_allowed_ip']"
-      - all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['allowed_hosts']['previous_allowed_ip'] == []
-      - "'192.168.100.11' in all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['allowed_hosts']['desired_allowed_ip']"
-      - "'192.168.100.12' in all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['allowed_hosts']['desired_allowed_ip']"
-      - all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['allowed_hosts']['current_allowed_networks'] == ["192.168.200.0/24"]
-      - all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['allowed_hosts']['previous_allowed_networks'] == []
-      - all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['allowed_hosts']['desired_allowed_networks'] == ["192.168.200.0/24"]
-  with_items:
-    - '{{ esxi1 }}'
-    - '{{ esxi2 }}'
-
-- name: Configure the NFC firewall rule to only allow traffic from one IP on one ESXi host
-  vmware_host_firewall_manager:
-    hostname: "{{ vcenter_hostname }}"
-    username: "{{ vcenter_username }}"
-    password: "{{ vcenter_password }}"
-    validate_certs: false
-    esxi_hostname: "{{ esxi1 }}"
-    rules:
-      - name: NFC
-        enabled: true
-        allowed_hosts:
-          all_ip: false
-          ip_address:
-            - "192.168.100.11"
-  register: single_host_ip_specific
-- set_fact:
-    nfc_state: "{{ single_host_ip_specific.rule_set_state[esxi1]['NFC'] }}"
-- debug: var=single_host_ip_specific
-- debug: var=nfc_state
-- name: ensure NFC is configured on that host
-  assert:
-    that:
-      - nfc_state.current_state == true
-      - nfc_state.desired_state == true
-      - nfc_state.previous_state == true
-      - nfc_state.allowed_hosts.current_allowed_all == False
-      - nfc_state.allowed_hosts.previous_allowed_all == true
-      - nfc_state.allowed_hosts.desired_allowed_all == False
-      - nfc_state.allowed_hosts.current_allowed_ip == ["192.168.100.11"]
-      - nfc_state.allowed_hosts.previous_allowed_all == true
-      - nfc_state.allowed_hosts.desired_allowed_ip == ["192.168.100.11"]
-      - nfc_state.allowed_hosts.current_allowed_networks == []
-      - nfc_state.allowed_hosts.previous_allowed_networks == []
-      - nfc_state.allowed_hosts.desired_allowed_networks == []
-
-- name: Ensure we can still pass the allowed_hosts configuration through a list for compat
-  vmware_host_firewall_manager:
-    hostname: "{{ vcenter_hostname }}"
-    username: "{{ vcenter_username }}"
-    password: "{{ vcenter_password }}"
-    validate_certs: false
-    esxi_hostname: "{{ esxi1 }}"
-    rules:
-      - name: NFC
-        enabled: true
-        allowed_hosts:
-          - all_ip: false
-            ip_address:
-              - "1.2.3.4"
-  register: using_list
-- debug: var=using_list
-- set_fact:
-    nfc_state: "{{ using_list.rule_set_state[esxi1]['NFC'] }}"
-- name: ensure the correct host is set
-  assert:
-    that:
-      - nfc_state.allowed_hosts.current_allowed_ip == ["1.2.3.4"]
-- name: Clean up the firewall rules
-  vmware_host_firewall_manager:
-    cluster_name: '{{ ccr1 }}'
-    rules:
-        - name: vvold
-          enabled: false
-        - name: CIMHttpServer
-          enabled: true
-          allowed_hosts:
-            all_ip: true
-        - name: NFC
-          enabled: true
-          allowed_hosts:
-            all_ip: true
-  ignore_errors: true
+          - host_result_check_mode.changed == False
+          - host_result_check_mode.rule_set_state is defined
+
+    - name: ensure info are gathered for {{ host1 }}
+      assert:
+        that:
+          - host_result_check_mode.rule_set_state[item]['vvold']['current_state'] == False
+          - host_result_check_mode.rule_set_state[item]['vvold']['desired_state'] == False
+          - host_result_check_mode.rule_set_state[item]['vvold']['previous_state'] == False
+      with_items:
+        - '{{ esxi1 }}'
+
+    - name: Configure CIMHttpServer rule set on all hosts of {{ ccr1 }}
+      community.vmware.vmware_host_firewall_manager:
+        hostname: "{{ vcenter_hostname }}"
+        username: "{{ vcenter_username }}"
+        password: "{{ vcenter_password }}"
+        validate_certs: false
+        cluster_name: "{{ ccr1 }}"
+        rules:
+          - name: CIMHttpServer
+            enabled: true
+            allowed_hosts:
+              all_ip: false
+              ip_address:
+                - "192.168.100.11"
+                - "192.168.100.12"
+              ip_network:
+                - "192.168.200.0/24"
+      register: all_hosts_ip_specific
+
+    - debug: var=all_hosts_ip_specific
+
+    - name: ensure everything is changed for all hosts of {{ ccr1 }}
+      assert:
+        that:
+          - all_hosts_ip_specific.changed
+          - all_hosts_ip_specific.rule_set_state is defined
+
+    - name: ensure CIMHttpServer is configured for all hosts in {{ ccr1 }}
+      assert:
+        that:
+          - all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['current_state'] == true
+          - all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['desired_state'] == true
+          - all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['previous_state'] == true
+          - all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['allowed_hosts']['current_allowed_all'] == False
+          - all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['allowed_hosts']['previous_allowed_all'] == true
+          - all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['allowed_hosts']['desired_allowed_all'] == False
+          - "'192.168.100.11' in all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['allowed_hosts']['current_allowed_ip']"
+          - "'192.168.100.12' in all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['allowed_hosts']['current_allowed_ip']"
+          - all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['allowed_hosts']['previous_allowed_ip'] == []
+          - "'192.168.100.11' in all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['allowed_hosts']['desired_allowed_ip']"
+          - "'192.168.100.12' in all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['allowed_hosts']['desired_allowed_ip']"
+          - all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['allowed_hosts']['current_allowed_networks'] == ["192.168.200.0/24"]
+          - all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['allowed_hosts']['previous_allowed_networks'] == []
+          - all_hosts_ip_specific.rule_set_state[item]['CIMHttpServer']['allowed_hosts']['desired_allowed_networks'] == ["192.168.200.0/24"]
+      with_items:
+        - '{{ esxi1 }}'
+        - '{{ esxi2 }}'
+
+    - name: Configure the NFC firewall rule to only allow traffic from one IP on one ESXi host
+      community.vmware.vmware_host_firewall_manager:
+        hostname: "{{ vcenter_hostname }}"
+        username: "{{ vcenter_username }}"
+        password: "{{ vcenter_password }}"
+        validate_certs: false
+        esxi_hostname: "{{ esxi1 }}"
+        rules:
+          - name: NFC
+            enabled: true
+            allowed_hosts:
+              all_ip: false
+              ip_address:
+                - "192.168.100.11"
+      register: single_host_ip_specific
+
+    - set_fact:
+        nfc_state: "{{ single_host_ip_specific.rule_set_state[esxi1]['NFC'] }}"
+
+    - debug: var=single_host_ip_specific
+
+    - debug: var=nfc_state
+
+    - name: ensure NFC is configured on that host
+      assert:
+        that:
+          - nfc_state.current_state == true
+          - nfc_state.desired_state == true
+          - nfc_state.previous_state == true
+          - nfc_state.allowed_hosts.current_allowed_all == False
+          - nfc_state.allowed_hosts.previous_allowed_all == true
+          - nfc_state.allowed_hosts.desired_allowed_all == False
+          - nfc_state.allowed_hosts.current_allowed_ip == ["192.168.100.11"]
+          - nfc_state.allowed_hosts.previous_allowed_all == true
+          - nfc_state.allowed_hosts.desired_allowed_ip == ["192.168.100.11"]
+          - nfc_state.allowed_hosts.current_allowed_networks == []
+          - nfc_state.allowed_hosts.previous_allowed_networks == []
+          - nfc_state.allowed_hosts.desired_allowed_networks == []
+
+    - name: Ensure we can still pass the allowed_hosts configuration through a list for compat
+      community.vmware.vmware_host_firewall_manager:
+        hostname: "{{ vcenter_hostname }}"
+        username: "{{ vcenter_username }}"
+        password: "{{ vcenter_password }}"
+        validate_certs: false
+        esxi_hostname: "{{ esxi1 }}"
+        rules:
+          - name: NFC
+            enabled: true
+            allowed_hosts:
+              all_ip: false
+              ip_address:
+                - "1.2.3.4"
+      register: using_list
+
+    - debug: var=using_list
+
+    - set_fact:
+        nfc_state: "{{ using_list.rule_set_state[esxi1]['NFC'] }}"
+
+    - name: ensure the correct host is set
+      assert:
+        that:
+          - nfc_state.allowed_hosts.current_allowed_ip == ["1.2.3.4"]
+
+  always:
+    - name: Clean up the firewall rules
+      community.vmware.vmware_host_firewall_manager:
+        cluster_name: '{{ ccr1 }}'
+        rules:
+            - name: vvold
+              enabled: false
+            - name: CIMHttpServer
+              enabled: true
+              allowed_hosts:
+                all_ip: true
+            - name: NFC
+              enabled: true
+              allowed_hosts:
+                all_ip: true
+      ignore_errors: true