driver / standard (pull_request) Successful in 56s
driver / lint (pull_request) Successful in 49s
driver / types (pull_request) Failing after 1m6s
driver / test (3.10) (pull_request) Failing after 5m48s
driver / test (3.11) (pull_request) Failing after 3m11s
driver / test (3.12) (pull_request) Successful in 2m48s
driver / test (3.13) (pull_request) Successful in 4m16s
driver / lowest (pull_request) Successful in 4m47s
driver / security (pull_request) Successful in 6m8s
driver / build (pull_request) Failing after 52s
CI / driver (pull_request) Failing after 30m42s
driver / publish (pull_request) Skipped
- CI moves to .gitea/workflows/ci.yml and calls the shared driver workflow of NAPALM/driver-standard; napalm-device-types comes from git until it is on PyPI. - requires-python >=3.10 (napalm-device-types needs it), LICENSE file, py.typed, SPDX license string, links to git.netork.io. - mypy strict for the package; napalm_linux.linux is exempt for now (21 errors), recorded in the quality baseline with its long functions and the 2200-line module. Coverage floor 58 % (measured 58.23 %).
193 lines
6.0 KiB
Markdown
193 lines
6.0 KiB
Markdown
# napalm-linux
|
|
|
|
NAPALM driver for **generic Linux systems** — Debian, Ubuntu, RHEL, Rocky, Alpine, Arch and any
|
|
other distribution reachable via SSH.
|
|
|
|
Connects over SSH using [Netmiko](https://github.com/ktbyers/netmiko) (`linux` device type) and
|
|
**automatically detects** the installed package manager (`apt`, `dnf`, `yum`, `apk`, `pacman`).
|
|
|
|
## Requirements
|
|
|
|
| Dependency | Minimum version |
|
|
|---|---|
|
|
| Python | 3.9 |
|
|
| NAPALM | 4.0 |
|
|
| Netmiko | 4.0 |
|
|
| napalm-device-types | 0.2.0 |
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
pip install napalm napalm-linux
|
|
```
|
|
|
|
Or from source:
|
|
|
|
```bash
|
|
git clone https://git.netork.io/NAPALM/napalm-linux
|
|
pip install -e napalm-linux/
|
|
```
|
|
|
|
When working in the NetOrk monorepo, install both packages as editable:
|
|
|
|
```bash
|
|
pip install -e vendor/napalm-device-types/ -e vendor/napalm-linux/
|
|
```
|
|
|
|
## Quick start
|
|
|
|
```python
|
|
from napalm import get_network_driver
|
|
|
|
Driver = get_network_driver("linux")
|
|
|
|
with Driver(
|
|
"10.0.0.5",
|
|
"admin",
|
|
"s3cr3t",
|
|
optional_args={
|
|
# "port": 22,
|
|
# "pkg_manager": "apt", # force package manager; auto-detected by default
|
|
# "sudo_password": "sudo-pass", # for commands that need root; without it,
|
|
# # `sudo -n` (passwordless sudo) is tried
|
|
# "debugging": True, # enable verbose logging
|
|
},
|
|
) as dev:
|
|
facts = dev.get_facts()
|
|
print(facts)
|
|
|
|
# OS-specific methods (from napalm-device-types OSDriver)
|
|
packages = dev.get_packages()
|
|
updates = dev.get_pending_updates()
|
|
services = dev.get_services()
|
|
users = dev.get_os_users()
|
|
procs = dev.get_processes()
|
|
jobs = dev.get_cron_jobs()
|
|
|
|
# Upgrade specific packages
|
|
result = dev.apply_updates(["openssh-server", "curl"])
|
|
print(result) # {"success": True, "output": "..."}
|
|
|
|
# Upgrade everything with pending updates
|
|
result = dev.apply_updates([])
|
|
|
|
# Restart a service (start, stop, restart, enable, disable)
|
|
result = dev.manage_service("cron", "restart")
|
|
print(result) # {"success": True, "output": ""}
|
|
```
|
|
|
|
## Supported NAPALM methods
|
|
|
|
### Standard NAPALM
|
|
|
|
| Method | Supported | Notes |
|
|
|---|---|---|
|
|
| `open()` / `close()` | ✅ | SSH via netmiko `linux` |
|
|
| `is_alive()` | ✅ | |
|
|
| `get_facts()` | ✅ | DMI / `/proc/uptime` / `ip link` |
|
|
| `get_interfaces()` | ✅ | `ip link show` |
|
|
| `get_interfaces_ip()` | ✅ | `ip addr show` |
|
|
| `get_arp_table()` | ✅ | `ip neigh show` |
|
|
| `get_config()` | ✅ | Returns `ip addr` + `ip route` output |
|
|
| `ping()` | ✅ | Executes `ping` on the remote host |
|
|
| `load_merge_candidate()` | ❌ | Not applicable for generic Linux |
|
|
| `load_replace_candidate()` | ❌ | Not applicable for generic Linux |
|
|
| `compare_config()` | ❌ | Not applicable for generic Linux |
|
|
| `commit_config()` | ❌ | Not applicable for generic Linux |
|
|
| `discard_config()` | ❌ | Not applicable for generic Linux |
|
|
| `rollback()` | ❌ | Not applicable for generic Linux |
|
|
|
|
### OSDriver extensions (napalm-device-types)
|
|
|
|
| Method | Supported | Package managers |
|
|
|---|---|---|
|
|
| `get_packages()` | ✅ | apt, dnf, yum, apk, pacman |
|
|
| `get_pending_updates()` | ✅ | apt, dnf, yum, apk, pacman |
|
|
| `apply_updates(packages)` | ✅ | apt, dnf, yum, apk, pacman |
|
|
| `get_services()` | ✅ | systemd, one round trip (fallback: SysV `service`) |
|
|
| `manage_service(name, action)` | ✅ | systemd: start, stop, restart, enable, disable |
|
|
| `get_os_users()` | ✅ | `/etc/passwd` + `/etc/group` |
|
|
| `get_processes()` | ✅ | `ps axo` |
|
|
| `get_cron_jobs()` | ✅ | user crontabs + `/etc/cron.d/` |
|
|
|
|
## Package manager auto-detection
|
|
|
|
The driver probes for each binary in order via `command -v`:
|
|
|
|
```
|
|
apt → dnf → yum → apk → pacman
|
|
```
|
|
|
|
Force a specific package manager:
|
|
|
|
```python
|
|
optional_args = {"pkg_manager": "dnf"}
|
|
```
|
|
|
|
## SSH user permissions
|
|
|
|
The SSH user needs read access to:
|
|
|
|
| Data | Required permission |
|
|
|---|---|
|
|
| `/etc/passwd`, `/etc/group` | world-readable (default) |
|
|
| `/proc/uptime`, `/sys/class/dmi/…` | world-readable (default) |
|
|
| User crontabs (`/var/spool/cron/…`) | `root` or `sudo` required |
|
|
| `systemctl list-unit-files`, `systemctl show` | unprivileged |
|
|
| `systemctl start/stop/restart/enable/disable` | `root`, or `sudo` (with `sudo_password`, or passwordless) |
|
|
| `apt list --upgradable` | may require `apt-get update` (root) |
|
|
| `dnf check-update` / `yum check-update` | unprivileged, but slower without cache |
|
|
|
|
For full functionality it is recommended to run as `root` or grant passwordless `sudo` for
|
|
the above commands.
|
|
|
|
With a `sudo_password`, privileged commands run on an exec channel next to the interactive
|
|
shell: the password reaches `sudo -S` on stdin, never a command line, so it shows neither in
|
|
the process list nor in a shell history. The interactive session switches its history off
|
|
before its first command.
|
|
|
|
`get_services()` and `manage_service()` come from napalm-device-types'
|
|
`SystemdServicesMixin`; this driver supplies only the transport. An action runs as
|
|
`timeout 45 systemctl --no-ask-password <action> -- <unit>.service`, so a unit that hangs
|
|
on its way up or down cannot hold the session, and only the exit status decides whether it
|
|
succeeded. Without a sudo password it uses `sudo -n`, which fails at once instead of
|
|
waiting for a password prompt.
|
|
|
|
On OpenMediaVault (napalm-openmediavault inherits this driver), enabling or disabling a
|
|
unit that OMV manages itself — Samba, NFS, SSH — may be reverted the next time OMV applies
|
|
its configuration.
|
|
|
|
## Tested distributions
|
|
|
|
| Distribution | Version | Package manager | Tested |
|
|
|---|---|---|---|
|
|
| Debian | 12 (Bookworm) | apt | ✅ |
|
|
| Ubuntu | 22.04 LTS | apt | ✅ |
|
|
| Rocky Linux | 9 | dnf | planned |
|
|
| Alpine Linux | 3.19 | apk | planned |
|
|
| Arch Linux | rolling | pacman | planned |
|
|
|
|
Contributions for additional distributions and versions are welcome.
|
|
|
|
## Development
|
|
|
|
```bash
|
|
# Create venv
|
|
python -m venv .venv
|
|
source .venv/bin/activate
|
|
|
|
# Install in editable mode with dev dependencies
|
|
pip install -e ../napalm-device-types/ -e ".[dev]"
|
|
|
|
# Run tests
|
|
pytest tests/ -v
|
|
|
|
# Lint / format
|
|
ruff check napalm_linux/
|
|
ruff format napalm_linux/
|
|
```
|
|
|
|
## License
|
|
|
|
Apache 2.0
|