Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cloudinit/net/eni.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,10 @@ def _render_iface(self, iface, render_hwaddress=False):
sections = []
subnets = iface.get('subnets', {})
accept_ra = iface.pop('accept-ra', None)
ethernet_wol = iface.pop('wakeonlan', None)
if ethernet_wol:
# Specify WOL setting 'g' for using "Magic Packet"
iface['ethernet-wol'] = 'g'
if subnets:
for index, subnet in enumerate(subnets):
ipv4_subnet_mtu = None
Expand Down
6 changes: 5 additions & 1 deletion cloudinit/net/network_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,9 @@ def handle_physical(self, command):
accept_ra = command.get('accept-ra', None)
if accept_ra is not None:
accept_ra = util.is_true(accept_ra)
wakeonlan = command.get('wakeonlan', None)
if wakeonlan is not None:
wakeonlan = util.is_true(wakeonlan)
iface.update({
'name': command.get('name'),
'type': command.get('type'),
Expand All @@ -379,7 +382,8 @@ def handle_physical(self, command):
'address': None,
'gateway': None,
'subnets': subnets,
'accept-ra': accept_ra
'accept-ra': accept_ra,
'wakeonlan': wakeonlan,
})
self._network_state['interfaces'].update({command.get('name'): iface})
self.dump_network_state()
Expand Down
5 changes: 5 additions & 0 deletions cloudinit/net/sysconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,11 @@ def _render_iface_shared(cls, iface, iface_cfg, flavor):
if new_key:
iface_cfg[new_key] = old_value

# only set WakeOnLan for physical interfaces
if ('wakeonlan' in iface and iface['wakeonlan'] and
iface['type'] == 'physical'):
iface_cfg['ETHTOOL_OPTS'] = 'wol g'

@classmethod
def _render_subnets(cls, iface_cfg, subnets, has_default_route, flavor):
# setting base values
Expand Down
143 changes: 143 additions & 0 deletions tests/unittests/test_net.py
Original file line number Diff line number Diff line change
Expand Up @@ -1378,6 +1378,89 @@
"""),
},
},
'wakeonlan_disabled': {
'expected_eni': textwrap.dedent("""\
auto lo
iface lo inet loopback

auto iface0
iface iface0 inet dhcp
""").rstrip(' '),
'expected_netplan': textwrap.dedent("""
network:
ethernets:
iface0:
dhcp4: true
wakeonlan: false
version: 2
"""),
'expected_sysconfig_opensuse': {
'ifcfg-iface0': textwrap.dedent("""\
BOOTPROTO=dhcp4
STARTMODE=auto
"""),
},
'expected_sysconfig_rhel': {
'ifcfg-iface0': textwrap.dedent("""\
BOOTPROTO=dhcp
DEVICE=iface0
NM_CONTROLLED=no
ONBOOT=yes
TYPE=Ethernet
USERCTL=no
"""),
},
'yaml_v2': textwrap.dedent("""\
version: 2
ethernets:
iface0:
dhcp4: true
wakeonlan: false
""").rstrip(' '),
},
'wakeonlan_enabled': {
'expected_eni': textwrap.dedent("""\
auto lo
iface lo inet loopback

auto iface0
iface iface0 inet dhcp
ethernet-wol g
Comment thread
dermotbradley marked this conversation as resolved.
""").rstrip(' '),
'expected_netplan': textwrap.dedent("""
network:
ethernets:
iface0:
dhcp4: true
wakeonlan: true
version: 2
"""),
'expected_sysconfig_opensuse': {
'ifcfg-iface0': textwrap.dedent("""\
BOOTPROTO=dhcp4
ETHTOOL_OPTS="wol g"
Comment thread
dermotbradley marked this conversation as resolved.
STARTMODE=auto
"""),
},
'expected_sysconfig_rhel': {
'ifcfg-iface0': textwrap.dedent("""\
BOOTPROTO=dhcp
DEVICE=iface0
ETHTOOL_OPTS="wol g"
Comment thread
dermotbradley marked this conversation as resolved.
NM_CONTROLLED=no
ONBOOT=yes
TYPE=Ethernet
USERCTL=no
"""),
},
'yaml_v2': textwrap.dedent("""\
version: 2
ethernets:
iface0:
dhcp4: true
wakeonlan: true
Comment thread
dermotbradley marked this conversation as resolved.
""").rstrip(' '),
},
'all': {
'expected_eni': ("""\
auto lo
Expand Down Expand Up @@ -3293,6 +3376,20 @@ def test_dhcpv6_stateful_config(self):
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)

def test_wakeonlan_disabled_config_v2(self):
entry = NETWORK_CONFIGS['wakeonlan_disabled']
found = self._render_and_read(network_config=yaml.load(
entry['yaml_v2']))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)

def test_wakeonlan_enabled_config_v2(self):
entry = NETWORK_CONFIGS['wakeonlan_enabled']
found = self._render_and_read(network_config=yaml.load(
entry['yaml_v2']))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)

def test_check_ifcfg_rh(self):
"""ifcfg-rh plugin is added NetworkManager.conf if conf present."""
render_dir = self.tmp_dir()
Expand Down Expand Up @@ -3829,6 +3926,20 @@ def test_dhcpv6_stateless_config(self):
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)

def test_wakeonlan_disabled_config_v2(self):
entry = NETWORK_CONFIGS['wakeonlan_disabled']
found = self._render_and_read(network_config=yaml.load(
entry['yaml_v2']))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)

def test_wakeonlan_enabled_config_v2(self):
entry = NETWORK_CONFIGS['wakeonlan_enabled']
found = self._render_and_read(network_config=yaml.load(
entry['yaml_v2']))
self._compare_files_to_expected(entry[self.expected_name], found)
self._assert_headers(found)

def test_render_v4_and_v6(self):
entry = NETWORK_CONFIGS['v4_and_v6']
found = self._render_and_read(network_config=yaml.load(entry['yaml']))
Expand Down Expand Up @@ -4478,6 +4589,22 @@ def testsimple_render_dhcpv6_stateful(self):
entry['expected_netplan'].splitlines(),
files['/etc/netplan/50-cloud-init.yaml'].splitlines())

def testsimple_wakeonlan_disabled_config_v2(self):
entry = NETWORK_CONFIGS['wakeonlan_disabled']
files = self._render_and_read(network_config=yaml.load(
entry['yaml_v2']))
self.assertEqual(
entry['expected_netplan'].splitlines(),
files['/etc/netplan/50-cloud-init.yaml'].splitlines())

def testsimple_wakeonlan_enabled_config_v2(self):
entry = NETWORK_CONFIGS['wakeonlan_enabled']
files = self._render_and_read(network_config=yaml.load(
entry['yaml_v2']))
self.assertEqual(
entry['expected_netplan'].splitlines(),
files['/etc/netplan/50-cloud-init.yaml'].splitlines())

def testsimple_render_all(self):
entry = NETWORK_CONFIGS['all']
files = self._render_and_read(network_config=yaml.load(entry['yaml']))
Expand Down Expand Up @@ -4645,6 +4772,22 @@ def testsimple_render_dhcpv6_reject_ra(self):
entry['expected_eni'].splitlines(),
files['/etc/network/interfaces'].splitlines())

def testsimple_wakeonlan_disabled_config_v2(self):
entry = NETWORK_CONFIGS['wakeonlan_disabled']
files = self._render_and_read(network_config=yaml.load(
entry['yaml_v2']))
self.assertEqual(
entry['expected_eni'].splitlines(),
files['/etc/network/interfaces'].splitlines())

def testsimple_wakeonlan_enabled_config_v2(self):
entry = NETWORK_CONFIGS['wakeonlan_enabled']
files = self._render_and_read(network_config=yaml.load(
entry['yaml_v2']))
self.assertEqual(
entry['expected_eni'].splitlines(),
files['/etc/network/interfaces'].splitlines())

def testsimple_render_manual(self):
"""Test rendering of 'manual' for 'type' and 'control'.

Expand Down