nautobot / nautobot-plugin-ssot-arista-cloudvision Goto Github PK
View Code? Open in Web Editor NEWSingle Source of Truth synchronization between Nautobot and Arista CloudVision
License: Other
Single Source of Truth synchronization between Nautobot and Arista CloudVision
License: Other
Sync between CVP and nautobot
Error running CloudVision ⟹ Nautobot job
I downgraded nautobot-ssot-aristacv
to 1.5.1 and the sync job runs properly with no issues.
Sync works
Sync fails
In CVP 2021.1.1 (at least), when you place devices in nested container, the device inherits multiple Container
tags, which results in errors when syncing:
Traceback (most recent call last):
File "/opt/nautobot/.local/lib/python3.9/site-packages/nautobot_ssot_aristacv/diffsync/fromcv/cloudvision.py", line 39, in load
self.add(self.cf)
File "/opt/nautobot/.local/lib/python3.9/site-packages/diffsync/__init__.py", line 657, in add
raise ObjectAlreadyExists(f"Object {uid} already present")
diffsync.exceptions.ObjectAlreadyExists: Object arista_Container__<device_name> already present
# pylint: disable=invalid-name
"""Nautobot signal handler functions for aristavc_sync."""
from django.apps import apps as global_apps
from nautobot.extras.choices import CustomFieldTypeChoices
def post_migrate_create_custom_fields(apps=global_apps, **kwargs):
"""Callback function for post_migrate() -- create CustomField records."""
ContentType = apps.get_model("contenttypes", "ContentType")
Device = apps.get_model("dcim", "Device")
CustomField = apps.get_model("extras", "CustomField")
for device_cf_dict in [
{
"name": "arista_eostrain",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "EOS Train",
},
{
"name": "arista_eos",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "EOS Version",
},
{
"name": "arista_ztp",
"type": CustomFieldTypeChoices.TYPE_BOOLEAN,
"label": "ztp",
},
{
"name": "arista_pimbidir",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "pimbidir",
},
{
"name": "arista_pim",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "pim",
},
{
"name": "arista_bgp",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "bgp",
},
{
"name": "arista_mpls",
"type": CustomFieldTypeChoices.TYPE_BOOLEAN,
"label": "mpls",
},
{
"name": "arista_systype",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "systype",
},
{
"name": "arista_mlag",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "mlag",
},
{
"name": "arista_tapagg",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "TAP Aggregation",
},
{
"name": "arista_sflow",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "sFlow",
},
{
"name": "arista_terminattr",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "TerminAttr Version",
},
{
"name": "arista_topology_network_type",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "Topology Network Type",
},
{
"name": "arista_topology_type",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "Topology Type",
},
{
"name": "arista_topology_pod",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "Topology pod",
},
]:
print("-------------------------------------------")
print(device_cf_dict)
field, created = CustomField.objects.get_or_create(
name=device_cf_dict["name"],
defaults=device_cf_dict,
slug=device_cf_dict["name"],
)
print(field, created)
field.content_types.set([ContentType.objects.get_for_model(Device)])
def post_migrate_create_manufacturer(apps=global_apps, **kwargs):
"""Callback function for post_migrate() -- create Arista Manufacturer."""
Manufacturer = apps.get_model("dcim", "Manufacturer")
Manufacturer.objects.get_or_create(name="Arista", slug="arista")
def post_migrate_create_platform(apps=global_apps, **kwargs):
"""Callback function for post_migrate() -- create Arista Platform."""
Platform = apps.get_model("dcim", "Platform")
Manufacturer = apps.get_model("dcim", "Manufacturer")
Platform.objects.get_or_create(
name="arista.eos.eos",
slug="arista_eos",
napalm_driver="eos",
manufacturer=Manufacturer.objects.get(slug="arista"),
)
Switch A - Switch B (pod1)
Switch C - Switch D (pod2)
Switch E - Switch F (pod3)
I want to have two free interfaces of my pod1, so to know which switches is my pod 1 , I search for pod1 in the field arista_topology_rack.
The pod1 information is provide from cloudvision configuration.
Data imported correctly into nautobot from CVP.
import failed with teh following error :-
An exception occurred: KeyError: 'enabledState'
Traceback (most recent call last):
File "/opt/data/nautobot/lib64/python3.8/site-packages/nautobot_ssot/jobs/base.py", line 332, in run
self.sync_data()
File "/opt/data/nautobot/lib64/python3.8/site-packages/nautobot_ssot_aristacv/jobs.py", line 135, in sync_data
cv.load()
File "/opt/data/nautobot/lib64/python3.8/site-packages/nautobot_ssot_aristacv/diffsync/adapters/cloudvision.py", line 126, in load
self.load_devices()
File "/opt/data/nautobot/lib64/python3.8/site-packages/nautobot_ssot_aristacv/diffsync/adapters/cloudvision.py", line 45, in load_devices
self.load_interfaces(device=new_device)
File "/opt/data/nautobot/lib64/python3.8/site-packages/nautobot_ssot_aristacv/diffsync/adapters/cloudvision.py", line 58, in load_interfaces
port_info = cloudvision.get_interfaces_chassis(client=self.conn, dId=device.serial)
File "/opt/data/nautobot/lib64/python3.8/site-packages/nautobot_ssot_aristacv/utils/cloudvision.py", line 512, in get_interfaces_chassis
"enabled": bool(results["enabledState"]["Name"] == "enabled"),
KeyError: 'enabledState'
# pylint: disable=invalid-name
"""Nautobot signal handler functions for aristavc_sync."""
from django.apps import apps as global_apps
from nautobot.extras.choices import CustomFieldTypeChoices
def post_migrate_create_custom_fields(apps=global_apps, **kwargs):
"""Callback function for post_migrate() -- create CustomField records."""
ContentType = apps.get_model("contenttypes", "ContentType")
Device = apps.get_model("dcim", "Device")
CustomField = apps.get_model("extras", "CustomField")
for device_cf_dict in [
{
"name": "arista_eostrain",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "EOS Train",
},
{
"name": "arista_eos",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "EOS Version",
},
{
"name": "arista_ztp",
"type": CustomFieldTypeChoices.TYPE_BOOLEAN,
"label": "ztp",
},
{
"name": "arista_pimbidir",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "pimbidir",
},
{
"name": "arista_pim",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "pim",
},
{
"name": "arista_bgp",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "bgp",
},
{
"name": "arista_mpls",
"type": CustomFieldTypeChoices.TYPE_BOOLEAN,
"label": "mpls",
},
{
"name": "arista_systype",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "systype",
},
{
"name": "arista_mlag",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "mlag",
},
{
"name": "arista_tapagg",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "TAP Aggregation",
},
{
"name": "arista_sflow",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "sFlow",
},
{
"name": "arista_terminattr",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "TerminAttr Version",
},
{
"name": "arista_topology_network_type",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "Topology Network Type",
},
{
"name": "arista_topology_type",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "Topology Type",
},
{
"name": "arista_topology_pod",
"type": CustomFieldTypeChoices.TYPE_TEXT,
"label": "Topology pod",
},
]:
print("-------------------------------------------")
print(device_cf_dict)
field, created = CustomField.objects.get_or_create(
name=device_cf_dict["name"],
defaults=device_cf_dict,
slug=device_cf_dict["name"],
)
print(field, created)
field.content_types.set([ContentType.objects.get_for_model(Device)])
def post_migrate_create_manufacturer(apps=global_apps, **kwargs):
"""Callback function for post_migrate() -- create Arista Manufacturer."""
Manufacturer = apps.get_model("dcim", "Manufacturer")
Manufacturer.objects.get_or_create(name="Arista", slug="arista")
def post_migrate_create_platform(apps=global_apps, **kwargs):
"""Callback function for post_migrate() -- create Arista Platform."""
Platform = apps.get_model("dcim", "Platform")
Manufacturer = apps.get_model("dcim", "Manufacturer")
Platform.objects.get_or_create(
name="arista.eos.eos",
slug="arista_eos",
napalm_driver="eos",
manufacturer=Manufacturer.objects.get(slug="arista"),
)
Switch A - Switch B (pod1)
Switch C - Switch D (pod2)
Switch E - Switch F (pod3)
I want to have two free interfaces of my pod1, so to know which switches is my pod 1 , I search for pod1 in the field arista_topology_rack.
The pod1 information is provide from cloudvision configuration.
I think that the issue is here:
At the moment there are no API endpoints for this plugin. This means that all sync jobs have to be executed within nautobot. This also prevents the user from executing a sync operation outside of nautobot. I think it would be beneficial to add API endpoints to run sync jobs in either direction.
When working with CVP, there can be a workflow to add or remove devices. Once this is complete, a workflow could then be initiated to call the sync from cloudvision to nautbot job. This would then keep nautobot and CVP in sync in a fairly close window. Allowing this option in the form of an endpoint would allow the user to initiate this from whatever workflow currently exists in their environment.
Expect to see the status for an interface to be Active if the Operational status is up.
The operational and link status keys aren't always in the same update notification as the interface ID, MTU, and other attributes but are seen in subsequent notifications. As they're not seen in the same notification they're assumed to be down. This doesn't match what is seen in CloudVision.
When I try to run a sync from the CloudVision data source using CVaaS, I get the following traceback:
An exception occurred: ValidationError: {'all': ["Unknown field name 'arista_model' in custom field data."]}
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/nautobot/extras/jobs.py", line 832, in _run_job
output = job.run(data=data, commit=commit)
File "/usr/local/lib/python3.6/site-packages/nautobot_ssot/jobs/base.py", line 202, in run
self.sync_data()
File "/source/nautobot_ssot_aristacv/jobs.py", line 47, in sync_data
cv.sync_to(nb)
File "/usr/local/lib/python3.6/site-packages/diffsync/init.py", line 496, in sync_to
target.sync_from(self, diff_class=diff_class, flags=flags, callback=callback)
File "/usr/local/lib/python3.6/site-packages/diffsync/init.py", line 476, in sync_from
result = syncer.perform_sync()
File "/usr/local/lib/python3.6/site-packages/diffsync/helpers.py", line 313, in perform_sync
changed |= self.sync_diff_element(element)
File "/usr/local/lib/python3.6/site-packages/diffsync/helpers.py", line 368, in sync_diff_element
changed |= self.sync_diff_element(child, parent_model=model)
File "/usr/local/lib/python3.6/site-packages/diffsync/helpers.py", line 345, in sync_diff_element
changed, modified_model = self.sync_model(model, ids, attrs)
File "/usr/local/lib/python3.6/site-packages/diffsync/helpers.py", line 401, in sync_model
model = model.delete()
File "/source/nautobot_ssot_aristacv/diffsync/fromcv/models.py", line 90, in delete
device.validated_save()
File "/usr/local/lib/python3.6/site-packages/nautobot/core/models/init.py", line 51, in validated_save
self.full_clean()
File "/usr/local/lib/python3.6/site-packages/django/db/models/base.py", line 1231, in full_clean
raise ValidationError(errors)
django.core.exceptions.ValidationError: {'all': ["Unknown field name 'arista_model' in custom field data."]}
A sync of plugin SSOT between Cloudvision and Nautobot in our dev environnement lasts 29 minutes with : {'create': 3404, 'update': 0, 'delete': 0, 'no-change': 0, 'skip': 0} ( for 20 devices)
So the behavior expected is less then 1hours for a normal sync
A sync of plugin SSOT between Cloudvision and Nautobot in our prod environnement lasts more than 19 hours and it still running with : {'create': 39685, 'update': 22, 'delete': 3, 'no-change': 2774, 'skip': 1}
The job remains stuck at this stage : Syncing from CloudvisionAdapter to NautobotAdapter...
And it never finish .
Could you check why this sync is very slow ?
The README still references the old module name and needs to be updated. Since the README is generic, we'll hold this issue until we're ready to document.
This is a reminder to update the README prior to release.
Fix the pyproject.toml to allow newer versions of nautobot-ssot.
I should be able to update nautobot-ssot to the latest.
nautobot-ssot
is pinned at version 1.0.1 by this plugin.
I have changed the cvp default port to 443 via customizing the variables in nautobot config.py. This is my configuration.
PLUGINS_CONFIG = {
"nautobot_ssot": {
"hide_example_jobs": True, # defaults to False if unspecified
},
"nautobot_ssot_aristacv": {
"cvp_host": "10.23.84.200",
"cvp_port": "443",
"cvp_user": "gcastaldo",
"cvp_password": "xxxxxx",
"insecure": "True"
}
}
I expect that the socket will be opened on port 443.
I experienced error on socket opens.
Traceback (most recent call last):
File "/opt/nautobot/.local/lib/python3.8/site-packages/nautobot_ssot/jobs/base.py", line 207, in run
self.sync_data()
File "/opt/nautobot/.local/lib/python3.8/site-packages/nautobot_ssot_aristacv/jobs.py", line 125, in sync_data
cvutils.connect()
File "/opt/nautobot/.local/lib/python3.8/site-packages/nautobot_ssot_aristacv/diffsync/cvutils.py", line 41, in connect
cert = bytes(ssl.get_server_certificate((cvp_host, 8443)), "utf-8")
File "/usr/local/lib/python3.8/ssl.py", line 1483, in get_server_certificate
with create_connection(addr) as sock:
File "/usr/local/lib/python3.8/socket.py", line 808, in create_connection
raise err
File "/usr/local/lib/python3.8/socket.py", line 796, in create_connection
sock.connect(sa)
OSError: [Errno 113] No route to host
but, via tcpdump, i checked that plugin tries to open the socket on port 8443 .
root@VMW-DEVNET-AWX17:~/nautobot-docker-compose# tcpdump -i ens32 host 10.23.84.200
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens32, link-type EN10MB (Ethernet), capture size 262144 bytes
11:50:22.344580 IP VMW-DEVNET-AWX17.maticmind.it.56764 > 10.23.84.200.8443: Flags [S], seq 1288640698, win 64240, options [mss 1460,sackOK,TS val 3279922292 ecr 0,nop,wscale 7], length 0
11:50:22.355716 IP 10.23.84.200 > VMW-DEVNET-AWX17.maticmind.it: ICMP host 10.23.84.200 unreachable - admin prohibited, length 76
When importing devices into Nautobot, allow for a management IP address to be synced as well.
This would be helpful in syncing more information about devices into Nautobot which means Nautobot could be the Source of Truth for more data.
Links from PyPI to home page and repository to bring me to correct page.
You get a 404 Page Not Found error.
I expect a single platform to be created and assigned to all Devices. The single Platform should be for Arista.
A platform for each device type is created.
I'm expecting to get custom fields from migration that include the prefix "arista_" in the slug.
Custom fields are created, but without the prefix arista_.
Got a KeyError 'arista_eos' on sync from cloudvision to nautobot
Got a warning icon next to the slug column items saying : 'Name "all fields" does not match slug'
From a fresh db.
Rather than having a blanket default site and/or device role, provide some method that allows customizing the site and/or device roles applied to devices when imported.
As an end user using the current state of the plugin, changing device roles and device sites must be down manually after importing data in Nautobot. Allowing for customization of device role and sites would streamline the import process.
When syncing data from CVP to Nautobot, plugin fails when "Loading data from Nautobot".
The plugin apparently try to validate all custom fields, not just "it's own" or the ones created/handled by the plugin.
The plugin should only care about it's own fields.
The example happens because the fieldvalidation is done for all custom fields.
An exception occurred: ValidationError: 1 validation error for CustomField value str type expected (type=type_error.str)
Traceback (most recent call last):
File "/opt/nautobot/lib64/python3.8/site-packages/nautobot_ssot/jobs/base.py", line 327, in run
self.sync_data()
File "/opt/nautobot/lib64/python3.8/site-packages/nautobot_ssot_aristacv/jobs.py", line 131, in sync_data
nb.load()
File "/opt/nautobot/lib64/python3.8/site-packages/nautobot_ssot_aristacv/diffsync/fromcv/nautobot.py", line 34, in load
self.cf = CustomField(name=cf_name, value=cf_value, device_name=dev.name)
File "pydantic/main.py", line 331, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for CustomField
value
str type expected (type=type_error.str)__
Create a cloudvision_imported
tag tied to devices imported into Nautobot from CV.
This would allow to see which devices have been imported when you override the default import settings.
It'd be nice to have the Software Version of a Device be noted in the Device Lifecycle plugin if it's also imported.
Instead of having EOS Version noted as a Custom Field it'd be much better to have those versions created in the DLC plugin and a Relationship created. This enables far more functionality with this information, such as defining Validated Software or CVEs.
The interfaces in switchport trunk mode are recognized and configured in mode "TAGGED"
The interfaces in switchport trunk mode aren't recognized and configured in mode "ACCESS"
Hi, I think that it isn't a bug of the plugin because the CVaaS don't report the correct mode of the switchport interfaces.
I have a propose, if the CVaaS output is wrong is better to don't configure it in Nautobot.
As a Nautobot user, I want to sync the tags assigned to interfaces in Nautobot to CloudVision as interface tags.
The deletion of devices when syncing from CloudVision to Nautobot should be configurable by the end user and default to off to prevent inadvertently deleting non-CloudVision managed devices.
Wouldn't it be better to apply the arista as a filter, that way you don't have to load all the devices?
We received a news from arista about the collection : arista.tag.v1
It will be obsolete soon.
Could you update this part of code : https://github.com/nautobot/nautobot-plugin-ssot-arista-cloudvision/blob/v1.5.0/nautobot_ssot_aristacv/diffsync/adapters/cloudvision.py to use arista.tag.v2 ?
https://aristanetworks.github.io/cloudvision-apis/models/tag.v2/
Thanks
As Nautobot supports documenting console and power ports it would be useful to pull this information from CloudVision if possible.
Being able to track connections for console and power is useful for automation and inventory purposes.
When upgrading the Docker image of Nautobot from 1.4.8 to 1.5.7, the post_migrate_create_custom_fields
command should passed successfully. The command is run automatically by the container.
Instead, an exception occurred complaining about a duplicate key.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
psycopg2.errors.UniqueViolation: duplicate key value violates unique constraint "extras_customfield_name_key"
DETAIL: Key (name)=(arista_eostrain) already exists.
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/local/bin/nautobot-server", line 8, in <module>
sys.exit(main())
File "/usr/local/lib/python3.9/site-packages/nautobot/core/cli.py", line 54, in main
run_app(
File "/usr/local/lib/python3.9/site-packages/nautobot/core/runner/runner.py", line 263, in run_app
management.execute_from_command_line([runner_name, command] + command_args)
File "/usr/local/lib/python3.9/site-packages/django/core/management/__init__.py", line 419, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python3.9/site-packages/django/core/management/__init__.py", line 413, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python3.9/site-packages/django/core/management/base.py", line 354, in run_from_argv
self.execute(*args, **cmd_options)
File "/usr/local/lib/python3.9/site-packages/django/core/management/base.py", line 398, in execute
output = self.handle(*args, **options)
File "/usr/local/lib/python3.9/site-packages/nautobot/core/management/commands/post_upgrade.py", line 78, in handle
call_command(
File "/usr/local/lib/python3.9/site-packages/django/core/management/__init__.py", line 181, in call_command
return command.execute(*args, **defaults)
File "/usr/local/lib/python3.9/site-packages/django/core/management/base.py", line 398, in execute
output = self.handle(*args, **options)
File "/usr/local/lib/python3.9/site-packages/django/core/management/base.py", line 89, in wrapped
res = handle_func(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/django/core/management/commands/migrate.py", line 268, in handle
emit_post_migrate_signal(
File "/usr/local/lib/python3.9/site-packages/django/core/management/sql.py", line 42, in emit_post_migrate_signal
models.signals.post_migrate.send(
File "/usr/local/lib/python3.9/site-packages/django/dispatch/dispatcher.py", line 180, in send
return [
File "/usr/local/lib/python3.9/site-packages/django/dispatch/dispatcher.py", line 181, in <listcomp>
(receiver, receiver(signal=self, sender=sender, **named))
File "/usr/local/lib/python3.9/site-packages/nautobot_ssot_aristacv/signals.py", line 83, in post_migrate_create_custom_fields
field, _ = CustomField.objects.get_or_create(
File "/usr/local/lib/python3.9/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/django/db/models/query.py", line 588, in get_or_create
return self.create(**params), True
File "/usr/local/lib/python3.9/site-packages/django/db/models/query.py", line 453, in create
Syncing from cloudvision as a service to nautobot I expect the databases to be aligned.
I receive the following traceback:
Traceback (most recent call last):
File "/opt/nautobot/.local/lib/python3.8/site-packages/nautobot_ssot/jobs/base.py", line 332, in run
self.sync_data()
File "/opt/nautobot/.local/lib/python3.8/site-packages/nautobot_ssot/jobs/base.py", line 137, in sync_data
self.load_source_adapter()
File "/opt/nautobot/.local/lib/python3.8/site-packages/nautobot_ssot_aristacv/jobs.py", line 117, in load_source_adapter
self.source_adapter.load()
File "/opt/nautobot/.local/lib/python3.8/site-packages/nautobot_ssot_aristacv/diffsync/adapters/cloudvision.py", line 190, in load
self.load_devices()
File "/opt/nautobot/.local/lib/python3.8/site-packages/nautobot_ssot_aristacv/diffsync/adapters/cloudvision.py", line 53, in load_devices
self.load_interfaces(device=new_device)
File "/opt/nautobot/.local/lib/python3.8/site-packages/nautobot_ssot_aristacv/diffsync/adapters/cloudvision.py", line 67, in load_interfaces
port_info = cloudvision.get_interfaces_chassis(client=self.conn, dId=device.serial)
File "/opt/nautobot/.local/lib/python3.8/site-packages/nautobot_ssot_aristacv/utils/cloudvision.py", line 516, in get_interfaces_chassis
"mtu": results["mtu"],
KeyError: 'mtu'
Currently this plugin only imports devices that have an Active streaming status. I'd like the ability to import all devices connected to a CVP instance regardless of the current status. We can have it as a plugin setting whether only active devices are imported or not.
Perhaps I have a lab instance that has a large number of devices connected to it that I wish to import but I don't want to bring them all online simply to import them in. Could also be useful for importing devices that are currently having issues with streaming that you wish to import anyways.
Python version: 3.10 Nautobot version: 1.5.7 nautobot_ssot_aristacv 1.4.0 ssot : 1.2.0
Steps to Reproduce
1.Plugins, dashboard, single source of truth
2.Cloudvision --> Nautobot
3. Debug and Dry run, Run job now
Pull data from CVP into Nautobot, or at least show me what its going to pull in.
After several logs entries showing interface details for each device-
Loading data from Nautobot
Then a failure - An exception occurred: IndexError: list index out of range
Traceback (most recent call last):
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_ssot/jobs/base.py", line 332, in run
self.sync_data()
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_ssot/jobs/base.py", line 146, in sync_data
self.load_target_adapter()
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_ssot_aristacv/jobs.py", line 123, in load_target_adapter
self.target_adapter.load()
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_ssot_aristacv/diffsync/adapters/nautobot.py", line 41, in load
version=nautobot.get_device_version(dev),
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_ssot_aristacv/utils/nautobot.py", line 107, in get_device_version
version = relations["destination"][software_relation][0].source.version
File "/opt/nautobot/lib/python3.10/site-packages/django/db/models/query.py", line 318, in getitem
return qs._result_cache[0]
IndexError: list index out of range
Sync completed
Getting IndexError
Dry run is successful
Sync info from CVP to Nautobot
Failing with below trace
Traceback (most recent call last):
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_ssot/jobs/base.py", line 332, in run
self.sync_data()
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_ssot/jobs/base.py", line 137, in sync_data
self.load_source_adapter()
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_ssot_aristacv/jobs.py", line 117, in load_source_adapter
self.source_adapter.load()
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_ssot_aristacv/diffsync/adapters/cloudvision.py", line 190, in load
self.load_devices()
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_ssot_aristacv/diffsync/adapters/cloudvision.py", line 53, in load_devices
self.load_interfaces(device=new_device)
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_ssot_aristacv/diffsync/adapters/cloudvision.py", line 62, in load_interfaces
chassis_type = cloudvision.get_device_type(client=self.conn, dId=device.serial)
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_ssot_aristacv/utils/cloudvision.py", line 472, in get_device_type
if query["fixedSystem"] is None:
KeyError: 'fixedSystem'
Able to connect to on-prem instance using a token.
Using a token is only supported with the CVaaS Cloud instance.
Expect to be able to use the method to get a device's ID by passing the hostname.
Running the method throws a TypeError:
In [43]: req = services.DeviceStreamRequest(patrial_eq_filter=[models.Device(hostname="rtr1")])
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In [43], line 1
----> 1 req = services.DeviceStreamRequest(patrial_eq_filter=[models.Device(hostname="rtr1")])
TypeError: Parameter to MergeFrom() must be instance of same class: expected google.protobuf.StringValue got str.
In [44]: cvp.get_device_id(device_name="rtr1")
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In [44], line 1
----> 1 cvp.get_device_id(device_name="rtr1")
File /usr/local/lib/python3.9/site-packages/nautobot_ssot_aristacv/utils/cloudvision.py:119, in CloudvisionApi.get_device_id(self, device_name)
116 """Get device_id for device_name from CloudVision inventory."""
117 device_stub = services.DeviceServiceStub(self.comm_channel)
118 req = services.DeviceStreamRequest(
--> 119 partial_eq_filter=[models.Device(hostname=device_name, streaming_status=models.STREAMING_STATUS_ACTIVE)]
120 )
121 resp = device_stub.GetOne(req)
122 return resp.value.key.device_id.value
TypeError: Parameter to MergeFrom() must be instance of same class: expected google.protobuf.StringValue got str.
It'd be helpful to have representation of the CloudVision instance and associated data like software version in Nautobot. This could also include the Relationship between that instance and the connected Devices.
In order to know which instance controls a particular Device it'd be helpful to document that Relationship and also for tracking versions in use.
Add the ability to customize the CVAAS url.
Not all instances of CVAAS live at www.arista.io. Currently, that URL is hardcoded.
Sync device interfaces from CloudVision to Nautobot when syncing devices.
Syncing of interfaces from CloudVision to Nautobot would allow Nautobot to be the SSoT of more info.
Sync from cloudvision to Nautobot it looks like the configuration file dosen't match my the boolean True statment in the configuration file of nautbot
Parameter | Value |
---|---|
Server type | On prem |
CloudVision host | X |
Username | nautobot |
Insecure | True |
Delete devices on sync | False |
New device default site | cloudvision_imported |
New device default role | network |
New device default role color | ff0000 |
New device default status | cloudvision_imported |
New device default status color | ff0000 |
Apply import tag | True |
2021-10-01T10:32:26.788554+00:00 | Warning | Devices not present in Cloudvision but present in Nautobot will not be deleted from Nautobot. | |
---|---|---|---|
2021-10-01T10:32:26.788973+00:00 | Default | Connecting to CloudVision | |
2021-10-01T10:32:27.573671+00:00 | Failure | An exception occurred: KeyError: 'sessionId' Traceback (most recent call last): File "/opt/nautobot/lib64/python3.6/site-packages/nautobot_ssot/jobs/base.py", line 207, in run self.sync_data() File "/opt/nautobot/lib64/python3.6/site-packages/nautobot_ssot_aristacv/jobs.py", line 122, in sync_data cvutils.connect() File "/opt/nautobot/lib64/python3.6/site-packages/nautobot_ssot_aristacv/diffsync/cvutils.py", line 40, in connect call_creds = grpc.access_token_call_credentials(response.json()["sessionId"]) KeyError: 'sessionId' |
PLUGINS = ["nautobot_ssot", "nautobot_ssot_aristacv"]
PLUGINS_CONFIG = {
# "nautobot_ssot" : {
# ADD YOUR SETTINGS HERE
# }
"nautobot_ssot_aristacv": {
# "cvaas_token": "",
"cvp_host": "X",
"cvp_user": "nautobot",
"cvp_password": "X",
"insecure": "True",
# "from_cloudvision_default_site": "",
# "from_cloudvision_default_device_role": "",
# "from_cloudvision_default_device_role_color": "",
# "from_cloudvision_default_device_status": "",
# "from_cloudvision_default_device_status_color": "",
# "delete_devices_on_sync": "",
"apply_import_tag": "True"
}
}
All of the values for the Configuration section for the CloudVisionDataSource and Target should should be shown.
The values for Verify
and delete devices on sync
are both blank. I believe this is due to them being booleans and we need to stringify the values for display.
Nautobot starts without issue and the plugin is available for use.
Stacktrace is caused by a missing module:
Traceback (most recent call last):
File "/usr/local/bin/nautobot-server", line 8, in <module>
sys.exit(main())
File "/usr/local/lib/python3.9/site-packages/nautobot/core/cli.py", line 54, in main
run_app(
File "/usr/local/lib/python3.9/site-packages/nautobot/core/runner/runner.py", line 266, in run_app
management.execute_from_command_line([runner_name, command] + command_args)
File "/usr/local/lib/python3.9/site-packages/django/core/management/__init__.py", line 419, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python3.9/site-packages/django/core/management/__init__.py", line 395, in execute
django.setup()
File "/usr/local/lib/python3.9/site-packages/django/__init__.py", line 24, in setup
apps.populate(settings.INSTALLED_APPS)
File "/usr/local/lib/python3.9/site-packages/django/apps/registry.py", line 122, in populate
app_config.ready()
File "/usr/local/lib/python3.9/site-packages/nautobot_ssot_aristacv/__init__.py", line 34, in ready
super().ready()
File "/usr/local/lib/python3.9/site-packages/nautobot/extras/plugins/__init__.py", line 143, in ready
jobs = import_object(f"{self.__module__}.{self.jobs}")
File "/usr/local/lib/python3.9/site-packages/nautobot/extras/plugins/utils.py", line 45, in import_object
spec.loader.exec_module(module)
File "<frozen importlib._bootstrap_external>", line 850, in exec_module
File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
File "/usr/local/lib/python3.9/site-packages/nautobot_ssot_aristacv/jobs.py", line 15, in <module>
from nautobot_ssot_aristacv.diffsync.tocv.cloudvision import CloudVision
File "/usr/local/lib/python3.9/site-packages/nautobot_ssot_aristacv/diffsync/tocv/cloudvision.py", line 4, in <module>
import nautobot_ssot_aristacv.diffsync.cvutils as cvutils
File "/usr/local/lib/python3.9/site-packages/nautobot_ssot_aristacv/diffsync/cvutils.py", line 6, in <module>
import arista.inventory.v1 as inv
File "/usr/local/lib/python3.9/site-packages/arista/inventory/v1/__init__.py", line 3, in <module>
from arista.inventory.v1 import inventory_pb2 as models
File "/usr/local/lib/python3.9/site-packages/arista/inventory/v1/inventory_pb2.py", line 17, in <module>
from fmp import extensions_pb2 as fmp_dot_extensions__pb2
File "/usr/local/lib/python3.9/site-packages/fmp/__init__.py", line 3, in <module>
import wrappers_pb2 as wrappers
ModuleNotFoundError: No module named 'wrappers_pb2'
Hello,
the documentation (README) mentions delete_devices_on_sync_cv_source
while the actual variable seems to be delete_devices_on_sync
Also, the setting apply_import_tag
is not included in the example of PLUGINS_CONFIG
(https://github.com/nautobot/nautobot-plugin-ssot-arista-cloudvision#installation).
Best,
Upgrade from 1.4.0 to 1.5.0 without issues.
Getting an error after upgrading to latest and running nautobot-server post_upgrade
Traceback (most recent call last):
File "/opt/nautobot/lib/python3.10/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
psycopg2.errors.UniqueViolation: duplicate key value violates unique constraint "extras_customfield_name_key"
DETAIL: Key (name)=(arista_eostrain) already exists.
I was able to workaround the error by deleting all CustomFields from the Nautobot instance and try again. After that the error is gone and the upgrades succeeds.
Another issue that came with the upgrade to 1.5.0 is that enabling the create controller
feature causes some error on the imported CloudVision device. After the initial sync, the CloudVision controller is created with empty CustomFields values. After trying subsequent syncs, there is an error:
Traceback (most recent call last):
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_ssot/jobs/base.py", line 332, in run
self.sync_data()
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_ssot/jobs/base.py", line 146, in sync_data
self.load_target_adapter()
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_ssot_aristacv/jobs.py", line 115, in load_target_adapter
self.target_adapter.load()
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_ssot_aristacv/diffsync/adapters/nautobot.py", line 140, in load
self.load_devices()
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_ssot_aristacv/diffsync/adapters/nautobot.py", line 45, in load_devices
version=nautobot.get_device_version(dev),
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_ssot_aristacv/utils/nautobot.py", line 94, in get_device_version
version = device.custom_field_data["arista_eos"]
KeyError: 'arista_eos'
After checking further, there is no arista_eos
value for the CloudVision device:
>>> for dev in Device.objects.all():
... print(f"Arista EOS CF for {dev.name} is {dev.custom_field_data['arista_eos'] if dev.custom_field_data.get('arista_eos') else 'MISSING' }")
...
Arista EOS CF for CloudVision is MISSING
Arista EOS CF for nsx01-borderleaf-01 is 4.28.3M
Arista EOS CF for nsx01-leaf-01 is 4.28.5M
Arista EOS CF for nsx01-leaf-02 is 4.28.5M
After manually adding a value to the CloudVision arista_eos
field, the problem is solved and subsequent syncs succeeds.
https://networktocode.slack.com/archives/C01NWPK6WHL/p1676042235148109
Is there a possibility to increase amount of roles, as far as I saw in Custom fields, there are supported only “Leafs” or “spines”, we have much more in Arista:
leafs, subleafs, spines, super-spines, borders, route_servers. Is there a possibility to have it also in plugin.
What is more, the role could be associated to Device Role in Nautobot automatically
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.