Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates for Nautobot 2.0 #142

Merged
merged 62 commits into from
Jul 13, 2023
Merged
Show file tree
Hide file tree
Changes from 46 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
2ec77c4
build: 💥 Start upgrade to Nautobot 2.0
jdrew82 Jun 7, 2023
5ee82d7
fix: 🚚 Updating imports for new locations in Nautobot 2.0
jdrew82 Jun 8, 2023
fb82d13
fix: Temporarily disabled metrics until can be updated for new Jobs m…
jdrew82 Jun 8, 2023
6dcb3bc
fix: 💄 Fix the navigation elements to use new NavMenu elements
jdrew82 Jun 8, 2023
6b21b4d
test: ✅ Temporarily skip test until can update for Nautobot 2.0 changes
jdrew82 Jun 8, 2023
86c14f2
fix: Temporarily disable get_data_jobs functionality as get_jobs() fu…
jdrew82 Jun 8, 2023
1b4090f
refactor: ♻️ Update get_data_jobs() to work with new Job model directly
jdrew82 Jun 8, 2023
b93fb68
refactor: ♻️ Update Jobs to replace Region & Site with Location and L…
jdrew82 Jun 8, 2023
1b6c60b
refactor: ♻️ Redo Job form to remove check for 1.2 and hiding commit …
jdrew82 Jun 8, 2023
743fdfe
refactor: ♻️ Update DataSyncBaseJob to inherit from Job instead of Ba…
jdrew82 Jun 8, 2023
4e4628c
refactor: 🚚 Correct imports to use new locations
jdrew82 Jun 9, 2023
7ac2959
refactor: ♻️ Update metrics to use new Job model.
jdrew82 Jun 9, 2023
3d530d1
fix: 🐛 Add api kwarg to match super() function.
jdrew82 Jun 9, 2023
a217fa2
style: 🚚 Update var name to not conflict with jobs var.
jdrew82 Jun 9, 2023
3a4aa0b
refactor: 🚚 Move register_jobs method call to align with where jobs i…
jdrew82 Jun 9, 2023
f4fd3f4
docs: 📝 Updating documentation to remove atomic transaction as not re…
jdrew82 Jun 9, 2023
f2edd53
fix: 🐛 Correct duration function to use new JobResultStatusChoices an…
jdrew82 Jun 9, 2023
24f265b
test: ✅ Update tests for new JobResult model attributes
jdrew82 Jun 9, 2023
442ac6c
test: 🚨 Address various linter complaints
jdrew82 Jun 9, 2023
06e5dea
fix: 🐛 Correct View to perform Sync query with updated JobResult fields.
jdrew82 Jun 9, 2023
08fbb5d
refactor: ♻️ Update all Jobs and related models for Nautobot 2.0.
jdrew82 Jun 9, 2023
e0a0c32
build: 🏗️ Add pylint-nautobot to dev-dependencies
jdrew82 Jun 12, 2023
d0cfebc
fix: 🐛 Correct Job init to address merge errors
jdrew82 Jun 12, 2023
496d57d
fix: 🐛 Fix JobResult status for Sync objects to fix dashboard view
jdrew82 Jun 13, 2023
fbd1227
fix: 🐛 Update Sync query for data sources/targets to use class_path.
jdrew82 Jun 13, 2023
5abe2fc
test: 🚨 Add timeouts to requests to address pylint complaint
jdrew82 Jun 13, 2023
3cb3169
test: 🚨 Disable broad Exception linter complaint for adding integrations
jdrew82 Jun 13, 2023
6dbb05b
test: 🚨 Remove unnecessary paranthesis for linter
jdrew82 Jun 13, 2023
fff00f8
refactor: ♻️ Update Job registration to happen after integrations and…
jdrew82 Jun 13, 2023
85d098f
refactor: ♻️ Updating Infoblox integration for Nautobot 2.0 changes.
jdrew82 Jun 13, 2023
415321e
fix: 🐛 Correct log attribute to level_choice instead of level
jdrew82 Jun 13, 2023
b77dc02
refactor: ♻️ Specify log level in log statements and update missed lo…
jdrew82 Jun 14, 2023
c853134
fix: :bug: Override run method to pass form variables
jdrew82 Jun 14, 2023
7282776
fix: 🐛 Update Status to use name instead of slug
jdrew82 Jun 14, 2023
19e75ce
build: ➕ Add pylint-nautobot as dev dependency
jdrew82 Jun 14, 2023
1954593
fix: 🐛 Update group attribute for VLANs to be vlan_group
jdrew82 Jun 14, 2023
c6399ec
refactor: 🔥 Remove shortname for IPAddress model
jdrew82 Jun 14, 2023
0df84ba
fix: 🐛 Update CustomFields to use key and remove name & slug fields
jdrew82 Jun 14, 2023
428333b
fix: 🐛 Update Relationship to use label instead of name
jdrew82 Jun 14, 2023
44f195b
fix: 🐛 Specify related Prefix when creating IPAddress
jdrew82 Jun 14, 2023
77b4e58
refactor: ♻️ Update IPAddress create to use prefix and prefix_length …
jdrew82 Jun 14, 2023
5c7d29f
refactor: 🐛 Move application of Import tag to happen after sync_compl…
jdrew82 Jun 14, 2023
433e9ab
ci: 👷 Update CI to use 2.0.0-beta.1
jdrew82 Jun 21, 2023
e39cd01
fix: 🏗️ Update metadata to come from importlib
jdrew82 Jun 21, 2023
f6fcdbe
refactor: ♻️ Update logging to use job.logger.<type> and use lazy log…
jdrew82 Jul 6, 2023
e6e81f1
fix: Update prefix status to use type.
jdrew82 Jul 6, 2023
4f112f5
build: ⬆️ Update to Nautobot 2.0.0b2
jdrew82 Jul 11, 2023
3034b3b
build: ⬆️ Update all project dependencies
jdrew82 Jul 11, 2023
add5a0c
fix: 🐛 Revert App to be in Plugins menu
jdrew82 Jul 11, 2023
6857a1f
fix: 🐛 Change Tags to use name and remove slug
jdrew82 Jul 11, 2023
d44fe5e
test: ✅ Add ignored test for list_objects_unknown_filter_no_strict_fi…
jdrew82 Jul 11, 2023
11da154
ci: 👷 Update CI to use 2.0.0-beta2
jdrew82 Jul 11, 2023
221802c
ci: 👷 Update CI to use py 3.10 to match dev container
jdrew82 Jul 11, 2023
a99ea00
ci: 👷 Pylint should use 3.10 also
jdrew82 Jul 11, 2023
126ebb7
fix: 🐛 Update metric labels to use natural_key function
jdrew82 Jul 11, 2023
263116c
fix: 🐛 Correct other instances of Tag slug to name
jdrew82 Jul 11, 2023
e25a929
refactor: ♻️ Change Prefix status attribute to network_type to match …
jdrew82 Jul 11, 2023
49aae0e
refactor: ♻️ Made Status of Prefix Active always as can't determine n…
jdrew82 Jul 11, 2023
da27a46
fix: 🐛 Remove slug from VLANGroup creation.
jdrew82 Jul 11, 2023
8ce83b5
build: 🏗️ Add healthcheck to nautobot container and update worker to …
jdrew82 Jul 11, 2023
2663281
test: 🚨 Fix yamllint complaint
jdrew82 Jul 11, 2023
ddf1c67
build: 🔧 Remove 1.x from pylint-nautobot support versions
jdrew82 Jul 13, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ jobs:
fail-fast: true
matrix:
python-version: ["3.8"]
nautobot-version: ["1.5.13"]
nautobot-version: ["v2.0.0-beta.1"]
jdrew82 marked this conversation as resolved.
Show resolved Hide resolved
env:
INVOKE_NAUTOBOT_SSOT_PYTHON_VER: "${{ matrix.python-version }}"
INVOKE_NAUTOBOT_SSOT_NAUTOBOT_VER: "${{ matrix.nautobot-version }}"
Expand Down Expand Up @@ -119,19 +119,16 @@ jobs:
strategy:
fail-fast: true
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10"]
python-version: ["3.8", "3.9", "3.10"]
db-backend: ["postgresql"]
nautobot-version: ["latest"]
nautobot-version: ["v2.0.0-beta.1"]
include:
- python-version: "3.10"
db-backend: "postgresql"
nautobot-version: "1.5.13"
- python-version: "3.7"
- python-version: "3.8"
db-backend: "mysql"
nautobot-version: "1.5.13"
nautobot-version: "v2.0.0-beta.1"
- python-version: "3.10"
db-backend: "mysql"
nautobot-version: "stable"
nautobot-version: "v2.0.0-beta.1"
runs-on: "ubuntu-20.04"
env:
INVOKE_NAUTOBOT_SSOT_PYTHON_VER: "${{ matrix.python-version }}"
Expand Down
3 changes: 1 addition & 2 deletions development/development.env
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ MYSQL_ROOT_HOST=%
NAUTOBOT_SSOT_HIDE_EXAMPLE_JOBS="False"

NAUTOBOT_SSOT_ENABLE_INFOBLOX="True"
NAUTOBOT_SSOT_INFOBLOX_DEFAULT_STATUS="active"
NAUTOBOT_SSOT_INFOBLOX_ENABLE_RFC1918_NETWORK_CONTAINERS="True"
NAUTOBOT_SSOT_INFOBLOX_DEFAULT_STATUS="Active"
NAUTOBOT_SSOT_INFOBLOX_ENABLE_SYNC_TO_INFOBLOX="True"
NAUTOBOT_SSOT_INFOBLOX_IMPORT_OBJECTS_IP_ADDRESSES="True"
NAUTOBOT_SSOT_INFOBLOX_IMPORT_OBJECTS_SUBNETS="True"
Expand Down
3 changes: 0 additions & 3 deletions development/nautobot_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,6 @@
"enable_infoblox": is_truthy(os.getenv("NAUTOBOT_SSOT_ENABLE_INFOBLOX")),
"hide_example_jobs": is_truthy(os.getenv("NAUTOBOT_SSOT_HIDE_EXAMPLE_JOBS")),
"infoblox_default_status": os.getenv("NAUTOBOT_SSOT_INFOBLOX_DEFAULT_STATUS", "active"),
"infoblox_enable_rfc1918_network_containers": is_truthy(
os.getenv("NAUTOBOT_SSOT_INFOBLOX_ENABLE_RFC1918_NETWORK_CONTAINERS")
),
"infoblox_enable_sync_to_infoblox": is_truthy(os.getenv("NAUTOBOT_SSOT_INFOBLOX_ENABLE_SYNC_TO_INFOBLOX")),
"infoblox_import_objects_ip_addresses": is_truthy(
os.getenv("NAUTOBOT_SSOT_INFOBLOX_IMPORT_OBJECTS_IP_ADDRESSES")
Expand Down
28 changes: 0 additions & 28 deletions docs/user/developing_jobs.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,34 +158,6 @@ Similar to the database example further up, this suffers from having to perform

Finally, there are a couple of further ideas that could be used to improve performance. These aren't as well analyzed as the prior ones and there might be built-in support in this app for the in the future:

#### Escaping the Atomic Transaction

In Nautobot 1.x, all Jobs are executed in an [atomic transaction](https://en.wikipedia.org/wiki/Atomicity_(database_systems)). Atomic transactions often incur a performance overhead. The following example highlights how to have your sync operation "escape" the atomic transaction:

```python
class DataSource(DataSource, Job):
... # Excluded most of the class definition for example brevity

def execute_sync(self):
self.log_info(obj=None, message="The actual sync happens in post_run to escape the atomic transaction.")

def post_run(self):
super().execute_sync()
```

Using this example, the CRUD (create, update and delete) operations of your job will not happen as part of the atomic database transaction, because `post_run` is run outside of that. This brings with it the following caveats:

- The job result page in Nautobot will show the status of "Completed" _before_ your actual sync runs
- You will need to manually update the page to get further job log results
- The job result might still go into an erroneous state, updating the job result status
- If you implement any further logic in `post_run` keep in mind that it doesn't bubble exceptions up to the job result page in Nautobot
- If any exceptions are encountered during the CRUD operations (i.e. the diffsync models' `create`, `update` and `delete` methods) they will _not_ trigger a rollback of the objects created during this job

Due to these caveats it is recommended that you check carefully whether this optimization actually benefits your use case or not before applying it in production code.

!!! note
In Nautobot 2.0, jobs will no longer be atomic by default so this section will not apply anymore.

#### Using Bulk ORM Operations

Bulk ORM operations are available within Django to perform multiple inserts/updates in a single DB query. Take a look at the documentation for [bulk_create](https://docs.djangoproject.com/en/3.2/ref/models/querysets/#bulk-create) for example. These bulk operations should only be used very carefully in Nautobot. The following caveats apply when using them:
Expand Down
11 changes: 3 additions & 8 deletions nautobot_ssot/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
"""Plugin declaration for nautobot_ssot."""
# Metadata is inherited from Nautobot. If not including Nautobot in the environment, this should be added

try:
from importlib import metadata
except ImportError:
# Python version < 3.8
import importlib_metadata as metadata
from importlib import metadata

from nautobot.extras.plugins import PluginConfig

Expand All @@ -25,8 +20,8 @@ class NautobotSSOTPluginConfig(PluginConfig):
description = "Nautobot App that enables Single Source of Truth. Allows users to aggregate distributed data sources and/or distribute Nautobot data to other data sources such as databases and SDN controllers."
base_url = "ssot"
required_settings = []
min_version = "1.4.0"
max_version = "1.9999"
min_version = "2.0.0b1"
max_version = "2.9999"
default_settings = {
"enable_infoblox": False,
"hide_example_jobs": True,
Expand Down
2 changes: 1 addition & 1 deletion nautobot_ssot/choices.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""ChoiceSet classes for Single Source of Truth (SSoT)."""

from nautobot.utilities.choices import ChoiceSet
from nautobot.apps.choices import ChoiceSet


class SyncLogEntryActionChoices(ChoiceSet):
Expand Down
10 changes: 7 additions & 3 deletions nautobot_ssot/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import django_filters
from django.db.models import Q

from nautobot.utilities.filters import BaseFilterSet
from nautobot.apps.filters import BaseFilterSet

from .models import Sync, SyncLogEntry

Expand All @@ -29,8 +29,12 @@ class Meta:
model = SyncLogEntry
fields = ["sync", "action", "status", "synced_object_type"]

def search(self, queryset, _name, value): # pylint: disable=no-self-use
def search(self, queryset, _name, value):
"""String search of SyncLogEntry records."""
if not value.strip():
return queryset
return queryset.filter(Q(diff__icontains=value) | Q(message__icontains=value) | Q(object_repr__icontains=value))
return queryset.filter(
Q(diff__icontains=value) # pylint: disable=unsupported-binary-operation
| Q(message__icontains=value)
| Q(object_repr__icontains=value)
)
3 changes: 2 additions & 1 deletion nautobot_ssot/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

from django import forms

from nautobot.utilities.forms import add_blank_choice, BootstrapMixin, BOOLEAN_WITH_BLANK_CHOICES
from nautobot.apps.forms import add_blank_choice
from nautobot.core.forms import BootstrapMixin, BOOLEAN_WITH_BLANK_CHOICES

from .choices import SyncLogEntryActionChoices, SyncLogEntryStatusChoices
from .models import Sync, SyncLogEntry
Expand Down
56 changes: 5 additions & 51 deletions nautobot_ssot/integrations/infoblox/diffsync/adapters/infoblox.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"""Infoblox Adapter for Infoblox integration with SSoT plugin."""
import ipaddress
import re

from diffsync import DiffSync
Expand All @@ -9,7 +8,6 @@
from nautobot_ssot.integrations.infoblox.utils.client import get_default_ext_attrs, get_dns_name
from nautobot_ssot.integrations.infoblox.utils.diffsync import get_ext_attr_dict, build_vlan_map
from nautobot_ssot.integrations.infoblox.diffsync.models.infoblox import (
InfobloxAggregate,
InfobloxIPAddress,
InfobloxNetwork,
InfobloxVLANView,
Expand Down Expand Up @@ -42,8 +40,8 @@ def __init__(self, *args, job=None, sync=None, conn=None, **kwargs):
self.subnets = []

if self.conn in [None, False]:
self.job.log_failure(
message="Improperly configured settings for communicating to Infoblox. Please validate accuracy."
self.job.logger.error(
"Improperly configured settings for communicating to Infoblox. Please validate accuracy."
)
raise PluginImproperlyConfigured

Expand All @@ -66,7 +64,7 @@ def load_prefixes(self):
new_pf = self.prefix(
network=_pf["network"],
description=_pf.get("comment", ""),
status=_pf.get("status", "active"),
status=_pf.get("status", "Active"),
ext_attrs={**default_ext_attrs, **pf_ext_attrs},
vlans=build_vlan_map(vlans=_pf["vlans"]) if _pf.get("vlans") else {},
)
Expand Down Expand Up @@ -135,59 +133,15 @@ def load(self):
if PLUGIN_CFG["infoblox_import_objects"].get("vlans"):
self.load_vlans()
else:
self.job.log_info(
message="The `infoblox_import_objects` setting was not found so all objects will be imported."
)
self.job.logger.info("The `infoblox_import_objects` setting was not found so all objects will be imported.")
self.load_prefixes()
self.load_ipaddresses()
self.load_vlanviews()
self.load_vlans()
for obj in ["prefix", "ipaddress", "vlangroup", "vlan"]:
if obj in self.dict():
self.job.log(message=f"Loaded {len(self.dict()[obj])} {obj} from Infoblox.")
self.job.logger.info(f"Loaded {len(self.dict()[obj])} {obj} from Infoblox.")

def sync_complete(self, source, diff, flags=DiffSyncFlags.NONE, logger=None):
"""Add tags and custom fields to synced objects."""
source.tag_involved_objects(target=self)


class InfobloxAggregateAdapter(DiffSync):
"""DiffSync adapter using requests to communicate to Infoblox server."""

aggregate = InfobloxAggregate

top_level = ["aggregate"]

def __init__(self, *args, job=None, sync=None, conn=None, **kwargs):
"""Initialize Infoblox.

Args:
job (object, optional): Infoblox job. Defaults to None.
sync (object, optional): Infoblox DiffSync. Defaults to None.
conn (object): InfobloxAPI connection.
"""
super().__init__(*args, **kwargs)
self.job = job
self.sync = sync
self.conn = conn

if self.conn in [None, False]:
self.job.log_failure(
message="Improperly configured settings for communicating to Infoblox. Please validate accuracy."
)
raise PluginImproperlyConfigured

def load(self):
"""Load aggregate models."""
containers = self.conn.get_network_containers()
default_ext_attrs = get_default_ext_attrs(review_list=containers)
for container in containers:
network = ipaddress.ip_network(container["network"])
container_ext_attrs = get_ext_attr_dict(extattrs=container.get("extattrs", {}))
if network.is_private and container["network"] in ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]:
new_aggregate = self.aggregate(
network=container["network"],
description=container["comment"] if container.get("comment") else "",
ext_attrs={**default_ext_attrs, **container_ext_attrs},
)
self.add(new_aggregate)
Loading
Loading