Skip to content

Commit eb74543

Browse files
Danilo Egea Gondolfodaniloegea
authored andcommitted
apply: don't assume the NM loopback connection is called "lo"
It might have any name, so we need to get the connection name dynamically.
1 parent 369c027 commit eb74543

File tree

3 files changed

+37
-7
lines changed

3 files changed

+37
-7
lines changed

netplan_cli/cli/commands/apply.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,12 @@ def command_apply(self, run_generate=True, sync=False, exit_on_error=True, state
176176
else:
177177
logging.debug('no netplan generated networkd configuration exists')
178178

179+
loopback_connection = ''
179180
if restart_nm:
180181
logging.debug('netplan generated NM configuration changed, restarting NM')
181182
if utils.nm_running():
183+
if 'lo' in nm_ifaces:
184+
loopback_connection = utils.nm_get_connection_for_interface('lo')
182185
# restarting NM does not cause new config to be applied, need to shut down devices first
183186
for device in devices:
184187
if device not in nm_ifaces:
@@ -293,8 +296,10 @@ def command_apply(self, run_generate=True, sync=False, exit_on_error=True, state
293296
# re-set via an udev rule setting "NM_UNMANAGED=1"
294297
shutil.rmtree('/run/NetworkManager/devices', ignore_errors=True)
295298
utils.systemctl_network_manager('start', sync=sync)
296-
# If 'lo' is in the nm_interfaces set we flushed it's IPs (see above) and will need to bring it
297-
# back manually. For that, we need NM up and ready to accept commands
299+
300+
# If 'lo' is in the nm_interfaces set we flushed it's IPs (see above) and disconnected it.
301+
# NM will not bring it back automatically after restarting and we need to do that manually.
302+
# For that, we need NM up and ready to accept commands
298303
if 'lo' in nm_interfaces:
299304
sync = True
300305

@@ -315,13 +320,12 @@ def command_apply(self, run_generate=True, sync=False, exit_on_error=True, state
315320
break
316321
time.sleep(0.5)
317322

318-
# If "lo" is managed by NM through Netplan, apply will flush its addresses and NM
319-
# will not bring it back automatically like other connections.
323+
# If "lo" is managed by NM through Netplan, apply will flush its addresses and disconnect it.
324+
# NM will not bring it back automatically.
320325
# This is a possible scenario with netplan-everywhere. If a user tries to change the 'lo'
321326
# connection with nmcli for example, NM will create a persistent nmconnection file and emit a YAML for it.
322-
if 'lo' in nm_interfaces:
323-
cmd = ['nmcli', 'con', 'up', 'lo']
324-
subprocess.call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
327+
if 'lo' in nm_interfaces and loopback_connection:
328+
utils.nm_bring_interface_up(loopback_connection)
325329

326330
@staticmethod
327331
def is_composite_member(composites, phy):

netplan_cli/cli/utils.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,20 @@ def nm_interfaces(paths, devices):
7878
return interfaces
7979

8080

81+
def nm_get_connection_for_interface(interface: str) -> str:
82+
output = nmcli_out(['-m', 'tabular', '-f', 'GENERAL.CONNECTION', 'device', 'show', interface])
83+
lines = output.strip().split('\n')
84+
connection = lines[1]
85+
return connection if connection != '--' else ''
86+
87+
88+
def nm_bring_interface_up(connection: str) -> None: # pragma: nocover (must be covered by NM autopkgtests)
89+
try:
90+
nmcli(['connection', 'up', connection])
91+
except subprocess.CalledProcessError:
92+
pass
93+
94+
8195
def systemctl_network_manager(action, sync=False):
8296
# If the network-manager snap is installed use its service
8397
# name rather than the one of the deb packaged NetworkManager

tests/test_utils.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,3 +371,15 @@ def test_ip_addr_flush(self):
371371
self.assertEqual(self.mock_cmd.calls(), [
372372
['ip', 'addr', 'flush', 'eth42']
373373
])
374+
375+
@patch('netplan_cli.cli.utils.nmcli_out')
376+
def test_nm_get_connection_for_interface(self, nmcli):
377+
nmcli.return_value = 'CONNECTION \nlo \n'
378+
out = utils.nm_get_connection_for_interface('lo')
379+
self.assertEqual(out, 'lo')
380+
381+
@patch('netplan_cli.cli.utils.nmcli_out')
382+
def test_nm_get_connection_for_interface_no_connection(self, nmcli):
383+
nmcli.return_value = 'CONNECTION \n-- \n'
384+
out = utils.nm_get_connection_for_interface('asd0')
385+
self.assertEqual(out, '')

0 commit comments

Comments
 (0)