diff --git a/CHANGELOG.md b/CHANGELOG.md index 61f7680ec..68923f66d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [2.3.0] - 2022-10-28 + +### Added + +* Added the ability to configure the `multicast_group_address` to the `dcnm_network` module + ## [2.2.0] - 2022-10-14 ### Added @@ -188,6 +194,7 @@ The Ansible Cisco Data Center Network Manager (DCNM) collection includes modules * cisco.dcnm.dcnm_network - Add and remove Networks from a DCNM managed VXLAN fabric. * cisco.dcnm.dcnm_interface - DCNM Ansible Module for managing interfaces. +[2.3.0]: https://github.com/CiscoDevNet/ansible-dcnm/compare/2.2.0...2.3.0 [2.2.0]: https://github.com/CiscoDevNet/ansible-dcnm/compare/2.1.1...2.2.0 [2.1.1]: https://github.com/CiscoDevNet/ansible-dcnm/compare/2.1.0...2.1.1 [2.1.0]: https://github.com/CiscoDevNet/ansible-dcnm/compare/2.0.1...2.1.0 diff --git a/docs/cisco.dcnm.dcnm_network_module.rst b/docs/cisco.dcnm.dcnm_network_module.rst index 8a3e2d616..6d9ec7c3b 100644 --- a/docs/cisco.dcnm.dcnm_network_module.rst +++ b/docs/cisco.dcnm.dcnm_network_module.rst @@ -354,6 +354,22 @@ Parameters
Configured MTU value should be in range 68-9216
+ + + +
+ multicast_group_address + +
+ string +
+ + + + +
The multicast IP address for the network
+ + @@ -538,7 +554,7 @@ Parameters Examples -------- -.. code-block:: yaml +.. code-block:: yaml+jinja # This module supports the following states: # diff --git a/galaxy.yml b/galaxy.yml index ab1908dcc..cdcaecc13 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: cisco name: dcnm -version: 2.2.0 +version: 2.3.0 readme: README.md authors: - Shrishail Kariyappanavar diff --git a/plugins/modules/dcnm_network.py b/plugins/modules/dcnm_network.py index 76dec9b65..9b2f4de10 100644 --- a/plugins/modules/dcnm_network.py +++ b/plugins/modules/dcnm_network.py @@ -162,6 +162,11 @@ - Configured ID value should be in range 0-1023 type: int required: false + multicast_group_address: + description: + - The multicast IP address for the network + type: str + required: false attach: description: - List of network attachment details @@ -681,6 +686,7 @@ def diff_for_create(self, want, have): dhcp2_vrf_changed = False dhcp3_vrf_changed = False dhcp_loopback_changed = False + multicast_group_address_changed = False if want.get("networkId") and want["networkId"] != have["networkId"]: self.module.fail_json( @@ -729,6 +735,8 @@ def diff_for_create(self, want, have): dhcp3_vrf_have = json_to_dict_have.get("vrfDhcp3", "") dhcp_loopback_want = json_to_dict_want.get("loopbackId", "") dhcp_loopback_have = json_to_dict_have.get("loopbackId", "") + multicast_group_address_want = json_to_dict_want.get("mcastGroup", "") + multicast_group_address_have = json_to_dict_have.get("mcastGroup", "") if vlanId_have != "": vlanId_have = int(vlanId_have) tag_want = json_to_dict_want.get("tag", "") @@ -766,6 +774,7 @@ def diff_for_create(self, want, have): or dhcp2_vrf_have != dhcp2_vrf_want or dhcp3_vrf_have != dhcp3_vrf_want or dhcp_loopback_have != dhcp_loopback_want + or multicast_group_address_have != multicast_group_address_want ): # The network updates with missing networkId will have to use existing # networkId from the instance of the same network on DCNM. @@ -801,6 +810,8 @@ def diff_for_create(self, want, have): dhcp3_vrf_changed = True if dhcp_loopback_have != dhcp_loopback_want: dhcp_loopback_changed = True + if multicast_group_address_have != multicast_group_address_want: + multicast_group_address_changed = True want.update({"networkId": have["networkId"]}) create = want @@ -855,6 +866,8 @@ def diff_for_create(self, want, have): dhcp3_vrf_changed = True if dhcp_loopback_have != dhcp_loopback_want: dhcp_loopback_changed = True + if multicast_group_address_have != multicast_group_address_want: + multicast_group_address_changed = True want.update({"networkId": have["networkId"]}) create = want @@ -876,6 +889,7 @@ def diff_for_create(self, want, have): dhcp2_vrf_changed, dhcp3_vrf_changed, dhcp_loopback_changed, + multicast_group_address_changed, ) def update_create_params(self, net): @@ -928,6 +942,7 @@ def update_create_params(self, net): "vrfDhcp2": net.get("dhcp_srvr2_vrf", ""), "vrfDhcp3": net.get("dhcp_srvr3_vrf", ""), "loopbackId": net.get("dhcp_loopback_id", ""), + "mcastGroup": net.get("multicast_group_address", ""), } if template_conf["vlanId"] is None: @@ -948,6 +963,8 @@ def update_create_params(self, net): template_conf["vrfDhcp3"] = "" if template_conf["loopbackId"] is None: template_conf["loopbackId"] = "" + if template_conf["mcastGroup"] is None: + template_conf["mcastGroup"] = "" net_upd.update({"networkTemplateConfig": json.dumps(template_conf)}) @@ -1031,6 +1048,7 @@ def get_have(self): "vrfDhcp2": json_to_dict.get("vrfDhcp2", ""), "vrfDhcp3": json_to_dict.get("vrfDhcp3", ""), "loopbackId": json_to_dict.get("loopbackId", ""), + "mcastGroup": json_to_dict.get("mcastGroup", ""), } net.update({"networkTemplateConfig": json.dumps(t_conf)}) @@ -1066,6 +1084,7 @@ def get_have(self): "vrfDhcp2": json_to_dict.get("vrfDhcp2", ""), "vrfDhcp3": json_to_dict.get("vrfDhcp3", ""), "loopbackId": json_to_dict.get("loopbackId", ""), + "mcastGroup": json_to_dict.get("mcastGroup", ""), } l2net.update({"networkTemplateConfig": json.dumps(t_conf)}) @@ -1493,6 +1512,7 @@ def get_diff_merge(self, replace=False): dhcp2_vrf_changed = {} dhcp3_vrf_changed = {} dhcp_loopback_changed = {} + multicast_group_address_changed = {} for want_c in self.want_create: found = False @@ -1517,6 +1537,7 @@ def get_diff_merge(self, replace=False): dhcp2_vrf_chg, dhcp3_vrf_chg, dhcp_loopbk_chg, + mcast_grp_chg, ) = self.diff_for_create(want_c, have_c) gw_changed.update({want_c["networkName"]: gw_chg}) tg_changed.update({want_c["networkName"]: tg_chg}) @@ -1534,6 +1555,9 @@ def get_diff_merge(self, replace=False): dhcp_loopback_changed.update( {want_c["networkName"]: dhcp_loopbk_chg} ) + multicast_group_address_changed.update( + {want_c["networkName"]: mcast_grp_chg} + ) if diff: diff_create_update.append(diff) break @@ -1648,6 +1672,7 @@ def get_diff_merge(self, replace=False): or dhcp2_vrf_changed.get(want_a["networkName"], False) or dhcp3_vrf_changed.get(want_a["networkName"], False) or dhcp_loopback_changed.get(want_a["networkName"], False) + or multicast_group_address_changed.get(want_a["networkName"], False) ): dep_net = want_a["networkName"] @@ -1735,6 +1760,7 @@ def format_diff(self): found_c.update({"dhcp_srvr2_vrf": json_to_dict.get("vrfDhcp2", "")}) found_c.update({"dhcp_srvr3_vrf": json_to_dict.get("vrfDhcp3", "")}) found_c.update({"dhcp_loopback_id": json_to_dict.get("loopbackId", "")}) + found_c.update({"multicast_group_address": json_to_dict.get("mcastGroup", "")}) found_c.update({"attach": []}) del found_c["fabric"] @@ -2052,6 +2078,7 @@ def push_to_remote(self, is_rollback=False): "vrfDhcp2": json_to_dict.get("vrfDhcp2", ""), "vrfDhcp3": json_to_dict.get("vrfDhcp3", ""), "loopbackId": json_to_dict.get("loopbackId", ""), + "mcastGroup": json_to_dict.get("mcastGroup", ""), } net.update({"networkTemplateConfig": json.dumps(t_conf)}) @@ -2145,6 +2172,7 @@ def validate_input(self): dhcp_srvr2_vrf=dict(type="str", length_max=32), dhcp_srvr3_vrf=dict(type="str", length_max=32), dhcp_loopback_id=dict(type="int", range_min=0, range_max=1023), + multicast_group_address=dict(type="ipv4", default=""), ) att_spec = dict( ip_address=dict(required=True, type="str"), @@ -2208,6 +2236,7 @@ def validate_input(self): dhcp_srvr2_vrf=dict(type="str", length_max=32), dhcp_srvr3_vrf=dict(type="str", length_max=32), dhcp_loopback_id=dict(type="int", range_min=0, range_max=1023), + multicast_group_address=dict(type="ipv4", default=""), ) att_spec = dict( ip_address=dict(required=True, type="str"), @@ -2459,6 +2488,9 @@ def dcnm_update_network_information(self, want, have, cfg): if cfg.get("dhcp_loopback_id", None) is None: json_to_dict_want["loopbackId"] = json_to_dict_have["loopbackId"] + if cfg.get("multicast_group_address", None) is None: + json_to_dict_want["mcastGroup"] = json_to_dict_have["mcastGroup"] + want.update({"networkTemplateConfig": json.dumps(json_to_dict_want)}) def update_want(self): diff --git a/tests/integration/targets/dcnm_network/tests/dcnm/self-contained-tests/sm_mcast_params.yaml b/tests/integration/targets/dcnm_network/tests/dcnm/self-contained-tests/sm_mcast_params.yaml new file mode 100644 index 000000000..3ff46d290 --- /dev/null +++ b/tests/integration/targets/dcnm_network/tests/dcnm/self-contained-tests/sm_mcast_params.yaml @@ -0,0 +1,44 @@ +- name: Setup - Remove all existing networks + cisco.dcnm.dcnm_network: + fabric: "{{ ansible_it_fabric }}" + state: deleted + +- name: Test mcast parameters for state merged + cisco.dcnm.dcnm_network: + fabric: "{{ ansible_it_fabric }}" + state: merged + config: + - net_name: ansible-net13 + vrf_name: ansible-vrf-int1 + net_id: 7009 + vlan_id: 3505 + gw_ip_subnet: '152.168.30.1/24' + mtu_l3intf: 7600 + arp_suppress: False + int_desc: 'test interface' + is_l2only: False + vlan_name: testvlan + multicast_group_address: '224.5.5.5' + attach: + - ip_address: "{{ ansible_switch1 }}" + ports: [] + deploy: True + register: result + +- assert: + that: + - 'result.changed == true' + +- name: Query fabric state until networkStatus transitions to DEPLOYED state + cisco.dcnm.dcnm_network: + fabric: "{{ ansible_it_fabric }}" + state: query + register: result + until: + - "result.response[0].parent.networkStatus is search('DEPLOYED')" + retries: 30 + delay: 2 + +- assert: + that: + - "result.response[0].parent.networkTemplateConfig.mcastGroup is search('224.5.5.5')" \ No newline at end of file diff --git a/tests/integration/targets/dcnm_network/tests/dcnm/self-contained-tests/sm_mcast_update.yaml b/tests/integration/targets/dcnm_network/tests/dcnm/self-contained-tests/sm_mcast_update.yaml new file mode 100644 index 000000000..d40f99933 --- /dev/null +++ b/tests/integration/targets/dcnm_network/tests/dcnm/self-contained-tests/sm_mcast_update.yaml @@ -0,0 +1,76 @@ +- name: Setup - Remove all existing networks + cisco.dcnm.dcnm_network: + fabric: "{{ ansible_it_fabric }}" + state: deleted + +- name: Create network with initial DEFAULT mcast parameter value + cisco.dcnm.dcnm_network: + fabric: "{{ ansible_it_fabric }}" + state: merged + config: + - net_name: ansible-net13 + vrf_name: ansible-vrf-int1 + net_id: 7009 + vlan_id: 3505 + gw_ip_subnet: '152.168.30.1/24' + mtu_l3intf: 7600 + arp_suppress: False + int_desc: 'test interface' + is_l2only: False + vlan_name: testvlan + dhcp_loopback_id: 0 + attach: + - ip_address: "{{ ansible_switch1 }}" + ports: [] + deploy: True + register: result + +- name: Query fabric state until networkStatus transitions to DEPLOYED state + cisco.dcnm.dcnm_network: + fabric: "{{ ansible_it_fabric }}" + state: query + register: result + until: + - "result.response[0].parent.networkStatus is search('DEPLOYED')" + retries: 30 + delay: 2 + +- assert: + that: + - "result.response[0].parent.networkTemplateConfig.mcastGroup is search('239.1.1.1')" + +- name: Change mcast parameter values + cisco.dcnm.dcnm_network: + fabric: "{{ ansible_it_fabric }}" + state: merged + config: + - net_name: ansible-net13 + vrf_name: ansible-vrf-int1 + net_id: 7009 + vlan_id: 3505 + gw_ip_subnet: '152.168.30.1/24' + mtu_l3intf: 7600 + arp_suppress: False + int_desc: 'test interface' + is_l2only: False + vlan_name: testvlan + multicast_group_address: '230.55.24.155' + attach: + - ip_address: "{{ ansible_switch1 }}" + ports: [] + deploy: True + register: result + +- name: Query fabric state until networkStatus transitions to DEPLOYED state + cisco.dcnm.dcnm_network: + fabric: "{{ ansible_it_fabric }}" + state: query + register: result + until: + - "result.response[0].parent.networkStatus is search('DEPLOYED')" + retries: 30 + delay: 2 + +- assert: + that: + - "result.response[0].parent.networkTemplateConfig.mcastGroup is search('230.55.24.155')" \ No newline at end of file diff --git a/tests/integration/targets/dcnm_network/tests/dcnm/self-contained-tests/so_mcast_update.yaml b/tests/integration/targets/dcnm_network/tests/dcnm/self-contained-tests/so_mcast_update.yaml new file mode 100644 index 000000000..16e2a4a1d --- /dev/null +++ b/tests/integration/targets/dcnm_network/tests/dcnm/self-contained-tests/so_mcast_update.yaml @@ -0,0 +1,105 @@ +- name: Setup - Remove all existing networks + cisco.dcnm.dcnm_network: + fabric: "{{ ansible_it_fabric }}" + state: deleted + +- name: Create network with initial mcast parameter value + cisco.dcnm.dcnm_network: + fabric: "{{ ansible_it_fabric }}" + state: merged + config: + - net_name: ansible-net13 + vrf_name: ansible-vrf-int1 + net_id: 7009 + vlan_id: 3505 + gw_ip_subnet: '152.168.30.1/24' + mtu_l3intf: 7600 + arp_suppress: False + int_desc: 'test interface' + is_l2only: False + vlan_name: testvlan_net13 + multicast_group_address: '230.101.134.144' + attach: + - ip_address: "{{ ansible_switch1 }}" + ports: [] + deploy: True + - net_name: ansible-net14 + vrf_name: ansible-vrf-int1 + net_id: 7010 + vlan_id: 3506 + gw_ip_subnet: '152.168.31.1/24' + mtu_l3intf: 7600 + arp_suppress: False + int_desc: 'test interface' + is_l2only: False + vlan_name: testvlan_net14 + multicast_group_address: '234.55.66.188' + attach: + - ip_address: "{{ ansible_switch1 }}" + ports: [] + deploy: True + register: result + +- name: Query fabric state until networkStatus transitions to DEPLOYED state + cisco.dcnm.dcnm_network: + fabric: "{{ ansible_it_fabric }}" + state: query + register: result + until: + - "result.response[0].parent.networkStatus is search('DEPLOYED')" + - "result.response[1].parent.networkStatus is search('DEPLOYED')" + retries: 30 + delay: 2 + +- set_fact: + testnet1: "{{ item }}" + when: "item.parent.displayName is search('ansible-net13')" + loop: "{{ result.response }}" + +- set_fact: + testnet2: "{{ item }}" + when: "item.parent.displayName is search('ansible-net14')" + loop: "{{ result.response }}" + +- assert: + that: + - "testnet1.parent.networkTemplateConfig.mcastGroup is search('230.101.134.144')" + - "testnet2.parent.networkTemplateConfig.mcastGroup is search('234.55.66.188')" + + +- name: Override network with a single network and change values within that newtwork + cisco.dcnm.dcnm_network: + fabric: "{{ ansible_it_fabric }}" + state: overridden + config: + - net_name: ansible-net14 + vrf_name: ansible-vrf-int1 + net_id: 7010 + vlan_id: 3506 + gw_ip_subnet: '152.168.31.1/24' + mtu_l3intf: 7600 + arp_suppress: False + int_desc: 'test interface' + is_l2only: False + vlan_name: testvlan_net14 + multicast_group_address: '238.55.66.124' + attach: + - ip_address: "{{ ansible_switch1 }}" + ports: [] + deploy: True + register: result + +- name: Query fabric state until networkStatus transitions to DEPLOYED state + cisco.dcnm.dcnm_network: + fabric: "{{ ansible_it_fabric }}" + state: query + register: result + until: + - "result.response[0].parent.networkStatus is search('DEPLOYED')" + retries: 30 + delay: 2 + +- assert: + that: + - "result.response|length == 1" + - "result.response[0].parent.networkTemplateConfig.mcastGroup is search('238.55.66.124')" \ No newline at end of file