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
50 changes: 45 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ except Exception as e:
| general | hostname | supported |
| general | permissions | not supported |
| general | logging | not supported |
| general | reload | supported |
| networking | | supported |
| networking | on | supported |
| networking | off | supported |
Expand All @@ -61,6 +62,7 @@ except Exception as e:
| connection | clone | not supported |
| connection | edit | not supported |
| connection | delete | supported |
| connection | monitor | not supported |
| connection | reload | supported |
| connection | load | not supported |
| connection | import | not supported |
Expand All @@ -69,17 +71,20 @@ except Exception as e:
| device | status | supported |
| device | show | supported |
| device | set | not supported |
| device | up | supported |
| device | connect | supported |
| device | reapply | supported |
| device | modify | not supported |
| device | down | supported |
| device | disconnect | supported |
| device | delete | supported |
| device | monitor | not supported |
| device | wifi | supported |
| device | wifi connect | supported |
| device | wifi rescan | supported |
| device | wifi hotspot | supported |
| device | lldp | not supported |
| device | wifi | supported |
| device | wifi connect | supported |
| device | wifi rescan | supported |
| device | wifi hotspot | supported |
| device | wifi show-password | not supported |
| device | lldp | not supported |
| agent | | not supported |
| agent | secret | not supported |
| agent | polkit | not supported |
Expand Down Expand Up @@ -216,6 +221,16 @@ The `fields` argument applies the same effect to the command as the `-f | --fiel
nmcli.device.show_all(fields: str = None) -> List[DeviceDetails]
```

#### nmcli.device.up

Connect the device.

The `wait` argument applies the same effect to the command as the `--wait` option. If it is omitted, the default behavior is followed.

```
nmcli.device.up(ifname: str, wait: int = None) -> None
```

#### nmcli.device.connect

Connect the device.
Expand All @@ -226,6 +241,16 @@ The `wait` argument applies the same effect to the command as the `--wait` optio
nmcli.device.connect(ifname: str, wait: int = None) -> None
```

#### nmcli.device.down

Disconnect a device and prevent the device from automatically activating further connections without user/manual intervention.

The `wait` argument applies the same effect to the command as the `--wait` option. If it is omitted, the default behavior is followed.

```
nmcli.device.down(ifname: str, wait: int = None) -> None
```

#### nmcli.device.disconnect

Disconnect devices.
Expand Down Expand Up @@ -330,6 +355,21 @@ Change persistent system hostname.
nmcli.general.set_hostname(hostname: str) -> None
```

#### nmcli.general.reload

Reload NetworkManager's configuration and perform certain updates.

The `flags` argument specifies which configurations to reload. Valid flags are:
- `conf`: Reload NetworkManager.conf configuration from disk
- `dns-rc`: Update DNS configuration (equivalent to SIGUSR1)
- `dns-full`: Restart the DNS plugin

If no flags are provided, everything that is supported is reloaded.

```
nmcli.general.reload(flags: Optional[List[str]] = None) -> None
```

### networking

#### nmcli.networking
Expand Down
16 changes: 16 additions & 0 deletions nmcli/_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,15 @@ def show(self, ifname: str, fields: str = None) -> DeviceDetails:
def show_all(self, fields: str = None) -> List[DeviceDetails]:
raise NotImplementedError

def up(self, ifname: str, wait: int = None) -> None:
raise NotImplementedError

def connect(self, ifname: str, wait: int = None) -> None:
raise NotImplementedError

def down(self, ifname: str, wait: int = None) -> None:
raise NotImplementedError

def disconnect(self, ifname: str, wait: int = None) -> None:
raise NotImplementedError

Expand Down Expand Up @@ -131,11 +137,21 @@ def show_all(self, fields: str = None) -> List[DeviceDetails]:
details[key] = None if value in ('--', '""') else value
return results

def up(self, ifname: str, wait: int = None) -> None:
cmd = add_wait_option_if_needed(
wait) + ['device', 'up', ifname]
self._syscmd.nmcli(cmd)

def connect(self, ifname: str, wait: int = None) -> None:
cmd = add_wait_option_if_needed(
wait) + ['device', 'connect', ifname]
self._syscmd.nmcli(cmd)

def down(self, ifname: str, wait: int = None) -> None:
cmd = add_wait_option_if_needed(
wait) + ['device', 'down', ifname]
self._syscmd.nmcli(cmd)

def disconnect(self, ifname: str, wait: int = None) -> None:
cmd = add_wait_option_if_needed(
wait) + ['device', 'disconnect', ifname]
Expand Down
20 changes: 20 additions & 0 deletions nmcli/_general.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import List, Optional

from ._system import SystemCommand, SystemCommandInterface
from .data import General

Expand All @@ -16,9 +18,14 @@ def get_hostname(self) -> str:
def set_hostname(self, hostname: str):
raise NotImplementedError

def reload(self, flags: Optional[List[str]] = None) -> None:
raise NotImplementedError


class GeneralControl(GeneralControlInterface):

VALID_RELOAD_FLAGS = ['conf', 'dns-rc', 'dns-full']

def __init__(self, syscmd: SystemCommandInterface = None):
self._syscmd = syscmd or SystemCommand()

Expand All @@ -35,3 +42,16 @@ def get_hostname(self) -> str:

def set_hostname(self, hostname: str):
self._syscmd.nmcli(['general', 'hostname', hostname])

def reload(self, flags: Optional[List[str]] = None) -> None:
if flags is not None:
for flag in flags:
if flag not in self.VALID_RELOAD_FLAGS:
raise ValueError(
f"Invalid reload flag '{flag}'. "
f"Valid flags are: {', '.join(self.VALID_RELOAD_FLAGS)}"
)
cmd = ['general', 'reload']
if flags:
cmd += flags
self._syscmd.nmcli(cmd)
20 changes: 19 additions & 1 deletion nmcli/dummy/_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,24 @@
from ..data.hotspot import Hotspot


class DummyDeviceControl(DeviceControlInterface):
class DummyDeviceControl(DeviceControlInterface): # pylint: disable=too-many-public-methods

@property
def show_args(self):
return self._show_args

@property
def up_args(self):
return self._up_args

@property
def connect_args(self):
return self._connect_args

@property
def down_args(self):
return self._down_args

@property
def disconnect_args(self):
return self._disconnect_args
Expand Down Expand Up @@ -57,7 +65,9 @@ def __init__(self,
self._result_show_all = result_show_all or []
self._result_wifi_hotspot = result_wifi_hotspot
self._show_args: List[Tuple] = []
self._up_args: List[Tuple] = []
self._connect_args: List[Tuple] = []
self._down_args: List[Tuple] = []
self._disconnect_args: List[Tuple] = []
self._reapply_args: List[str] = []
self._delete_args: List[Tuple] = []
Expand Down Expand Up @@ -85,10 +95,18 @@ def show_all(self, fields: str = None) -> List[DeviceDetails]:
self._raise_error_if_needed()
return self._result_show_all

def up(self, ifname: str, wait: int = None) -> None:
self._raise_error_if_needed()
self._up_args.append((ifname, wait))

def connect(self, ifname: str, wait: int = None) -> None:
self._raise_error_if_needed()
self._connect_args.append((ifname, wait))

def down(self, ifname: str, wait: int = None) -> None:
self._raise_error_if_needed()
self._down_args.append((ifname, wait))

def disconnect(self, ifname: str, wait: int = None) -> None:
self._raise_error_if_needed()
self._disconnect_args.append((ifname, wait))
Expand Down
11 changes: 10 additions & 1 deletion nmcli/dummy/_general.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import List
from typing import List, Optional

from .._general import GeneralControlInterface
from ..data.general import General
Expand All @@ -10,6 +10,10 @@ class DummyGeneralControl(GeneralControlInterface):
def set_hostname_args(self):
return self._set_hostname_args

@property
def reload_args(self):
return self._reload_args

def __init__(self,
result_call: General = None,
result_status: General = None,
Expand All @@ -20,6 +24,7 @@ def __init__(self,
self._result_status = result_status
self._result_hostname = result_hostname
self._set_hostname_args: List[str] = []
self._reload_args: List[Optional[List[str]]] = []

def __call__(self) -> General:
self._raise_error_if_needed()
Expand All @@ -41,6 +46,10 @@ def set_hostname(self, hostname: str):
self._raise_error_if_needed()
self._set_hostname_args.append(hostname)

def reload(self, flags: Optional[List[str]] = None) -> None:
self._raise_error_if_needed()
self._reload_args.append(flags)

def _raise_error_if_needed(self):
if not self._raise_error is None:
raise self._raise_error
23 changes: 23 additions & 0 deletions tests/test_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,17 @@ def test_show_all():
assert s2.passed_parameters == ['-f', 'all', 'device', 'show']


def test_up():
s = DummySystemCommand()
device = DeviceControl(s)
ifname = 'eth0'
device.up(ifname)
assert s.passed_parameters == ['device', 'up', ifname]

device.up(ifname, wait=10)
assert s.passed_parameters == ['--wait', '10', 'device', 'up', ifname]


def test_connect():
s = DummySystemCommand()
device = DeviceControl(s)
Expand All @@ -182,6 +193,18 @@ def test_connect():
assert s.passed_parameters == ['--wait', '10', 'device', 'connect', ifname]


def test_down():
s = DummySystemCommand()
device = DeviceControl(s)
ifname = 'eth0'
device.down(ifname)
assert s.passed_parameters == ['device', 'down', ifname]

device.down(ifname, wait=10)
assert s.passed_parameters == [
'--wait', '10', 'device', 'down', ifname]


def test_disconnect():
s = DummySystemCommand()
device = DeviceControl(s)
Expand Down
40 changes: 40 additions & 0 deletions tests/test_general.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import pytest

from nmcli._const import NetworkConnectivity, NetworkManagerState
from nmcli._general import GeneralControl
from nmcli.data import General
Expand Down Expand Up @@ -37,3 +39,41 @@ def test_set_hostname():
general = GeneralControl(s)
general.set_hostname('test')
assert s.passed_parameters == ['general', 'hostname', 'test']


def test_reload_without_flags():
s = DummySystemCommand()
general = GeneralControl(s)
general.reload()
assert s.passed_parameters == ['general', 'reload']


def test_reload_with_single_flag():
s = DummySystemCommand()
general = GeneralControl(s)
general.reload(['conf'])
assert s.passed_parameters == ['general', 'reload', 'conf']


def test_reload_with_all_valid_flags():
s = DummySystemCommand()
general = GeneralControl(s)
general.reload(['conf', 'dns-rc', 'dns-full'])
assert s.passed_parameters == ['general', 'reload', 'conf', 'dns-rc', 'dns-full']


def test_reload_with_invalid_flag():
s = DummySystemCommand()
general = GeneralControl(s)
with pytest.raises(ValueError) as exc_info:
general.reload(['invalid-flag'])
assert "Invalid reload flag 'invalid-flag'" in str(exc_info.value)
assert "Valid flags are: conf, dns-rc, dns-full" in str(exc_info.value)


def test_reload_with_mixed_valid_and_invalid_flags():
s = DummySystemCommand()
general = GeneralControl(s)
with pytest.raises(ValueError) as exc_info:
general.reload(['conf', 'invalid'])
assert "Invalid reload flag 'invalid'" in str(exc_info.value)