Files
fabric-orchestrator/src/gnmi/README.md
darnodo e041dab724 feat(build): configure project tooling and update dependencies
- 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
2025-12-31 09:36:00 +01:00

4.7 KiB

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:

uv add pygnmi click rich

Usage

Basic Connection

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

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

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

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

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:

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:

# ✅ 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.