diff --git a/lib/ansible/modules/net_tools/nmcli.py b/lib/ansible/modules/net_tools/nmcli.py index 3d2682da1e..6d297856b5 100644 --- a/lib/ansible/modules/net_tools/nmcli.py +++ b/lib/ansible/modules/net_tools/nmcli.py @@ -114,6 +114,12 @@ options: description: - The connection MTU, e.g. 9000. This can't be applied when creating the interface and is done once the interface has been created. - Can be used when modifying Team, VLAN, Ethernet (Future plans to implement wifi, pppoe, infiniband) + dhcp_client_id: + required: False + default: None + description: + - DHCP Client Identifier sent to the DHCP server. + version_added: "2.5" primary: required: False default: None @@ -611,6 +617,7 @@ class Nmcli(object): self.ingress = module.params['ingress'] self.egress = module.params['egress'] self.nmcli_bin = self.module.get_bin_path('nmcli', True) + self.dhcp_client_id = module.params['dhcp_client_id'] def execute_command(self, cmd, use_unsafe_shell=False, data=None): return self.module.run_command(cmd, use_unsafe_shell=use_unsafe_shell, data=data) @@ -733,6 +740,7 @@ class Nmcli(object): cmd.append(self.ifname) elif self.conn_name is not None: cmd.append(self.conn_name) + options = { 'ipv4.address': self.ip4, 'ipv4.gateway': self.gw4, @@ -741,6 +749,7 @@ class Nmcli(object): 'autoconnect': self.bool_to_string(self.autoconnect), 'ipv4.dns-search': self.dns4_search, 'ipv6.dns-search': self.dns6_search, + 'ipv4.dhcp-client-id': self.dhcp_client_id, } for key, value in options.items(): @@ -761,6 +770,7 @@ class Nmcli(object): 'autoconnect': self.bool_to_string(self.autoconnect), 'ipv4.dns-search': self.dns4_search, 'ipv6.dns-search': self.dns6_search, + 'ipv4.dhcp-client-id': self.dhcp_client_id, } for key, value in options.items(): @@ -821,17 +831,18 @@ class Nmcli(object): 'arp-interval': self.arp_interval, 'arp-ip-target': self.arp_ip_target, 'primary': self.primary, + 'ipv4.dhcp-client-id': self.dhcp_client_id, } for key, value in options.items(): if value is not None: cmd.extend([key, value]) - return cmd def modify_connection_bond(self): cmd = [self.nmcli_bin, 'con', 'mod', self.conn_name] # format for modifying bond interface + options = { 'ipv4.address': self.ip4, 'ipv4.gateway': self.gw4, @@ -847,6 +858,7 @@ class Nmcli(object): 'updelay': self.updelay, 'arp-interval': self.arp_interval, 'arp-ip-target': self.arp_ip_target, + 'ipv4.dhcp-client-id': self.dhcp_client_id, } for key, value in options.items(): @@ -897,6 +909,7 @@ class Nmcli(object): cmd.append(self.ifname) elif self.conn_name is not None: cmd.append(self.conn_name) + options = { 'ipv4.address': self.ip4, 'ipv4.gateway': self.gw4, @@ -905,6 +918,7 @@ class Nmcli(object): 'autoconnect': self.bool_to_string(self.autoconnect), 'ipv4.dns-search': self.dns4_search, 'ipv6.dns-search': self.dns6_search, + 'ipv4.dhcp-client-id': self.dhcp_client_id, } for key, value in options.items(): @@ -930,6 +944,7 @@ class Nmcli(object): 'ipv4.dns-search': self.dns4_search, 'ipv6.dns-search': self.dns6_search, '802-3-ethernet.mtu': self.mtu, + 'ipv4.dhcp-client-id': self.dhcp_client_id, } for key, value in options.items(): @@ -1209,6 +1224,7 @@ def main(): gw4=dict(required=False, default=None, type='str'), dns4=dict(required=False, default=None, type='list'), dns4_search=dict(type='list'), + dhcp_client_id=dict(required=False, default=None, type='str'), ip6=dict(required=False, default=None, type='str'), gw6=dict(required=False, default=None, type='str'), dns6=dict(required=False, default=None, type='str'), diff --git a/test/units/modules/net_tools/test_nmcli.py b/test/units/modules/net_tools/test_nmcli.py index 39d54ee962..42492d88a7 100644 --- a/test/units/modules/net_tools/test_nmcli.py +++ b/test/units/modules/net_tools/test_nmcli.py @@ -132,6 +132,20 @@ TESTCASE_VLAN = [ ] +TESTCASE_ETHERNET_DHCP = [ + { + 'type': 'ethernet', + 'conn_name': 'non_existent_nw_device', + 'ifname': 'ethernet_non_existant', + 'ip4': '10.10.10.10', + 'gw4': '10.10.10.1', + 'state': 'present', + '_ansible_check_mode': False, + 'dhcp_client_id': '00:11:22:AA:BB:CC:DD', + } +] + + def mocker_set(mocker, connection_exists=False): """ Common mocker object @@ -378,7 +392,7 @@ def test_mod_bridge_slave(mocked_generic_connection_modify): @pytest.mark.parametrize('patch_ansible_module', TESTCASE_VLAN, indirect=['patch_ansible_module']) def test_create_vlan_con(mocked_generic_connection_create): """ - Test if Bridge_slave created + Test if VLAN created """ with pytest.raises(SystemExit): @@ -395,7 +409,7 @@ def test_create_vlan_con(mocked_generic_connection_create): @pytest.mark.parametrize('patch_ansible_module', TESTCASE_VLAN, indirect=['patch_ansible_module']) def test_mod_vlan_conn(mocked_generic_connection_modify): """ - Test if Bridge_slave modified + Test if VLAN modified """ with pytest.raises(SystemExit): @@ -407,3 +421,18 @@ def test_mod_vlan_conn(mocked_generic_connection_modify): for param in ['vlan.id']: assert param in args[0] + + +@pytest.mark.parametrize('patch_ansible_module', TESTCASE_ETHERNET_DHCP, indirect=['patch_ansible_module']) +def test_eth_dhcp_client_id_con_create(mocked_generic_connection_create): + """ + Test : Ethernet connection created with DHCP_CLIENT_ID + """ + 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 'ipv4.dhcp-client-id' in args[0]