Skip to content

Introduction

Custom Scripts are small Python programs executed directly in the NetBox UI.
They standardize repetitive tasks and reduce manual clicks.

Why this is useful

  • Consistent structure: Devices, interfaces, and VMs follow the same schema.
  • All in one step: For VMs you can create an interface and assign an IP in one run.
  • Lightweight automation: Implement workflows without building a plugin.
  • Quality assurance: Enforce required fields, validations, and naming rules.

This page starts with a tiny “Hello” script to show the mechanics, then a practical script that reserves the next free IPv4 address.


Before you start

  • Scripts can be uploaded directly via the NetBox GUI under Extras → Scripts.
  • Alternatively, you can place them under the NetBox scripts path (e.g. netbox/scripts/).
  • When running, you can toggle Commit off for a dry run, or on to persist changes.

Minimal script: inputs, logging, dry-run

00_hello_script.py
from extras.scripts import Script, StringVar  # (1)!

class Hello(Script):
    class Meta:
        name = "Hello"
        description = "Demonstrates inputs, logging, and commit switch"

    name = StringVar(required=False, label="Name")  # (2)!

    def run(self, data, commit):  # (3)!
        name = (data.get("name") or "world").strip()
        self.log_info(f"Hello, {name}!")  # (4)!
        return f"Greeting sent (commit={commit})"  # (5)!
  1. Import the NetBox Script API.
  2. Define an optional input field shown in the UI.
  3. run() is the entrypoint. NetBox passes form data and the Commit flag.
  4. log_info outputs a message in the script results panel.
  5. Return a summary string at the end.

Example Script: Reserve IPv4 with optional DNS

What it does

  • Scans a chosen prefix for the first unused IPv4.
  • Creates an IPAddress in NetBox (only when Commit is enabled).
  • Optionally sets a DNS name from the provided DNS name input.

Inputs

  • IPv4 Prefix (required)
  • DNS name (optional)
01_reserve_ipv4.py
from extras.scripts import Script, ObjectVar, StringVar
from ipam.models import Prefix, IPAddress

class ReserveIPv4(Script):
    class Meta:  # (1)!
        name = "Reserve IPv4"
        description = "Find the first free IPv4 in the selected prefix and create an IPAddress"

    prefix = ObjectVar(  # (2)!
        model=Prefix,
        required=True,
        label="IPv4 Prefix",
        description="Select the prefix to reserve the next free address from.",
    )
    dns_name = StringVar(  # (3)!
        required=False,
        label="DNS name (optional)",
        description="Stored as DNS name, e.g., 'web01'."
    )

    def _pick_free_ip(self, prefix):  # (4)!
        for host in prefix.prefix.iter_hosts():
            ip_str = str(host)
            if IPAddress.objects.filter(address__startswith=f"{ip_str}/").exists():
                self.log_info(f"{ip_str} -> in use (NetBox)")
                continue
            self.log_success(f"{ip_str} -> free, will be used")
            return ip_str
        return None

    def run(self, data, commit):  # (5)!
        prefix = data["prefix"]
        dns_name = (data.get("dns_name") or "").strip()

        if prefix.prefix.version != 4:  # (6)!
            self.log_failure(f"{prefix.prefix} is not an IPv4 prefix.")
            return "Aborted."

        ip_plain = self._pick_free_ip(prefix)  # (7)!
        if not ip_plain:
            self.log_failure(f"No free IP found in {prefix.prefix}.")
            return "Aborted."

        ip_with_mask = f"{ip_plain}/{prefix.prefix.prefixlen}"

        ip_obj = IPAddress(address=ip_with_mask, dns_name=dns_name or "")  # (8)!
        if commit:
            ip_obj.save()
            self.log_success(f"IPAddress created: {ip_obj.address} (dns_name='{ip_obj.dns_name}')")
        else:
            self.log_info(f"[Dry-Run] would create: {ip_with_mask} (dns_name='{dns_name}')")

        return f"Prefix: {prefix.prefix}, IP: {ip_with_mask}, Commit={commit}"
  1. Script metadata displayed in the NetBox UI.
  2. Input field for selecting the prefix.
  3. Optional input field for a hostname → stored as DNS name.
  4. Helper method scans the prefix for the first unused IPv4.
  5. Main function: reads inputs, validates, and drives the process.
  6. Validation step: ensure only IPv4 prefixes are used.
  7. Calls the helper to get the next free IP, otherwise aborts.
  8. Creates and saves the IPAddress when Commit is on, or logs what would happen.