Step by step guide developing a netbox plugin
A Step-by-Step Guide to Developing a Netbox Plugin#
You are on this page so you know why you are using netbox and why you want to develop a plugin. I will dispense with the excess and jump right in to the steps.
For a real world scenario - I want to create a system plugin to store various systems in the company and link it to a number of vms that make up the system.
TTL255 has a decent tutorial but uses non-standard library tools
poetryandinvoke- so I didn’t want to have to learn yet another tool.
Steps#
Ensure you have a locally running netbox instance - to test on. You will need a local redis and postgres, then you can clone the repo, create a virtual environment, install
requirements.txtcopy theconfiguration.pyfile and complete it and then migrate and run the project with./manage.py runserver
-
Create project folder, plugin folder
mkdir netbox_systems_plugin cd netbox_systems_plugin mkdir netbox_systems
don’t enter the
netbox_systems/dir yet… -
Create the
setup.pyvim setup.pywrite:
from setuptools import find_packages, setup setup( name='netbox_systems', version='0.1', description='A systems plugin for netbox', author='Surfer190', license='Apache 2.0', install_requires=[], packages=find_packages(exclude=["tests"]), include_package_data=True, zip_safe=False, )exit vim
-
Create the
__init__.pyfilecd netbox_systems vim __init__.pywrite:
from extras.plugins import PluginConfig class SystemsConfig(PluginConfig): name = 'netbox_systems' verbose_name = 'Systems Plugin' description = 'Netbox plugin to group vms and other resources into systems' version = '0.1' author = 'Surfer190' author_email = 'surfer190@fixes.co.za' base_url = 'systems' required_settings = [] default_settings = { } config = SystemsConfig -
Initialise the git repo and commit the code (also create a
.gitignore)cd .. vim .gitignorewrite:
env/then exit vim
git init git add . git commit -m "Setup systems plugin" -
Create virtual env and make your netbox instance path available to your plugin’s virtual environment (this assumes you have netbox somewhere on your dev machine)
python3.9 -m venv env cd env/lib/python3.9/site-packages/ echo /path/to/netbox/netbox > netbox.pth cd ../../../../ source env/bin/activateHow do you test that netbox is available?
python >>> import sys >>> print(sys.path) [..., '/path/to/netbox/netbox'] >>> from netbox import configuration >>> print(configuration.PLUGINS) [] -
Install the plugin into your development environment (creates symbolic links)
python setup.py develop
-
Create a model
cd netbox_systems vim models.pywrite:
from django.db import models from netbox.models import ChangeLoggedModel class System(ChangeLoggedModel): name = models.CharField(max_length=50) vms = models.ManyToManyField( 'virtualization.VirtualMachine', blank=True ) def __str__(self): return self.nameexit vim
-
Make migrations (but first you need a
manage.pyfile and minimal settings for a django project)This is where it is tricky, the tutorial just says run
./manage.py makemigrations <plugin_name>The problem is that there is no
manage.pyin the current directory…As suggested by Ben Lopatin in Django Standalone Apps, you must create your own minimal
manage.pyfile that lives in the plugin project root (not the plugin itself). It should look like this:Go to the project root and create a
manage.py:cd .. vim manage.pyand write:
#!/usr/bin/env python import os import sys import django from django.conf import settings os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.test_settings' django.setup() if __name__ == '__main__': from django.core.management import execute_from_command_line execute_from_command_line(sys.argv)Then you need a minimal settings file, that I put in
tests/test_settings.pymkdir tests touch __init__.py vim test_settings.pyand write:
from pathlib import Path SECRET_KEY = 'something' BASE_DIR = Path(__file__).resolve().parent.parent DATABASES={ "default": { "ENGINE": "django.db.backends.sqlite3", "NAME": BASE_DIR / 'db.sqlite3', } } ROOT_URLCONF="netbox_systems.urls" DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' INSTALLED_APPS=[ "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "extras", "netbox_systems", ] # Netbox ALLOWED_URL_SCHEMES = ( 'file', 'ftp', 'ftps', 'http', 'https', 'irc', 'mailto', 'sftp', 'ssh', 'tel', 'telnet', 'tftp', 'vnc', 'xmpp' )You can then create and name the migration:
./manage.py makemigrations netbox_systems -n create_base_systems_model -
Then add the model to admin
cd netbox_systems vim admin.pyand write:
from django.contrib import admin from .models import System @admin.register(System) class SystemAdmin(admin.ModelAdmin): list_display = ( 'name', 'service', 'environment_name', 'responsible_team', 'platform_owner', 'secondary', 'customer_data' ) -
Add tests
cd .. cd tests vim test_models.pyand write:
from django.test import TestCase from django.core.management import call_command from netbox_systems.models import Service class TestMigrations(TestCase): def test_no_missing_migrations(self): call_command("makemigrations", check=True, dry_run=True) class TestServiceModel(TestCase): def test_service_str_representation(self): service = Service.objects.create( name='DNS' ) self.assertEqual(str(service.name), 'DNS')then test with:
cd .. ./manage.py test
Adding a reference to a netbox model I got ModuleNotFoundError: No module named 'mptt'
So I had to install the netbox requirements into my plugin env…is that good or bad?
Also be
RuntimeError: Model class extras.models.change_logging.ObjectChange doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.
because I did:
class System(ChangeLoggedModel):
...
vms = models.ManyToManyField(
'virtualization.VirtualMachine'
)