pynetbox Documentation

repository·main·Indexed 20 days ago

https://github.com/netbox-community/pynetbox

A Python API client library for NetBox that provides a programmatic way to interact with NetBox data and configuration. It features a layered architecture (Api, App, Endpoint) for navigating the API, support for multithreaded queries, cursor-based pagination for NetBox 4.6+, and strict filter validation against the OpenAPI specification. The library supports CRUD operations, file and image uploads, and specialized extensions for the NetBox Branching Plugin.

Tokens
20.4K
Snippets
80
Records
91
Agent score
64%

What's inside pynetbox

  1. Caveats and limitations of extensions

    main

    When using the extension framework, keep the following constraints in mind:

    • Plugin Scope Only: Extensions can only target endpoints under nb.plugins.*. They cannot override built-in NetBox applications like dcim or ipam.
    • No Auto-discovery: Extensions are not automatically detected. You must explicitly pass them to the pynetbox.api(extensions=[...]) call.
    • One Extension per Plugin: Only one extension can be registered per plugin_name per API instance. If multiple extensions use the same plugin_name, the last one provided in the list will overwrite previous ones.
  2. Use the Record class to access single NetBox objects

    main

    The Record class represents a single object returned by the NetBox API. API fields are exposed directly as attributes on the object. If the API response contains nested objects, pynetbox recursively wraps them in their own Record instances.

    Lazy Loading Behavior: When you retrieve a record from a list endpoint (e.g., via .filter() or .all()), the initial Record is "shallow". If you attempt to access an attribute that was not included in the list response, pynetbox will automatically perform an additional API call to fetch the full detail view for that specific object to populate the missing data.

    # Example of attribute access on a Record
    # If 'device' was returned from a list endpoint, accessing a field 
    # not in the list view will trigger a lazy fetch of the full detail.
    device_name = device.name
  3. Perform CRUD operations using Endpoints

    main

    In pynetbox, Endpoint objects are automatically created when you access an attribute on an App instance. These objects provide the interface for performing CRUD (Create, Read, Update, Delete) operations against NetBox API endpoints.

    Common methods available on an Endpoint include:

    • .all(): Retrieve all records at the endpoint.
    • .get(id): Retrieve a single record by its ID.
    • .filter(**kwargs): Retrieve records matching specific criteria.
    • .create(**kwargs): Create a new record.
    • .update(id, **kwargs): Update an existing record.
    • .delete(id): Delete an existing record.
    import pynetbox
    
    b = pynetbox.api('http://localhost:8000', token='your-token')
    
    # Accessing an attribute on an App returns an Endpoint
    devices = b.dcim.devices
    
    # Perform CRUD operations
    all_devices = devices.all()
    device = devices.get(1)
    filtered = devices.filter(site='headquarters')
    new_device = devices.create(name='test', site=1, device_type=1, role=1)
  4. Use the RecordSet class to iterate over collections

    main

    A RecordSet is a lazy, one-shot iterator over Record objects, typically returned by Endpoint.all() or Endpoint.filter(). It handles pagination automatically, fetching subsequent pages from NetBox as you iterate through the set.

    Important: Materializing for multiple passes Because RecordSet is a one-shot iterator, you cannot iterate over it more than once. If you need to access the same collection multiple times, you must materialize it into a standard Python list using the list() function.

    # Iterating through a RecordSet (one-shot)
    for record in nb.dcim.devices.all():
        print(record.name)
    
    # Materializing a RecordSet to allow multiple iterations
    devices = list(nb.dcim.devices.filter(role='spine'))
    print(len(devices))
    for device in devices:
        print(device.name)
  5. Use cursor-based pagination

    main

    For NetBox 4.6+, you can use cursor-based pagination via the pagination="cursor" argument. This is significantly more performant for very large result sets as it avoids the cost of scanning offsets.

    Behavior and Trade-offs:

    • Automatic Fallback: If the NetBox server is older than 4.6, pynetbox transparently falls back to offset-based pagination.
    • No Total Count: NetBox omits the count in cursor mode. Calling len(record_set) will trigger a separate, additional count request.
    • Fixed Ordering: Results are always ordered by id. You cannot combine cursor pagination with an explicit ordering filter.
    • Sequential Only: Cursor pagination is inherently sequential and cannot be combined with threading. If pagination="cursor" is set, queries will be sequential even if threading=True is passed.
    import pynetbox
    
    nb = pynetbox.api(
        'http://localhost:8000',
        token='your-token',
        pagination="cursor",
    )
    
    # .all() and .filter() now page using the server's `start` cursor
    devices = nb.dcim.devices.all()
  6. Use ROMultiFormatDetailEndpoint for multi-format resources

    main
    The ROMultiFormatDetailEndpoint is a read-only detail endpoint designed for resources that can return multiple response formats, such as structured JSON or raw content like SVG (e.g., rack elevations). It provides a .list() method to retrieve the resource.
  7. Use DetailEndpoint for sub-resources

    main

    A DetailEndpoint represents a detail route on an existing record (for example, /api/ipam/prefixes/{id}/available-ips/).

    Users do not construct DetailEndpoint objects directly; instead, they are returned by model-specific properties. For example, accessing Prefixes.available_ips returns a DetailEndpoint object which supports .list() and .create() methods.

  8. Validate filters with strict_filters

    main

    By default, NetBox does not validate filters passed to GET endpoints; if a filter is invalid, NetBox silently returns the entire table. Pynetbox can prevent this by validating parameters against the NetBox OpenAPI specification.

    • Global Enablement: Set strict_filters=True during API initialization.
    • Per-request Override: Use the strict_filters keyword argument in .filter() or .get() calls to enable or disable validation for that specific request.
    # Enable globally
    nb = pynetbox.api('http://localhost:8000', strict_filters=True)
    
    # Disable for a specific request (will return entire table if filter is wrong)
    nb.dcim.devices.filter(non_existing_filter="aaaa", strict_filters=False)
    
    # Enable for a specific request (will raise an exception if filter is wrong)
    nb.dcim.devices.filter(non_existing_filter="aaaa", strict_filters=True)
  9. Understand the pynetbox API structure and namespaces

    main

    The pynetbox object structure mirrors the NetBox application structure. Each NetBox app is an attribute of the API object. Dashes in NetBox endpoint names are converted to underscores in Python.

    Core Namespaces:

    • nb.circuits: Circuit management
    • nb.core: Core objects (data sources, jobs, object changes)
    • nb.dcim: Data Center Infrastructure Management
    • nb.extras: Tags, custom fields, webhooks, etc.
    • nb.ipam: IP Address Management
    • nb.tenancy: Tenants and contacts
    • nb.users: Users and permissions
    • nb.virtualization: Virtual machines and clusters
    • nb.vpn: VPN tunnels and terminations
    • nb.wireless: Wireless LANs and links

    Plugin Endpoints: Endpoints provided by NetBox plugins are accessed via the plugins namespace. For example, a plugin named my-plugin with an endpoint /api/plugins/my-plugin/objects/ is accessed as nb.plugins.my_plugin.objects.

  10. How pynetbox's layered architecture works

    main

    pynetbox uses a hierarchical, layered architecture where each layer wraps the one below it to provide a structured way to navigate the NetBox API:

    1. Api: The main entry point. It manages the HTTP session, authentication token, and global configuration.
    2. App: Represents a NetBox application (e.g., dcim, ipam). Accessing an attribute on an Api instance returns an App.
    3. Endpoint: Represents an individual NetBox API endpoint. Accessing an attribute on an App returns an Endpoint.

    This allows you to navigate the API using standard Python attribute access (e.g., nb.dcim.devices).

    import pynetbox
    
    # Create an API connection (Api)
    nb = pynetbox.api('http://localhost:8000', token='your-token')
    
    # Access an app (App)
    nb.dcim
    
    # Access an endpoint (Endpoint)
    nb.dcim.devices
    
    # Call an endpoint method (returns Record / RecordSet)
    devices = nb.dcim.devices.all()
  11. Customize HTTP behavior with custom sessions

    main

    You can replace the default requests.Session by assigning a new session object to nb.http_session. This allows you to customize headers, SSL verification, and timeouts.

    Common Tasks:

    • Custom Headers: Assign a requests.Session with pre-configured headers.
    • Disable SSL: Set session.verify = False on your custom session.
    • Timeouts: To set a default timeout for all requests, you must mount a custom requests.adapters.HTTPAdapter to the session.
    import pynetbox
    import requests
    from requests.adapters import HTTPAdapter
    
    # Example: Custom Headers
    session = requests.Session()
    session.headers = {'mycustomheader': 'test'}
    nb = pynetbox.api('http://localhost:8000', token='your-token')
    nb.http_session = session
    
    # Example: Custom Timeouts via Adapter
    class TimeoutHTTPAdapter(HTTPAdapter):
        def __init__(self, *args, **kwargs):
            self.timeout = kwargs.pop('timeout', 5)
            super().__init__(*args, **kwargs)
    
        def send(self, request, **kwargs):
            kwargs['timeout'] = self.timeout
            return super().send(request, **kwargs)
    
    adapter = TimeoutHTTPAdapter(timeout=10)
    session = requests.Session()
    session.mount('http://', adapter)
    session.mount('https://', adapter)
    
    nb = pynetbox.api('http://localhost:8000', token='your-token')
    nb.http_session = session