Getting Started With NetBox Custom Scripts

One of many awesome features of NetBox is Custom Scripts. You may have already heard about them, and may think they sound complicated as they are written in Python, but fear not, you do not need to be a full on Pythonista to get started. 

Although custom scripting is considered an advanced feature, because the complete Python environment is available to the script, including all of NetBox’s internal mechanisms, writing your own custom scripts for NetBox is fairly straightforward. Make sure you test your scripts thoroughly on a non-production NetBox Instance before running in a production environment.

This blog post aims to show you how to get started, and to hopefully inspire you to develop some scripts of your own. We will step through writing a custom script that will create a new site in NetBox, along with the required routers, switches, Wireless APs and servers. This script is a great time saver, allowing you to set up a new site and all the required devices in a couple of seconds, all within the same screen of the UI! 

Subscribe to our community newsletter for more tutorials like these!

Running Custom Scripts

Once scripts have been uploaded to NetBox they are available to be executed from within the UI under Customization – Scripts, and also via the REST API. Below is a preview of the New Branch Script in the UI. You can see the formatting is all taken care of, along with required inputs, including drop-down menus to allow you to select existing data from the NetBox database, for example a Switch Model: 

A screenshot showing how to create a new branch custom script in NetBox

Writing Custom Scripts

So, let’s break down our example script. First of all we have some import statements: 

from extras.scripts import *
from django.utils.text import slugify
from dcim.choices import DeviceStatusChoices, SiteStatusChoices
from dcim.models import Device, DeviceRole, DeviceType, Site

All custom scripts must inherit from the extras.scripts.Script base class. This class provides the functionality necessary to generate forms and log activity. We also want to make use of slugs (short names) for the objects so we import slugify from django.utils. Next, as this script is working with objects within the DCIM data model in Netbox, we import some classes from here too – from dcim.models we import Device, DeviceRole, DeviceType and Site, and from dcim.choices we import DeviceStatusChoices and SiteStatusChoices

The main point here is that the complete NetBox Python environment is available to a custom script, including all of NetBox’s internal mechanisms. So if you are developing your own custom scripts then at some point you may need to refer to the NetBox source code.

Ok, back to the script itself – after the imports you have the script Python class that inherits the Script base class. There is also some class meta data – in this case the name and a description of what the script does.

class NewBranchScript(Script):
    class Meta:
        name = "New Branch"
        description = "Provision a new branch site"

The next section is a set of variables that the script will use, and these map to the user inputs for the script in the web UI. For example the first input is the site_name for the new site. The next variable is switch_count which is simply the number of switches to be deployed at the new site. Then switch_model allows the user to select the device model from a drop down menu, by accessing the Device Type model.

This pattern then simply repeats for Routers, Wireless Access Points and servers:

 site_name = StringVar(
        description="Name of the new site"
    )
    switch_count = IntegerVar(
        description="Number of access switches to create"
    )
    switch_model = ObjectVar(
        description="Access switch model",
        model=DeviceType
    )
    router_count = IntegerVar(
        description="Number of routers to create"
    )
    router_model = ObjectVar(
        description="Router model",
        model=DeviceType
    )
    ap_count = IntegerVar(
        description="Number of APs to create"
    )
    ap_model = ObjectVar(
        description="AP model",
        model=DeviceType
    )
    server_count = IntegerVar(
        description="Number of servers to create"
    )
    server_model = ObjectVar(
        description="Server model",
        model=DeviceType
    )

Now, the other component that a custom script needs to have is a run method – and this is where your script’s execution logic lives. The run method accepts two arguments – `data` which is a dictionary containing all the variable data passed via the web form, and commit which is a Boolean (either true or false) indicating whether database changes will be committed or not.

def run(self, data, commit):

The next section within the run method creates the new site, using the value of the site_name<c/ode> variable. It also creates the slug for the site name and sets the status of the new site to planned. Then the new site object is saved, and a log message written on a successful update.

        # Create the new site
        site = Site(
            name=data['site_name'],
            slug=slugify(data['site_name']),
            status=SiteStatusChoices.STATUS_PLANNED
        )
        site.save()
        self.log_success(f"Created new site: {site}")

Next up to be created are the switches. The role of the switch is defined as Access Switch which is one of the device roles that already exists in our example NetBox database, and then for each switch it creates a new device with the device type being the switch model, the name consisting of the slug of the site in upper case, followed by -SW then another dash and then lastly the number of the switch.

The site value is the site that has just been created. The `status uses the DeviceStatusChoices method and sets it to planned, and the role is also set based on the value of the switch_role variable. Then the new object is saved, and a success log message is generated.


        # Create access switches
        switch_role = DeviceRole.objects.get(name='Access Switch')
        for i in range(1, data['switch_count'] + 1):
            switch = Device(
                device_type=data['switch_model'],
                name=f'{site.slug.upper()}-SW-{i}',
                site=site,
                status=DeviceStatusChoices.STATUS_PLANNED,
                device_role=switch_role
            )
            switch.save()
            self.log_success(f"Created new switch: {switch}")

This code block is essentially then repeated to add the required Routers, APs, and Servers:


        # Create routers
        router_role = DeviceRole.objects.get(name='WAN Router')
        for i in range(1, data['router_count'] + 1):
            router = Device(
                device_type=data['router_model'],
                name=f'{site.slug.upper()}-RTR-{i}',
                site=site,
                status=DeviceStatusChoices.STATUS_PLANNED,
                device_role=router_role
            )
            router.save()
            self.log_success(f"Created new router: {router}")
        # Create APs
        ap_role = DeviceRole.objects.get(name='Wireless AP')
        for i in range(1, data['ap_count'] + 1):
            ap = Device(
                device_type=data['ap_model'],
                name=f'{site.slug.upper()}-AP-{i}',
                site=site,
                status=DeviceStatusChoices.STATUS_PLANNED,
                device_role=ap_role
            )
            ap.save()
            self.log_success(f"Created new AP: {router}")
        # Create Servers
        server_role = DeviceRole.objects.get(name='vSphere')
        for i in range(1, data['server_count'] + 1):
            server = Device(
                device_type=data['server_model'],
                name=f'{site.slug.upper()}-VSP-{i}',
                site=site,
                status=DeviceStatusChoices.STATUS_PLANNED,
                device_role=server_role
            )
            server.save()
            self.log_success(f"Created new server: {router}"

The last section simply generates a CSV table of the new devices which is then displayed in the output.


        # Generate a CSV table of new devices
        output = [
            'name,make,model'
        ]
        for device in Device.objects.filter(site=site):
            attrs = [
                device.name,
                device.device_type.manufacturer.name,
                device.device_type.model
            ]
            output.append(','.join(attrs))
        return 'n'.join(output)

Adding Custom Scripts to NetBox

Now we have our script written we can upload it to NetBox, via the UI. Navigate to Customization – Scripts and from here you can click the link to add a new script. You can either upload the file from your local machine, or from a remote data source like a Git repo or S3 bucket. Note – remote data sources were added in NetBox v3.5.0 and you can read about them here.

We’ll add our script from a remote data source (Git repo):

After we click Create, we can now see the script has been loaded and is available to be run: 

To run the script, simply click on the script name. This will launch the script, prompting for user input for the values that will define the new branch site. In this example, the new site is in Stockholm, Sweden, so the site name will be SWSTO01. It will have two switches, that are the Juniper EX4300-48P model, two ISR4321 WAN routers, four MR56 APs, and two Proliant DL380 servers.

NetBox script for custom report screenshot

Next, click on Run Script and you can now see the success log messages, and in the output you have the CSV formatted list of the site and devices that have been created:

Then if you click through to Organization – Sites, then click the name of the new site, you can see that it has been created with a status of Planned, and with ten devices under Related Objects

Scroll further down, and you will see each newly created device also, ready to be assigned to a rack. How Easy was that?

Wrap Up

So, I hope that this has been a useful overview of what Custom Scripts are in NetBox and what kind of tasks they can be used to accomplish. You’ve learned the basics of writing Custom Scripts and where to find documentation to help you develop your own scripts. 

You can find the example script used in this article in the Git Repository that accompanies the NetBox Zero to Hero course, along with another example script to help get you started.

You can also view a short video explaining how to work with Scripts stored in a remote data source (git repository) synchronised with NetBox, and there are more example scripts here for you to take inspiration from.

If you are interested in receiving tutorials like this in your inbox, subscribe to our community newsletter.

Happy NetBox scripting!

Share the Post:

Related Posts