Skip to content

Netbox Create IP Task¤

task api name: create_ip

Task to create next available IP from prefix or get existing IP address.

Netbox service create_ip task integrated with Nornir service and can be called using nb_create_ip Jinja2 filter, allowing to allocate IP addresses in Netbox on the fly while rendering configuration templates.

NORFAB Netbox Create IP Command Shell Reference¤

NorFab shell supports these command options for Netbox create_ip task:

nf#man tree netbox.create.ip
root
└── netbox:    Netbox service
    └── create:    Create objects in Netbox
        └── ip:    Allocate next available IP address from prefix
            ├── instance:    Netbox instance name to target
            ├── workers:    Filter worker to target, default 'any'
            ├── timeout:    Job timeout
            ├── verbose-result:    Control output details, default 'False'
            ├── *prefix:    Prefix to allocate IP address from, can also provide prefix name or filters
            ├── device:    Device name to associate IP address with
            ├── interface:    Device interface name to associate IP address with
            ├── description:    IP address description
            ├── vrf:    VRF to associate with IP address
            ├── tags:    Tags to add to IP address
            ├── dns_name:    IP address DNS name
            ├── tenant:    Tenant name to associate with IP address
            ├── comments:    IP address comments field
            ├── role:    IP address functional role
            └── dry-run:    Do not commit to database
nf#

Python API Reference¤

Allocate the next available IP address from a given subnet.

Parameters:

Name Type Description Default
job Job

NorFab Job object containing relevant metadata

required
prefix str

The prefix from which to allocate the IP address.

required
description str

A description for the allocated IP address.

None
device str

The device associated with the IP address.

None
interface str

The interface associated with the IP address.

None
vrf str

The VRF (Virtual Routing and Forwarding) instance.

None
tags list

A list of tags to associate with the IP address.

None
dns_name str

The DNS name for the IP address.

None
tenant str

The tenant associated with the IP address.

None
comments str

Additional comments for the IP address.

None
instance str

The NetBox instance to use.

None
dry_run bool

If True, do not actually allocate the IP address. Defaults to False.

False

Returns:

Name Type Description
dict Result

A dictionary containing the result of the IP allocation.

Source code in norfab\workers\netbox_worker.py
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
@Task()
def create_ip(
    self,
    job: Job,
    prefix: Union[str, dict],
    device: str = None,
    interface: str = None,
    description: str = None,
    vrf: str = None,
    tags: Union[None, list] = None,
    dns_name: str = None,
    tenant: str = None,
    comments: str = None,
    role: str = None,
    is_primary: bool = None,
    instance: Union[None, str] = None,
    dry_run: bool = False,
) -> Result:
    """
    Allocate the next available IP address from a given subnet.

    Args:
        job: NorFab Job object containing relevant metadata
        prefix (str): The prefix from which to allocate the IP address.
        description (str, optional): A description for the allocated IP address.
        device (str, optional): The device associated with the IP address.
        interface (str, optional): The interface associated with the IP address.
        vrf (str, optional): The VRF (Virtual Routing and Forwarding) instance.
        tags (list, optional): A list of tags to associate with the IP address.
        dns_name (str, optional): The DNS name for the IP address.
        tenant (str, optional): The tenant associated with the IP address.
        comments (str, optional): Additional comments for the IP address.
        instance (str, optional): The NetBox instance to use.
        dry_run (bool, optional): If True, do not actually allocate the IP address. Defaults to False.

    Returns:
        dict: A dictionary containing the result of the IP allocation.
    """
    instance = instance or self.default_instance
    ret = Result(task=f"{self.name}:create_ip", result={}, resources=[instance])
    tags = tags or []
    has_changes = False
    nb_ip = None
    nb_device = None
    nb = self._get_pynetbox(instance)

    # try to source existing IP from netbox
    if device and interface and description:
        nb_ip = nb.ipam.ip_addresses.get(
            device=device, interface=interface, description=description
        )
    elif device and interface:
        nb_ip = nb.ipam.ip_addresses.get(device=device, interface=interface)
    elif description:
        nb_ip = nb.ipam.ip_addresses.get(description=description)

    # create new IP address
    if not nb_ip:
        job.event(f"Creating new IP address {nb_ip} from prefix {prefix}")
        # source prefix from Netbox
        if isinstance(prefix, str):
            if vrf:
                nb_prefix = nb.ipam.prefixes.get(prefix=prefix, vrf__name=vrf)
            else:
                nb_prefix = nb.ipam.prefixes.get(prefix=prefix)
        elif isinstance(prefix, dict):
            nb_prefix = nb.ipam.prefixes.get(**prefix)
        if not nb_prefix:
            raise RuntimeError(f"Unable to source prefix from Netbox - {prefix}")
        # execute dry run on new IP
        if dry_run is True:
            nb_ip = nb_prefix.available_ips.list()[0]
            ret.status = "unchanged"
            ret.dry_run = True
            ret.result = {
                "address": str(nb_ip),
                "description": description,
                "vrf": vrf,
                "device": device,
                "interface": interface,
            }
            return ret
        # create new IP
        else:
            nb_ip = nb_prefix.available_ips.create()
        ret.status = "created"
    else:
        job.event(f"Using existing IP address {nb_ip}")
        ret.status = "updated"

    # update IP address parameters
    if description and description != nb_ip.description:
        nb_ip.description = description
        has_changes = True
    if vrf and vrf != nb_ip.vrf:
        nb_ip.vrf = {"name": vrf}
        has_changes = True
    if tenant and tenant != nb_ip.tenant:
        nb_ip.tenant = {"name": tenant}
        has_changes = True
    if dns_name and dns_name != nb_ip.dns_name:
        nb_ip.dns_name = dns_name
        has_changes = True
    if comments and comments != nb_ip.comments:
        nb_ip.comments = comments
        has_changes = True
    if role and role != nb_ip.role:
        nb_ip.role = role
        has_changes = True
    if tags and not any(t in nb_ip.tags for t in tags):
        for t in tags:
            if t not in nb_ip.tags:
                nb_ip.tags.append({"name": t})
                has_changes = True
    if device and interface:
        nb_interface = nb.dcim.interfaces.get(device=device, name=interface)
        if not nb_interface:
            raise RuntimeError(
                f"Unable to source '{device}:{interface}' interface from Netbox"
            )
        if (
            hasattr(nb_ip, "assigned_object")
            and nb_ip.assigned_object != nb_interface.id
        ):
            nb_ip.assigned_object_id = nb_interface.id
            nb_ip.assigned_object_type = "dcim.interface"
            if is_primary is not None:
                nb_device = nb.dcim.devices.get(name=device)
                nb_device.primary_ip4 = nb_ip.id
            has_changes = True

    # save IP address into Netbox
    if dry_run:
        ret.status = "unchanged"
        ret.dry_run = True
    elif has_changes:
        nb_ip.save()
        # make IP primary for device
        if is_primary is True and nb_device:
            nb_device.save()
    else:
        ret.status = "unchanged"

    # form and return results
    ret.result = {
        "address": str(nb_ip),
        "description": str(nb_ip.description),
        "vrf": str(nb_ip.vrf) if not vrf else nb_ip.vrf["name"],
        "device": device,
        "interface": interface,
    }

    return ret