- Replace placeholder deps with click, pygnmi, and rich for CLI functionality - Add fabric-orch CLI entry point via project.scripts - Configure hatchling as build backend with wheel/sdist targets - Add ruff linter configuration for code quality - Add dev dependency group with ruff - Alphabetize yang module imports
184 lines
4.7 KiB
Markdown
184 lines
4.7 KiB
Markdown
# gNMI Client Module
|
|
|
|
This module provides a high-level gNMI client wrapper for interacting with Arista devices using pygnmi.
|
|
|
|
## Features
|
|
|
|
- Connection management with context manager support
|
|
- Get capabilities (list supported YANG models)
|
|
- Get configuration and state data at any YANG path
|
|
- Set configuration with dry-run support
|
|
- Subscribe to path updates (on-change, sample modes)
|
|
- Error handling with meaningful exceptions
|
|
|
|
## Installation
|
|
|
|
Ensure you have the required dependencies:
|
|
|
|
```bash
|
|
uv add pygnmi click rich
|
|
```
|
|
|
|
## Usage
|
|
|
|
### Basic Connection
|
|
|
|
```python
|
|
from gnmi import GNMIClient
|
|
|
|
# Using context manager (recommended)
|
|
with GNMIClient(
|
|
host="172.16.0.50",
|
|
port=6030,
|
|
username="admin",
|
|
password="admin",
|
|
insecure=True
|
|
) as client:
|
|
# Use the client
|
|
caps = client.capabilities()
|
|
print(caps)
|
|
```
|
|
|
|
### Get Capabilities
|
|
|
|
```python
|
|
with GNMIClient(host="172.16.0.50", port=6030) as client:
|
|
# Get raw capabilities
|
|
caps = client.capabilities()
|
|
print(f"gNMI Version: {caps['gnmi_version']}")
|
|
|
|
# Get parsed models
|
|
models = client.get_models()
|
|
for model in models:
|
|
print(f" {model.name} ({model.organization}) v{model.version}")
|
|
```
|
|
|
|
### Get Data
|
|
|
|
```python
|
|
with GNMIClient(host="172.16.0.50", port=6030) as client:
|
|
# Get all data (config + state)
|
|
result = client.get("/interfaces/interface[name=Ethernet1]")
|
|
|
|
# Get config only
|
|
result = client.get(
|
|
"/interfaces/interface[name=Ethernet1]",
|
|
data_type="config"
|
|
)
|
|
|
|
# Get state only
|
|
result = client.get(
|
|
"/interfaces/interface[name=Ethernet1]/state",
|
|
data_type="state"
|
|
)
|
|
|
|
# Get multiple paths
|
|
result = client.get([
|
|
"/interfaces/interface[name=Ethernet1]/state",
|
|
"/interfaces/interface[name=Ethernet2]/state",
|
|
])
|
|
```
|
|
|
|
### Set Configuration
|
|
|
|
```python
|
|
with GNMIClient(host="172.16.0.50", port=6030) as client:
|
|
# Dry-run (default) - shows what would be set
|
|
result = client.set(
|
|
path="/interfaces/interface[name=Ethernet1]/config/description",
|
|
value="Uplink to Spine",
|
|
dry_run=True
|
|
)
|
|
|
|
# Actually apply the change
|
|
result = client.set(
|
|
path="/interfaces/interface[name=Ethernet1]/config/description",
|
|
value="Uplink to Spine",
|
|
dry_run=False
|
|
)
|
|
|
|
# Replace operation
|
|
result = client.set(
|
|
path="/interfaces/interface[name=Ethernet1]/config",
|
|
value={"description": "New config", "enabled": True},
|
|
operation="replace",
|
|
dry_run=False
|
|
)
|
|
|
|
# Delete operation
|
|
result = client.set(
|
|
path="/interfaces/interface[name=Ethernet1]/config/description",
|
|
value=None,
|
|
operation="delete",
|
|
dry_run=False
|
|
)
|
|
```
|
|
|
|
### Subscribe to Updates
|
|
|
|
```python
|
|
with GNMIClient(host="172.16.0.50", port=6030) as client:
|
|
# Subscribe to interface state changes
|
|
subscription = client.subscribe(
|
|
paths="/interfaces/interface/state/oper-status",
|
|
mode="stream",
|
|
stream_mode="on-change"
|
|
)
|
|
|
|
# Process updates
|
|
for update in subscription:
|
|
print(update)
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
The module provides specific exceptions for different error types:
|
|
|
|
```python
|
|
from gnmi import GNMIClient, GNMIError, GNMIConnectionError, GNMIPathError
|
|
|
|
try:
|
|
with GNMIClient(host="172.16.0.50", port=6030) as client:
|
|
result = client.get("/invalid/path")
|
|
except GNMIConnectionError as e:
|
|
print(f"Connection failed: {e}")
|
|
except GNMIPathError as e:
|
|
print(f"Invalid path: {e}")
|
|
except GNMIError as e:
|
|
print(f"gNMI error: {e}")
|
|
```
|
|
|
|
## Environment Variables
|
|
|
|
The CLI supports these environment variables for defaults:
|
|
|
|
- `GNMI_TARGET` - Target device (host:port)
|
|
- `GNMI_USERNAME` - Username for authentication
|
|
- `GNMI_PASSWORD` - Password for authentication
|
|
|
|
## Path Format Notes
|
|
|
|
For Arista EOS, use native paths **without** module prefixes for subscriptions:
|
|
|
|
```python
|
|
# ✅ Correct - native path
|
|
"/interfaces/interface[name=Ethernet1]/state"
|
|
|
|
# ❌ Incorrect - with module prefix (may fail for subscriptions)
|
|
"/openconfig-interfaces:interfaces/interface[name=Ethernet1]/state"
|
|
```
|
|
|
|
## Validated Paths
|
|
|
|
These paths have been validated against Arista cEOS 4.35.0F:
|
|
|
|
| Category | Path | Notes |
|
|
|----------|------|-------|
|
|
| Interfaces | `/interfaces/interface[name=Ethernet1]/state` | Full state |
|
|
| BGP | `/network-instances/network-instance[name=default]/protocols/protocol[identifier=BGP][name=BGP]/bgp/neighbors/neighbor/state` | All neighbors |
|
|
| VXLAN | `/interfaces/interface[name=Vxlan1]/arista-vxlan/vlan-to-vnis` | VNI mappings |
|
|
| MLAG | `/arista/eos/mlag/config` | Config only |
|
|
| EVPN | `/arista/eos/evpn` | Config only |
|
|
|
|
See `docs/yang-paths.md` for complete path documentation.
|