Skip to content
This repository has been archived by the owner on Oct 25, 2023. It is now read-only.

Commit

Permalink
Add minor CRUD operations, additional fields, other misc. (#49)
Browse files Browse the repository at this point in the history
  • Loading branch information
FragmentedPacket authored Jan 19, 2022
1 parent 9b729ec commit 386ad91
Show file tree
Hide file tree
Showing 9 changed files with 737 additions and 531 deletions.
23 changes: 12 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# Nautobot SSoT Infoblox

Using the [Nautobot SSoT](https://github.com/nautobot/nautobot-plugin-ssot) framework, the SSoT plugin for Infoblox allows for syncronizing source of IP network and VLAN data between [Infoblox](https://infoblox.com/) and [Nautobot](https://github.com/nautobot/nautobot).
Using the [Nautobot SSoT](https://github.com/nautobot/nautobot-plugin-ssot) framework, the SSoT plugin for Infoblox allows for synchronizing source of IP network and VLAN data between [Infoblox](https://infoblox.com/) and [Nautobot](https://github.com/nautobot/nautobot).

## Installation

The plugin is available as a Python package in pypi and can be installed with pip
The plugin is available as a Python package in PyPi and can be installed with pip.

```shell
pip install nautobot-ssot-infoblox
```

> The plugin is compatible with Nautobot 1.1.0 and higher
> The plugin is compatible with Nautobot 1.2.0 and higher
To ensure Nautobot SSoT Infoblox is automatically re-installed during future upgrades, create a file named `local_requirements.txt` (if not already existing) in the Nautobot root directory (alongside `requirements.txt`) and list the `nautobot-ssot-infoblox` package:

Expand All @@ -37,16 +37,17 @@ PLUGINS_CONFIG = {
}
```

## Usage
## DiffSync Models

The data fields that can be syncronized are:
Below are the data mappings between objects within Infoblox and the corresponding objects within Nautobot:

| Infoblox | Nautobot |
------------|-------------
| network | Prefix |
| ipaddress | IP Address |
| vlan | VLAN |
| vlanview | VLANGroup |
| Infoblox | Nautobot |
| ----------------- | ---------- |
| Network | Prefix |
| IP Address | IP Address |
| Vlan | VLAN |
| Vlan view | VLAN Group |
| Network container | Aggregate |

### API

Expand Down
6 changes: 6 additions & 0 deletions nautobot_ssot_infoblox/diffsync/adapters/infoblox.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Infoblox Adapter for Infoblox integration with SSoT plugin."""
import ipaddress
import re

from diffsync import DiffSync
from nautobot_ssot_infoblox.diffsync.client import InfobloxApi
Expand Down Expand Up @@ -49,9 +50,12 @@ def load_ipaddresses(self):
"""Method to load InfobloxIPAddress DiffSync model."""
for _prefix in self.subnets:
for _ip in self.conn.get_all_ipv4address_networks(prefix=_prefix):
_, prefix_length = _ip["network"].split("/")
new_ip = self.ipaddress(
address=_ip["ip_address"],
prefix=_ip["network"],
prefix_length=prefix_length,
dns_name=_ip["names"][0] if _ip["names"] else "",
status=self.conn.get_ipaddr_status(_ip),
description=_ip["comment"],
)
Expand All @@ -69,10 +73,12 @@ def load_vlanviews(self):
def load_vlans(self):
"""Method to load InfoblocVlan DiffSync model."""
for _vlan in self.conn.get_vlans():
vlan_group = re.search(r"(?:.+\:)(\S+)(?:\/\S+\/.+)", _vlan["_ref"])
new_vlan = self.vlan(
name=_vlan["name"],
vid=_vlan["id"],
status=_vlan["status"],
vlangroup=vlan_group.group(1) if vlan_group else "",
description=_vlan["comment"] if _vlan.get("comment") else "",
)
self.add(new_vlan)
Expand Down
11 changes: 7 additions & 4 deletions nautobot_ssot_infoblox/diffsync/adapters/nautobot.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"""Nautobot Adapter for Infoblox integration with SSoT plugin."""
import re
from diffsync import DiffSync
from nautobot.ipam.models import Aggregate, IPAddress, Prefix, VLAN, VLANGroup
from nautobot_ssot_infoblox.diffsync.models import (
Expand Down Expand Up @@ -45,14 +44,17 @@ def load_prefixes(self):
def load_ipaddresses(self):
"""Method to load IP Addresses from Nautobot."""
for ipaddr in IPAddress.objects.all():
addr = re.sub(r"/\d+", "", str(ipaddr.address))
_pf = Prefix.objects.net_contains(addr)
addr = ipaddr.host
# _pf = Prefix.objects.net_contains(addr)
prefix = Prefix.objects.net_contains(addr).last()
# the last Prefix is the most specific and is assumed the one the IP address resides in
prefix = _pf[len(_pf) - 1]
# prefix = _pf[len(_pf) - 1]
_ip = self.ipaddress(
address=addr,
prefix=str(prefix),
status=ipaddr.status.name,
prefix_length=ipaddr.prefix_length,
dns_name=ipaddr.dns_name,
description=ipaddr.description,
)
self.add(_ip)
Expand All @@ -73,6 +75,7 @@ def load_vlans(self):
vid=vlan.vid,
name=vlan.name,
description=vlan.description,
vlangroup=vlan.group.name if vlan.group else "",
status=nautobot_vlan_status(vlan.status.name),
)
self.add(_vlan)
Expand Down
28 changes: 28 additions & 0 deletions nautobot_ssot_infoblox/diffsync/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,22 @@ def reserve_fixed_address(self, network, mac_address):
return response.json().get("result").get("ipv4addr")
return False

def create_fixed_address(self, ip_address, mac_address):
"""Creates a fixed ip address within Infoblox.
Returns:
Str: The IP Address that was reserved
Return Response:
"10.220.0.1"
"""
url_path = "fixedaddress"
params = {"_return_fields": "ipv4addr", "_return_as_object": 1}
payload = {"ipv4addr": ip_address, "mac": mac_address}
response = self._request("POST", url_path, params=params, json=payload)
logger.info(response.json())
return response.json().get("result").get("ipv4addr")

def create_host_record(self, fqdn, ip_address):
"""Create an host record for a given FQDN.
Expand All @@ -818,6 +834,18 @@ def create_host_record(self, fqdn, ip_address):
logger.info("Infoblox host record created: %s", response.json())
return response.json().get("result")

def delete_host_record(self, ip_address):
"""Delete provided IP Address from Infoblox."""
resource = self.get_host_record_by_ip(ip_address)
if resource:
ref = resource[0]["_ref"]
self._delete(ref)
response = {"deleted": ip_address}
else:
response = {"error": f"Did not find {ip_address}"}
logger.info(response)
return response

def create_ptr_record(self, fqdn, ip_address):
"""Create an PTR record for a given FQDN.
Expand Down
6 changes: 4 additions & 2 deletions nautobot_ssot_infoblox/diffsync/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,14 @@ class IPAddress(DiffSyncModel):
"""IPAddress model for DiffSync."""

_modelname = "ipaddress"
_identifiers = ("address", "prefix")
_identifiers = ("address", "prefix", "prefix_length")
_shortname = ("address",)
_attributes = ("status", "description")
_attributes = ("status", "description", "dns_name")

address: str
dns_name: str
prefix: str
prefix_length: int
status: str
description: Optional[str]

Expand Down
17 changes: 16 additions & 1 deletion nautobot_ssot_infoblox/diffsync/models/infoblox.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,28 @@ def create(cls, diffsync, ids, attrs):
class InfobloxIPAddress(IPAddress):
"""Infoblox implementation of the VLAN Model."""

@classmethod
def create(cls, diffsync, ids, attrs):
"""Will create either a host record or fixed address (Not implemented).
This requires the IP Address to either have a DNS name
"""
if attrs["dns_name"]:
diffsync.conn.create_host_record(attrs["dns_name"], ids["address"])
return super().create(ids=ids, diffsync=diffsync, attrs=attrs)

def update(self, attrs):
"""Updates IPAddress object in Infoblox."""
"""Updates IP Address object in Infoblox."""
if attrs.get("description"):
json = {"comment": attrs["description"]}
self.diffsync.conn.update_ipaddress(address=self.get_identifiers()["address"], data=json)
return super().update(attrs)

def delete(self):
"""Delete an IP Address from Infoblox."""
self.diffsync.conn.delete_host_record(self.get_identifiers()["address"])
return super().delete()


class InfobloxAggregate(Aggregate):
"""Infoblox implementation of the Aggregate Model."""
Expand Down
16 changes: 11 additions & 5 deletions nautobot_ssot_infoblox/diffsync/models/nautobot.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,16 @@ def update(self, attrs):
_ipaddr.status = OrmStatus.objects.get(name=attrs["status"])
if attrs.get("description"):
_ipaddr.description = attrs["description"]
if attrs.get("dns_name"):
_ipaddr.dns_name = attrs["dns_name"]
_ipaddr.validated_save()
return super().update(attrs)

def delete(self):
"""Delete IPAddress object in Nautobot."""
self.diffsync.job.log_warning(f"IP Address {self.address} will be deleted.")
_ipaddr = OrmPrefix.objects.get(address=self.get_identifiers()["address"])
self.diffsync.job.log_warning(self, message=f"IP Address {self.address} will be deleted.")
ip_ids = self.get_identifiers()
_ipaddr = OrmIPAddress.objects.get(address=f"{ip_ids['address']}/{ip_ids['prefix_length']}")
_ipaddr.delete()
return super().delete()

Expand All @@ -95,7 +98,7 @@ def create(cls, diffsync, ids, attrs):

def delete(self):
"""Delete VLANGroup object in Nautobot."""
self.diffsync.job.log_warning(f"VLAN Group {self.name} will be deleted.")
self.diffsync.job.log_warning(message=f"VLAN Group {self.name} will be deleted.")
_vg = OrmVlanGroup.objects.get(**self.get_identifiers())
_vg.delete()
return super().delete()
Expand All @@ -111,6 +114,7 @@ def create(cls, diffsync, ids, attrs):
vid=ids["vid"],
name=attrs["name"],
status=OrmStatus.objects.get(name=cls.get_vlan_status(attrs["status"])),
group=OrmVlanGroup.objects.get(name=attrs["vlangroup"]) if attrs["vlangroup"] else None,
description=attrs["description"],
)
_vlan.tags.add(Tag.objects.get(slug="created-by-infoblox"))
Expand All @@ -134,12 +138,14 @@ def update(self, attrs):
_vlan.status = OrmStatus.objects.get(name=self.get_vlan_status(attrs["status"]))
if attrs.get("description"):
_vlan.description = attrs["description"]
if attrs.get("vlangroup"):
_vlan.group = OrmVlanGroup.objects.get(name=attrs["vlangroup"])
_vlan.validated_save()
return super().update(attrs)

def delete(self):
"""Delete VLAN object in Nautobot."""
self.diffsync.job.log_warning(f"VLAN {self.vid} will be deleted.")
self.diffsync.job.log_warning(message=f"VLAN {self.vid} will be deleted.")
_vlan = OrmVlan.objects.get(vid=self.get_identifiers()["vid"])
_vlan.delete()
return super().delete()
Expand Down Expand Up @@ -171,7 +177,7 @@ def update(self, attrs):

def delete(self):
"""Delete Aggregate object in Nautobot."""
self.diffsync.job.log_warning(f"Aggregate {self.network} will be deleted.")
self.diffsync.job.log_warning(message=f"Aggregate {self.network} will be deleted.")
_aggregate = OrmAggregate.objects.get(prefix=self.get_identifiers()["network"])
_aggregate.delete()
return super().delete()
Loading

0 comments on commit 386ad91

Please sign in to comment.