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

10520 remove Napalm code references #11768

Merged
merged 51 commits into from
Feb 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
3a9e431
Closes #10923: Remove unused NetBoxModelCSVForm class
jeremystretch Jan 9, 2023
4d221f4
Closes #10604: Remove unused extra_tabs block from object.html generi…
jeremystretch Jan 9, 2023
d997fe9
Merge branch 'develop' into feature
jeremystretch Jan 13, 2023
1890286
Closes #11489: Refactor & combine core middleware
jeremystretch Jan 13, 2023
4faa3b4
Remove old feature version notices
jeremystretch Jan 13, 2023
ff4eb41
Closes #11254: Introduce the X-Request-ID HTTP header to annotate the…
jeremystretch Jan 13, 2023
943dca7
Closes #8184: Enable HTMX for embedded tables (#11518)
jeremystretch Jan 16, 2023
dceffca
Merge branch 'develop' into feature
jeremystretch Jan 20, 2023
024df81
Add the `enabled` filed to InterfaceTemplate
Jan 9, 2023
bab1ce7
Changelog for #11440
jeremystretch Jan 24, 2023
47b5704
Merge branch 'develop' into feature
jeremystretch Jan 25, 2023
ff0e413
Clean up related objects for sites, tenants
jeremystretch Jan 25, 2023
14d9332
Standardize related model display for nested models
jeremystretch Jan 25, 2023
449522a
Standardize related model display for organizational models
jeremystretch Jan 25, 2023
cfa60e4
Standardize linking to related objects in tables
jeremystretch Jan 25, 2023
2061906
Standard related object links across all models
jeremystretch Jan 25, 2023
350b8c2
Use embedded table to show assigned services under object view
jeremystretch Jan 26, 2023
dacc699
Move rack reservations panel to separate tab
jeremystretch Jan 26, 2023
8745f8e
Use embedded tables for importing/export VRFs & L2VPNs under route ta…
jeremystretch Jan 26, 2023
0ad163e
Merge branch 'develop' into feature
jeremystretch Jan 26, 2023
9ff14e4
Closes #11584: Add a list view for contact assignments
jeremystretch Jan 26, 2023
7d32b88
#11517: Standardize display of contact assignments
jeremystretch Jan 26, 2023
36e9002
Closes #11611: Refactor API viewset classes and introduce NetBoxReadO…
jeremystretch Jan 27, 2023
c8779a8
Closes #11625: Add HTMX support to ObjectEditView
jeremystretch Jan 31, 2023
49fd6c5
10520 remove all Napalm code references
arthanson Jan 31, 2023
4d87ce5
Closes #11558: Add support for remote data sources (#11646)
jeremystretch Feb 2, 2023
169869b
#11558: Fix URL display under data source view
jeremystretch Feb 2, 2023
a461123
Merge branch 'develop' into feature
jeremystretch Feb 2, 2023
1f11cd0
Fixes #11659: Include all relevant DataFile attributes during bulk up…
jeremystretch Feb 3, 2023
2c35c53
Closes #9073: Remote data support for config contexts (#11692)
jeremystretch Feb 7, 2023
9862888
Closes #11693: Enable remote data synchronization for export templates
jeremystretch Feb 8, 2023
653edc3
Merge migrations
jeremystretch Feb 9, 2023
4c40206
Changelog for #11693
jeremystretch Feb 9, 2023
a9e58bc
Fixes #11694 - Remove obsolete SmallTextarea widget
kkthxbye-code Feb 10, 2023
c99ecc2
Closes #11737: ChangeLoggedModel should inherit WebhooksMixin
jeremystretch Feb 11, 2023
40ad9bf
Check for change records only if objects being deleted support change…
jeremystretch Feb 11, 2023
fa6cad1
DataFile should not inherit from ChangeLoggingMixin
jeremystretch Feb 11, 2023
944bda5
Fixes #9653 - Add default_platform to DeviceType
kkthxbye-code Feb 10, 2023
959a2ab
Fix issues with the ContactAssignmentListView
kkthxbye-code Feb 15, 2023
d6c41fb
Closes #11765: Remove StaticSelect & StaticSelectMultiple (#11767)
jeremystretch Feb 16, 2023
5982da4
10520 merge feature
arthanson Feb 16, 2023
d885e15
10520 remove lldp
arthanson Feb 16, 2023
48f65fa
10520 remove config, status - rebuild js
arthanson Feb 16, 2023
30c945a
#11765: Avoid setting netbox-static-select on SelectMultiple with size
jeremystretch Feb 16, 2023
e442bb9
Closes #11559: Implement config template rendering (#11769)
jeremystretch Feb 17, 2023
422d5db
Add index for (source, path) to DataFile
jeremystretch Feb 17, 2023
5dcd16b
10520 fix merge conflicts
arthanson Feb 17, 2023
b2f7f05
10520 re-add config parameters
arthanson Feb 17, 2023
c279cfc
10520 re-add serializer
arthanson Feb 17, 2023
7e68cb9
10520 update docs
arthanson Feb 18, 2023
df27528
Merge branch 'feature' into 10520-remove-napalm
jeremystretch Feb 24, 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
2 changes: 2 additions & 0 deletions docs/configuration/napalm.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# NAPALM Parameters

!!! **Note:** As of NetBox v3.5, NAPALM integration has been moved to a plugin and these configuration parameters are now deprecated.

## NAPALM_USERNAME

## NAPALM_PASSWORD
Expand Down
2 changes: 2 additions & 0 deletions docs/features/api-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ To learn more about this feature, check out the [webhooks documentation](../inte

To learn more about this feature, check out the [NAPALM documentation](../integrations/napalm.md).

As of NetBox v3.5, NAPALM integration has been moved to a plugin. Please see the [netbox_napalm_plugin](https://github.com/netbox-community/netbox-napalm) for installation instructions.

## Prometheus Metrics

NetBox includes a special `/metrics` view which exposes metrics for a [Prometheus](https://prometheus.io/) scraper, powered by the open source [django-prometheus](https://github.com/korfuri/django-prometheus) library. To learn more about this feature, check out the [Prometheus metrics documentation](../integrations/prometheus-metrics.md).
8 changes: 0 additions & 8 deletions docs/installation/3-netbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,14 +199,6 @@ When you have finished modifying the configuration, remember to save the file.

All Python packages required by NetBox are listed in `requirements.txt` and will be installed automatically. NetBox also supports some optional packages. If desired, these packages must be listed in `local_requirements.txt` within the NetBox root directory.

### NAPALM

Integration with the [NAPALM automation](../integrations/napalm.md) library allows NetBox to fetch live data from devices and return it to a requester via its REST API. The `NAPALM_USERNAME` and `NAPALM_PASSWORD` configuration parameters define the credentials to be used when connecting to a device.

```no-highlight
sudo sh -c "echo 'napalm' >> /opt/netbox/local_requirements.txt"
```

### Remote File Storage

By default, NetBox will use the local filesystem to store uploaded files. To use a remote filesystem, install the [`django-storages`](https://django-storages.readthedocs.io/en/stable/) library and configure your [desired storage backend](../configuration/system.md#storage_backend) in `configuration.py`.
Expand Down
73 changes: 1 addition & 72 deletions docs/integrations/napalm.md
Original file line number Diff line number Diff line change
@@ -1,74 +1,3 @@
# NAPALM

NetBox supports integration with the [NAPALM automation](https://github.com/napalm-automation/napalm) library. NAPALM allows NetBox to serve a proxy for operational data, fetching live data from network devices and returning it to a requester via its REST API. Note that NetBox does not store any NAPALM data locally.

The NetBox UI will display tabs for status, LLDP neighbors, and configuration under the device view if the following conditions are met:

* Device status is "Active"
* A primary IP has been assigned to the device
* A platform with a NAPALM driver has been assigned
* The authenticated user has the `dcim.napalm_read_device` permission

!!! note
To enable this integration, the NAPALM library must be installed. See [installation steps](../../installation/3-netbox/#napalm) for more information.

Below is an example REST API request and response:

```no-highlight
GET /api/dcim/devices/1/napalm/?method=get_environment

{
"get_environment": {
...
}
}
```

!!! note
To make NAPALM requests via the NetBox REST API, a NetBox user must have assigned a permission granting the `napalm_read` action for the device object type.

## Authentication

By default, the [`NAPALM_USERNAME`](../configuration/napalm.md#napalm_username) and [`NAPALM_PASSWORD`](../configuration/napalm.md#napalm_password) configuration parameters are used for NAPALM authentication. They can be overridden for an individual API call by specifying the `X-NAPALM-Username` and `X-NAPALM-Password` headers.

```
$ curl "http://localhost/api/dcim/devices/1/napalm/?method=get_environment" \
-H "Authorization: Token $TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json; indent=4" \
-H "X-NAPALM-Username: foo" \
-H "X-NAPALM-Password: bar"
```

## Method Support

The list of supported NAPALM methods depends on the [NAPALM driver](https://napalm.readthedocs.io/en/latest/support/index.html#general-support-matrix) configured for the platform of a device. Because there is no granular mechanism in place for limiting potentially disruptive requests, NetBox supports only read-only [get](https://napalm.readthedocs.io/en/latest/support/index.html#getters-support-matrix) methods.

## Multiple Methods

It is possible to request the output of multiple NAPALM methods in a single API request by passing multiple `method` parameters. For example:

```no-highlight
GET /api/dcim/devices/1/napalm/?method=get_ntp_servers&method=get_ntp_peers

{
"get_ntp_servers": {
...
},
"get_ntp_peers": {
...
}
}
```

## Optional Arguments

The behavior of NAPALM drivers can be adjusted according to the [optional arguments](https://napalm.readthedocs.io/en/latest/support/index.html#optional-arguments). NetBox exposes those arguments using headers prefixed with `X-NAPALM-`. For example, the SSH port is changed to 2222 in this API call:

```
$ curl "http://localhost/api/dcim/devices/1/napalm/?method=get_environment" \
-H "Authorization: Token $TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json; indent=4" \
-H "X-NAPALM-port: 2222"
```
As of NetBox v3.5, NAPALM integration has been moved to a plugin. Please see the [netbox_napalm_plugin](https://github.com/netbox-community/netbox-napalm) for installation instructions. **Note:** All previously entered NAPALM configuration data will be saved and automatically imported by the new plugin.
1 change: 0 additions & 1 deletion netbox/core/forms/model_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ def fieldsets(self):

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

# Determine the selected backend type
backend_type = get_field_value(self, 'type')
backend = registry['data_backends'].get(backend_type)
Expand Down
118 changes: 0 additions & 118 deletions netbox/dcim/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -419,124 +419,6 @@ def get_serializer_class(self):

return serializers.DeviceWithConfigContextSerializer

@swagger_auto_schema(
manual_parameters=[
Parameter(
name='method',
in_='query',
required=True,
type=openapi.TYPE_STRING
)
],
responses={'200': serializers.DeviceNAPALMSerializer}
)
@action(detail=True, url_path='napalm')
def napalm(self, request, pk):
"""
Execute a NAPALM method on a Device
"""
device = get_object_or_404(self.queryset, pk=pk)
if not device.primary_ip:
raise ServiceUnavailable("This device does not have a primary IP address configured.")
if device.platform is None:
raise ServiceUnavailable("No platform is configured for this device.")
if not device.platform.napalm_driver:
raise ServiceUnavailable(f"No NAPALM driver is configured for this device's platform: {device.platform}.")

# Check for primary IP address from NetBox object
if device.primary_ip:
host = str(device.primary_ip.address.ip)
else:
# Raise exception for no IP address and no Name if device.name does not exist
if not device.name:
raise ServiceUnavailable(
"This device does not have a primary IP address or device name to lookup configured."
)
try:
# Attempt to complete a DNS name resolution if no primary_ip is set
host = socket.gethostbyname(device.name)
except socket.gaierror:
# Name lookup failure
raise ServiceUnavailable(
f"Name lookup failure, unable to resolve IP address for {device.name}. Please set Primary IP or "
f"setup name resolution.")

# Check that NAPALM is installed
try:
import napalm
from napalm.base.exceptions import ModuleImportError
except ModuleNotFoundError as e:
if getattr(e, 'name') == 'napalm':
raise ServiceUnavailable("NAPALM is not installed. Please see the documentation for instructions.")
raise e

# Validate the configured driver
try:
driver = napalm.get_network_driver(device.platform.napalm_driver)
except ModuleImportError:
raise ServiceUnavailable("NAPALM driver for platform {} not found: {}.".format(
device.platform, device.platform.napalm_driver
))

# Verify user permission
if not request.user.has_perm('dcim.napalm_read_device'):
return HttpResponseForbidden()

napalm_methods = request.GET.getlist('method')
response = {m: None for m in napalm_methods}

config = get_config()
username = config.NAPALM_USERNAME
password = config.NAPALM_PASSWORD
timeout = config.NAPALM_TIMEOUT
optional_args = config.NAPALM_ARGS.copy()
if device.platform.napalm_args is not None:
optional_args.update(device.platform.napalm_args)

# Update NAPALM parameters according to the request headers
for header in request.headers:
if header[:9].lower() != 'x-napalm-':
continue

key = header[9:]
if key.lower() == 'username':
username = request.headers[header]
elif key.lower() == 'password':
password = request.headers[header]
elif key:
optional_args[key.lower()] = request.headers[header]

# Connect to the device
d = driver(
hostname=host,
username=username,
password=password,
timeout=timeout,
optional_args=optional_args
)
try:
d.open()
except Exception as e:
raise ServiceUnavailable("Error connecting to the device at {}: {}".format(host, e))

# Validate and execute each specified NAPALM method
for method in napalm_methods:
if not hasattr(driver, method):
response[method] = {'error': 'Unknown NAPALM method'}
continue
if not method.startswith('get_'):
response[method] = {'error': 'Only get_* NAPALM methods are supported'}
continue
try:
response[method] = getattr(d, method)()
except NotImplementedError:
response[method] = {'error': 'Method {} not implemented for NAPALM driver {}'.format(method, driver)}
except Exception as e:
response[method] = {'error': 'Method {} failed: {}'.format(method, e)}
d.close()

return Response(response)


class VirtualDeviceContextViewSet(NetBoxModelViewSet):
queryset = VirtualDeviceContext.objects.prefetch_related(
Expand Down
2 changes: 1 addition & 1 deletion netbox/dcim/filtersets.py
Original file line number Diff line number Diff line change
Expand Up @@ -806,7 +806,7 @@ class PlatformFilterSet(OrganizationalModelFilterSet):

class Meta:
model = Platform
fields = ['id', 'name', 'slug', 'napalm_driver', 'description']
fields = ['id', 'name', 'slug', 'description']


class DeviceFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet, LocalConfigContextFilterSet):
Expand Down
8 changes: 2 additions & 6 deletions netbox/dcim/forms/bulk_edit.py
Original file line number Diff line number Diff line change
Expand Up @@ -476,10 +476,6 @@ class PlatformBulkEditForm(NetBoxModelBulkEditForm):
queryset=Manufacturer.objects.all(),
required=False
)
napalm_driver = forms.CharField(
max_length=50,
required=False
)
config_template = DynamicModelChoiceField(
queryset=ConfigTemplate.objects.all(),
required=False
Expand All @@ -491,9 +487,9 @@ class PlatformBulkEditForm(NetBoxModelBulkEditForm):

model = Platform
fieldsets = (
(None, ('manufacturer', 'config_template', 'napalm_driver', 'description')),
(None, ('manufacturer', 'config_template', 'description')),
)
nullable_fields = ('manufacturer', 'config_template', 'napalm_driver', 'description')
nullable_fields = ('manufacturer', 'config_template', 'description')


class DeviceBulkEditForm(NetBoxModelBulkEditForm):
Expand Down
2 changes: 1 addition & 1 deletion netbox/dcim/forms/bulk_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ class PlatformImportForm(NetBoxModelImportForm):
class Meta:
model = Platform
fields = (
'name', 'slug', 'manufacturer', 'config_template', 'napalm_driver', 'napalm_args', 'description', 'tags',
'name', 'slug', 'manufacturer', 'config_template', 'description', 'tags',
)


Expand Down
8 changes: 2 additions & 6 deletions netbox/dcim/forms/model_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -451,19 +451,15 @@ class PlatformForm(NetBoxModelForm):

fieldsets = (
('Platform', (
'name', 'slug', 'manufacturer', 'config_template', 'napalm_driver', 'napalm_args', 'description', 'tags',

'name', 'slug', 'manufacturer', 'config_template', 'description', 'tags',
)),
)

class Meta:
model = Platform
fields = [
'name', 'slug', 'manufacturer', 'config_template', 'napalm_driver', 'napalm_args', 'description', 'tags',
'name', 'slug', 'manufacturer', 'config_template', 'description', 'tags',
]
widgets = {
'napalm_args': forms.Textarea(),
}


class DeviceForm(TenancyForm, NetBoxModelForm):
Expand Down
1 change: 0 additions & 1 deletion netbox/dcim/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,6 @@ class PlatformIndex(SearchIndex):
fields = (
('name', 100),
('slug', 110),
('napalm_driver', 300),
('description', 500),
)

Expand Down
6 changes: 3 additions & 3 deletions netbox/dcim/tables/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,11 @@ class PlatformTable(NetBoxTable):
class Meta(NetBoxTable.Meta):
model = models.Platform
fields = (
'pk', 'id', 'name', 'manufacturer', 'device_count', 'vm_count', 'slug', 'config_template', 'napalm_driver',
'napalm_args', 'description', 'tags', 'actions', 'created', 'last_updated',
'pk', 'id', 'name', 'manufacturer', 'device_count', 'vm_count', 'slug', 'config_template', 'description',
'tags', 'actions', 'created', 'last_updated',
)
default_columns = (
'pk', 'name', 'manufacturer', 'device_count', 'vm_count', 'napalm_driver', 'description',
'pk', 'name', 'manufacturer', 'device_count', 'vm_count', 'description',
)


Expand Down
10 changes: 3 additions & 7 deletions netbox/dcim/tests/test_filtersets.py
Original file line number Diff line number Diff line change
Expand Up @@ -1469,9 +1469,9 @@ def setUpTestData(cls):
Manufacturer.objects.bulk_create(manufacturers)

platforms = (
Platform(name='Platform 1', slug='platform-1', manufacturer=manufacturers[0], napalm_driver='driver-1', description='A'),
Platform(name='Platform 2', slug='platform-2', manufacturer=manufacturers[1], napalm_driver='driver-2', description='B'),
Platform(name='Platform 3', slug='platform-3', manufacturer=manufacturers[2], napalm_driver='driver-3', description='C'),
Platform(name='Platform 1', slug='platform-1', manufacturer=manufacturers[0], description='A'),
Platform(name='Platform 2', slug='platform-2', manufacturer=manufacturers[1], description='B'),
Platform(name='Platform 3', slug='platform-3', manufacturer=manufacturers[2], description='C'),
)
Platform.objects.bulk_create(platforms)

Expand All @@ -1487,10 +1487,6 @@ def test_description(self):
params = {'description': ['A', 'B']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)

def test_napalm_driver(self):
params = {'napalm_driver': ['driver-1', 'driver-2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)

def test_manufacturer(self):
manufacturers = Manufacturer.objects.all()[:2]
params = {'manufacturer_id': [manufacturers[0].pk, manufacturers[1].pk]}
Expand Down
3 changes: 0 additions & 3 deletions netbox/dcim/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1591,8 +1591,6 @@ def setUpTestData(cls):
'name': 'Platform X',
'slug': 'platform-x',
'manufacturer': manufacturer.pk,
'napalm_driver': 'junos',
'napalm_args': None,
'description': 'A new platform',
'tags': [t.pk for t in tags],
}
Expand All @@ -1612,7 +1610,6 @@ def setUpTestData(cls):
)

cls.bulk_edit_data = {
'napalm_driver': 'ios',
'description': 'New description',
}

Expand Down
Loading