Metadata-Version: 2.4
Name: napalm-linux
Version: 0.16.0
Summary: NAPALM driver for generic Linux systems via SSH
Author-email: Christian Manivong <christian@manivong.de>
License-Expression: Apache-2.0
Project-URL: Repository, https://git.netork.io/NAPALM/napalm-linux
Project-URL: Issues, https://git.netork.io/NAPALM/napalm-linux/issues
Project-URL: Changelog, https://git.netork.io/NAPALM/napalm-linux/src/branch/main/CHANGELOG.md
Keywords: napalm,network,automation,linux,ssh,driver
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: System :: Networking
Classifier: Topic :: System :: Systems Administration
Classifier: Typing :: Typed
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: napalm>=4.0
Requires-Dist: napalm-device-types>=4.27.0
Requires-Dist: netmiko>=4.0.0
Requires-Dist: paramiko>=5.0.0
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: pytest-cov>=5; extra == "dev"
Requires-Dist: ruff>=0.6; extra == "dev"
Requires-Dist: mypy>=1.11; extra == "dev"
Dynamic: license-file

# 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_scheduled_jobs()["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_scheduled_jobs()` | ✅ | `/etc/crontab`, `/etc/cron.d`, user crontabs, run-parts, anacron, systemd timers (napalm-device-types' `PosixScheduledJobsMixin`) |
| `manage_scheduled_job(key, action, digest=)` | ✅ | enable, disable, run now |
| `put_scheduled_job(spec)` / `delete_scheduled_job(key, digest=)` | ✅ | an application's own job: a systemd timer, else `/etc/cron.d`, else the user's crontab |

## 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 --cacheonly check-update` / `yum --cacheonly check-update` | `root` or `sudo`; reads the cache that `dnf makecache` (root) fills |

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.

Versions before that typed `echo '<password>' | sudo -S -p "" <command>` into the interactive
shell, so the login user's history kept the password once per command.
`get_history_sudo_lines()` counts those lines per history file without reading them, and
`remove_history_sudo_lines()` deletes exactly them and gives `/etc/snmp/snmpd.conf` and
`/etc/apt/apt.conf.d/00proxy` back to root where they were left to the login user
(napalm-device-types' `SudoHistoryMixin`). Rotate the sudo password afterwards: backups,
snapshots and audit logs may still hold it.

`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
