diff --git a/changelogs/fragments/11182-vxlan-parent-bridging.yml b/changelogs/fragments/11182-vxlan-parent-bridging.yml new file mode 100644 index 00000000000..943a4618db5 --- /dev/null +++ b/changelogs/fragments/11182-vxlan-parent-bridging.yml @@ -0,0 +1,3 @@ +minor_changes: + - nmcli module - add vxlan_parent argument required for multicast vxlan_remote addresses + - nmcli module - add vxlan to list of bridgeable devices diff --git a/plugins/modules/nmcli.py b/plugins/modules/nmcli.py index 02800e8f6a4..ec18fd2e1e8 100644 --- a/plugins/modules/nmcli.py +++ b/plugins/modules/nmcli.py @@ -530,6 +530,11 @@ description: - This is only used with VXLAN - VXLAN destination IP address. type: str + vxlan_parent: + description: + - This is only used with VXLAN - VXLAN parent device (required when using a multicast remote address). + type: str + version_added: 12.1.0 vxlan_local: description: - This is only used with VXLAN - VXLAN local IP address. @@ -1454,6 +1459,17 @@ vxlan_local: 192.168.1.2 vxlan_remote: 192.168.1.5 + - name: Add VxLan via multicast on a bridge + community.general.nmcli: + type: vxlan + conn_name: vxlan_test2 + vxlan_id: 17 + vxlan_parent: eth1 + vxlan_local: 192.168.1.2 + vxlan_remote: 239.192.0.17 + slave_type: bridge + master: br0 + - name: Add gre community.general.nmcli: type: gre @@ -1784,6 +1800,7 @@ def __init__(self, module): self.ingress = module.params["ingress"] self.egress = module.params["egress"] self.vxlan_id = module.params["vxlan_id"] + self.vxlan_parent = module.params["vxlan_parent"] self.vxlan_local = module.params["vxlan_local"] self.vxlan_remote = module.params["vxlan_remote"] self.ip_tunnel_dev = module.params["ip_tunnel_dev"] @@ -2041,6 +2058,7 @@ def connection_options(self, detect_change=False): options.update( { "vxlan.id": self.vxlan_id, + "vxlan.parent": self.vxlan_parent, "vxlan.local": self.vxlan_local, "vxlan.remote": self.vxlan_remote, } @@ -2256,6 +2274,7 @@ def slave_conn_type(self): "infiniband", "ovs-port", "ovs-interface", + "vxlan", ) @property @@ -2825,6 +2844,7 @@ def main(): egress=dict(type="str"), # vxlan specific vars vxlan_id=dict(type="int"), + vxlan_parent=dict(type="str"), vxlan_local=dict(type="str"), vxlan_remote=dict(type="str"), # ip-tunnel specific vars diff --git a/tests/unit/plugins/modules/test_nmcli.py b/tests/unit/plugins/modules/test_nmcli.py index 6023763a3ed..5165250bc2e 100644 --- a/tests/unit/plugins/modules/test_nmcli.py +++ b/tests/unit/plugins/modules/test_nmcli.py @@ -843,6 +843,34 @@ vxlan.remote: 192.168.225.6 """ +TESTCASE_VXLAN_MULTICAST = [ + { + "type": "vxlan", + "conn_name": "vxlan_multicast_test", + "ifname": "vxlan-device", + "vxlan_id": 17, + "vxlan_parent": "eth1", + "vxlan_local": "192.168.1.2", + "vxlan_remote": "239.192.0.17", + "slave_type": "bridge", + "master": "br0", + "state": "present", + "_ansible_check_mode": False, + } +] + +TESTCASE_VXLAN_MULTICAST_SHOW_OUTPUT = """\ +connection.id: vxlan_multicast_test +connection.interface-name: vxlan-device +connection.autoconnect: yes +connection.slave-type: bridge +connection.master: br0 +vxlan.id: 17 +vxlan.parent: eth1 +vxlan.local: 192.168.1.2 +vxlan.remote: 239.192.0.17 +""" + TESTCASE_GRE = [ { "type": "gre", @@ -2912,6 +2940,51 @@ def test_vxlan_connection_unchanged(mocked_vxlan_connection_unchanged, capfd): assert not results["changed"] +@pytest.mark.parametrize("patch_ansible_module", TESTCASE_VXLAN_MULTICAST, indirect=["patch_ansible_module"]) +def test_create_vxlan_multicast(mocked_generic_connection_create, capfd): + """ + Test if vxlan with multicast and parent device created + """ + with pytest.raises(SystemExit): + nmcli.main() + + assert nmcli.Nmcli.execute_command.call_count == 1 + arg_list = nmcli.Nmcli.execute_command.call_args_list + args, kwargs = arg_list[0] + + assert args[0][0] == "/usr/bin/nmcli" + assert args[0][1] == "con" + assert args[0][2] == "add" + assert args[0][3] == "type" + assert args[0][4] == "vxlan" + assert args[0][5] == "con-name" + assert args[0][6] == "vxlan_multicast_test" + + args_text = list(map(to_text, args[0])) + for param in [ + "connection.interface-name", + "vxlan-device", + "vxlan.local", + "192.168.1.2", + "vxlan.remote", + "239.192.0.17", + "vxlan.id", + "17", + "vxlan.parent", + "eth1", + "connection.slave-type", + "bridge", + "connection.master", + "br0", + ]: + assert param in args_text + + out, err = capfd.readouterr() + results = json.loads(out) + assert not results.get("failed") + assert results["changed"] + + @pytest.mark.parametrize("patch_ansible_module", TESTCASE_IPIP, indirect=["patch_ansible_module"]) def test_create_ipip(mocked_generic_connection_create, capfd): """ @@ -4720,6 +4793,7 @@ def test_bond_connection_unchanged_2(mocked_generic_connection_diff_check, capfd egress=dict(type="str"), # vxlan specific vars vxlan_id=dict(type="int"), + vxlan_parent=dict(type="str"), vxlan_local=dict(type="str"), vxlan_remote=dict(type="str"), # ip-tunnel specific vars