Page MenuHomeDevCentral

Represent IPv6 gateway in NetBox
Closed, ResolvedPublic

Description

The VMs web-001 and router-001 use native IPv6 from OVH.

router-001 IPv6
ipv6:
  address: 2001:41d0:303:d971::6a7e
  gateway: 2001:41d0:303:d9ff:ff:ff:ff:ff
  prefix: 64

Currently, we've two custom fields default_gw and default_gw_virt in NetBox.

This field accepts only ONE IP. It should now accept several IPs.

D2790 must be amended to handle that new format.

Event Timeline

To update the type on NetBox is tricky: if we move from object to multiple object, the database isn't updated, so it generates an integer the isn't iterable (object id -> list of object ids).

3.4.8 disabled this possibility, #11431 - Disallow changing custom field type after creation

So I'd suggest the following plan:

  1. Create two new properties default_gateways and default_gateways_virt
  2. Run a migration script to populate those new properties with legacy content: default_gateways = [default_gw] and default_gateways_virt = [default_gw_virt]
  3. Drop the legacy properties default_gw and default_gw_virt
dereckson triaged this task as High priority.

Done, with a migration script.

1#!/usr/bin/env python3
2
3# -------------------------------------------------------------
4# NetBox - migrate gateways fields
5# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
6# Project: Nasqueron
7# Description: Copy a singleton in a list in NetBox
8# Dependencies: pynetbox
9# License: BSD-2-Clause
10# -------------------------------------------------------------
11
12
13import pynetbox
14import yaml
15
16
17# -------------------------------------------------------------
18# Get NetBox config and credentials
19#
20# Salt configuration is used to get credentials.
21# As a fallback, ~/.config/netbox/auth.yaml is used.
22# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
23
24
25def get_netbox_config_from_salt():
26 config_path = "/usr/local/etc/salt/master.d/netbox.conf"
27
28 if not os.path.exists(config_path):
29 return False, None
30
31 with open(config_path) as fd:
32 salt_config = yaml.safe_load(fd)
33 salt_config = salt_config["ext_pillar"][0]["netbox"]
34 return True, {
35 "server": salt_config["api_url"].replace("/api/", ""),
36 "token": salt_config["api_token"],
37 }
38
39
40def get_netbox_config_from_config_dir():
41 try:
42 config_path = os.path.join(os.environ["HOME"], ".config", "netbox", "auth.yaml")
43 except KeyError:
44 return False, None
45
46 if not os.path.exists(config_path):
47 return False, None
48
49 with open(config_path) as fd:
50 return True, yaml.safe_load(fd)
51
52
53def get_netbox_config():
54 methods = [get_netbox_config_from_salt, get_netbox_config_from_config_dir]
55
56 for method in methods:
57 has_config, config = method()
58 if has_config:
59 return config
60
61 raise RuntimeError("Can't find NetBox config")
62
63
64def connect_to_netbox(config):
65 return pynetbox.api(config["server"], token=config["token"])
66
67
68# -------------------------------------------------------------
69# NetBox migration
70#
71# Migrate a custom field with only one object to a field
72# accepting several objects.
73# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
74
75
76def migrate_object(object, singleton_old_field, new_field):
77 value = object.custom_fields[singleton_old_field]
78
79 if value is not None:
80 object.custom_fields[new_field] = [value]
81 object.save()
82
83
84def migrate(objects, singleton_old_field, new_field):
85 for object in objects:
86 migrate_object(object, singleton_old_field, new_field)
87
88
89# -------------------------------------------------------------
90# Application entry point
91# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
92
93
94def run():
95 config = get_netbox_config()
96 nb = connect_to_netbox(config)
97
98 migrate(nb.dcim.interfaces.all(), "default_gw", "default_gateways")
99 migrate(
100 nb.virtualization.interfaces.all(), "default_gw_virt", "default_gateways_virt"
101 )
102
103
104if __name__ == "__main__":
105 run()

I've documented the process at https://www.dereckson.be/blog/2023/05/13/switch-netbox-custom-field-type-from-object-to-multiple-objects/