mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
2
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@ -17,7 +17,7 @@ body:
|
||||
What version of NetBox are you currently running? (If you don't have access to the most
|
||||
recent NetBox release, consider testing on our [demo instance](https://demo.netbox.dev/)
|
||||
before opening a bug report to see if your issue has already been addressed.)
|
||||
placeholder: v2.11.6
|
||||
placeholder: v2.11.7
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
|
2
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
2
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
@ -14,7 +14,7 @@ body:
|
||||
attributes:
|
||||
label: NetBox version
|
||||
description: What version of NetBox are you currently running?
|
||||
placeholder: v2.11.6
|
||||
placeholder: v2.11.7
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
|
@ -25,7 +25,7 @@ discussions.
|
||||
|
||||
### Slack
|
||||
|
||||
For real-time chat, you can join the **#netbox** Slack channel on [NetDev Community](https://slack.netbox.dev/).
|
||||
For real-time chat, you can join the **#netbox** Slack channel on [NetDev Community](https://netdev.chat/).
|
||||
Unfortunately, the Slack channel does not provide long-term retention of chat
|
||||
history, so try to avoid it for any discussions would benefit from being
|
||||
preserved for future reference.
|
||||
|
17
README.md
17
README.md
@ -2,8 +2,10 @@
|
||||
<img src="https://raw.githubusercontent.com/netbox-community/netbox/develop/docs/netbox_logo.svg" width="400" alt="NetBox logo" />
|
||||
</div>
|
||||
|
||||
NetBox is an IP address management (IPAM) and data center infrastructure
|
||||
management (DCIM) tool. Initially conceived by the network engineering team at
|
||||

|
||||
|
||||
NetBox is an infrastructure resource modeling (IRM) tool designed to empower
|
||||
network automation. Initially conceived by the network engineering team at
|
||||
[DigitalOcean](https://www.digitalocean.com/), NetBox was developed specifically
|
||||
to address the needs of network and infrastructure engineers. It is intended to
|
||||
function as a domain-specific source of truth for network operations.
|
||||
@ -14,18 +16,15 @@ complete list of requirements, see `requirements.txt`. The code is available [on
|
||||
|
||||
The complete documentation for NetBox can be found at [Read the Docs](https://netbox.readthedocs.io/en/stable/). A public demo instance is available at https://demo.netbox.dev.
|
||||
|
||||
| | status |
|
||||
|-------------|------------|
|
||||
| **master** |  |
|
||||
| **develop** |  |
|
||||
|
||||
<div align="center">
|
||||
<h4>Thank you to our sponsors!</h4>
|
||||
|
||||
[](https://try.digitalocean.com/developer-cloud)
|
||||
|
||||
[](https://ns1.com/)
|
||||
[](https://metal.equinix.com/)
|
||||
|
||||
[](https://ns1.com/)
|
||||
<br />
|
||||
[](https://stellar.tech/)
|
||||
|
||||
</div>
|
||||
@ -33,7 +32,7 @@ The complete documentation for NetBox can be found at [Read the Docs](https://ne
|
||||
### Discussion
|
||||
|
||||
* [GitHub Discussions](https://github.com/netbox-community/netbox/discussions) - Discussion forum hosted by GitHub; ideal for Q&A and other structured discussions
|
||||
* [Slack](https://slack.netbox.dev/) - Real-time chat hosted by the NetDev Community; best for unstructured discussion or just hanging out
|
||||
* [Slack](https://netdev.chat/) - Real-time chat hosted by the NetDev Community; best for unstructured discussion or just hanging out
|
||||
* [Google Group](https://groups.google.com/g/netbox-discuss) - Legacy mailing list; slowly being replaced by GitHub discussions
|
||||
|
||||
### Installation
|
||||
|
@ -24,7 +24,7 @@ Marking a field as required will force the user to provide a value for the field
|
||||
|
||||
The filter logic controls how values are matched when filtering objects by the custom field. Loose filtering (the default) matches on a partial value, whereas exact matching requires a complete match of the given string to a field's value. For example, exact filtering with the string "red" will only match the exact value "red", whereas loose filtering will match on the values "red", "red-orange", or "bored". Setting the filter logic to "disabled" disables filtering by the field entirely.
|
||||
|
||||
A custom field must be assigned to one or object types, or models, in NetBox. Once created, custom fields will automatically appear as part of these models in the web UI and REST API. Note that not all models support custom fields.
|
||||
A custom field must be assigned to one or more object types, or models, in NetBox. Once created, custom fields will automatically appear as part of these models in the web UI and REST API. Note that not all models support custom fields.
|
||||
|
||||
### Custom Field Validation
|
||||
|
||||
|
@ -8,7 +8,7 @@ There are several official forums for communication among the developers and com
|
||||
|
||||
* [GitHub issues](https://github.com/netbox-community/netbox/issues) - All feature requests, bug reports, and other substantial changes to the code base **must** be documented in an issue.
|
||||
* [GitHub Discussions](https://github.com/netbox-community/netbox/discussions) - The preferred forum for general discussion and support issues. Ideal for shaping a feature request prior to submitting an issue.
|
||||
* [#netbox on NetDev Community Slack](https://slack.netbox.dev/) - Good for quick chats. Avoid any discussion that might need to be referenced later on, as the chat history is not retained long.
|
||||
* [#netbox on NetDev Community Slack](https://netdev.chat/) - Good for quick chats. Avoid any discussion that might need to be referenced later on, as the chat history is not retained long.
|
||||
* [Google Group](https://groups.google.com/g/netbox-discuss) - Legacy mailing list; slowly being phased out in favor of GitHub discussions.
|
||||
|
||||
## Governance
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
# What is NetBox?
|
||||
|
||||
NetBox is an open source web application designed to help manage and document computer networks. Initially conceived by the network engineering team at [DigitalOcean](https://www.digitalocean.com/), NetBox was developed specifically to address the needs of network and infrastructure engineers. It encompasses the following aspects of network management:
|
||||
NetBox is an infrastructure resource modeling (IRM) application designed to empower network automation. Initially conceived by the network engineering team at [DigitalOcean](https://www.digitalocean.com/), NetBox was developed specifically to address the needs of network and infrastructure engineers. NetBox is made available as open source under the Apache 2 license. It encompasses the following aspects of network management:
|
||||
|
||||
* **IP address management (IPAM)** - IP networks and addresses, VRFs, and VLANs
|
||||
* **Equipment racks** - Organized by group and site
|
||||
|
@ -1,5 +1,25 @@
|
||||
# NetBox v2.11
|
||||
|
||||
## v2.11.7 (2021-06-16)
|
||||
|
||||
### Enhancements
|
||||
|
||||
* [#6455](https://github.com/netbox-community/netbox/issues/6455) - Permit /32 IPv4 and /128 IPv6 prefixes
|
||||
* [#6493](https://github.com/netbox-community/netbox/issues/6493) - Show change log diff for non-atomic (pre-2.11) changes
|
||||
* [#6564](https://github.com/netbox-community/netbox/issues/6564) - Add N connector type for pass-through ports
|
||||
* [#6588](https://github.com/netbox-community/netbox/issues/6588) - Add support for webp files as front/rear device type images
|
||||
* [#6589](https://github.com/netbox-community/netbox/issues/6589) - Standardize breadcrumb navigation for power panels and feeds
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* [#6553](https://github.com/netbox-community/netbox/issues/6553) - ProviderNetwork search should match on name
|
||||
* [#6562](https://github.com/netbox-community/netbox/issues/6562) - Disable ordering of secrets by assigned object
|
||||
* [#6563](https://github.com/netbox-community/netbox/issues/6563) - Fix filtering by location for cable connection forms
|
||||
* [#6584](https://github.com/netbox-community/netbox/issues/6584) - Fix ordering of nested inventory items
|
||||
* [#6602](https://github.com/netbox-community/netbox/issues/6602) - Fix deletion of devices with cables attached
|
||||
|
||||
---
|
||||
|
||||
## v2.11.6 (2021-06-04)
|
||||
|
||||
### Bug Fixes
|
||||
|
@ -104,6 +104,7 @@ class ProviderNetworkFilterSet(PrimaryModelFilterSet):
|
||||
if not value.strip():
|
||||
return queryset
|
||||
return queryset.filter(
|
||||
Q(name__icontains=value) |
|
||||
Q(description__icontains=value) |
|
||||
Q(comments__icontains=value)
|
||||
).distinct()
|
||||
|
@ -924,6 +924,7 @@ class PortTypeChoices(ChoiceSet):
|
||||
TYPE_110_PUNCH = '110-punch'
|
||||
TYPE_BNC = 'bnc'
|
||||
TYPE_F = 'f'
|
||||
TYPE_N = 'n'
|
||||
TYPE_MRJ21 = 'mrj21'
|
||||
TYPE_ST = 'st'
|
||||
TYPE_SC = 'sc'
|
||||
@ -954,6 +955,7 @@ class PortTypeChoices(ChoiceSet):
|
||||
(TYPE_110_PUNCH, '110 Punch'),
|
||||
(TYPE_BNC, 'BNC'),
|
||||
(TYPE_F, 'F Connector'),
|
||||
(TYPE_N, 'N Connector'),
|
||||
(TYPE_MRJ21, 'MRJ21'),
|
||||
),
|
||||
),
|
||||
|
@ -2,6 +2,9 @@ from django.db.models import Q
|
||||
|
||||
from .choices import InterfaceTypeChoices
|
||||
|
||||
# Exclude SVG images (unsupported by PIL)
|
||||
DEVICETYPE_IMAGE_FORMATS = 'image/bmp,image/gif,image/jpeg,image/png,image/tiff,image/webp'
|
||||
|
||||
|
||||
#
|
||||
# Racks
|
||||
|
@ -1172,12 +1172,11 @@ class DeviceTypeForm(BootstrapMixin, CustomFieldModelForm):
|
||||
)
|
||||
widgets = {
|
||||
'subdevice_role': StaticSelect2(),
|
||||
# Exclude SVG images (unsupported by PIL)
|
||||
'front_image': forms.ClearableFileInput(attrs={
|
||||
'accept': 'image/bmp,image/gif,image/jpeg,image/png,image/tiff'
|
||||
'accept': DEVICETYPE_IMAGE_FORMATS
|
||||
}),
|
||||
'rear_image': forms.ClearableFileInput(attrs={
|
||||
'accept': 'image/bmp,image/gif,image/jpeg,image/png,image/tiff'
|
||||
'accept': DEVICETYPE_IMAGE_FORMATS
|
||||
})
|
||||
}
|
||||
|
||||
@ -3948,6 +3947,7 @@ class ConnectCableToDeviceForm(BootstrapMixin, CustomFieldModelForm):
|
||||
required=False,
|
||||
query_params={
|
||||
'site_id': '$termination_b_site',
|
||||
'location_id': '$termination_b_location',
|
||||
'rack_id': '$termination_b_rack',
|
||||
}
|
||||
)
|
||||
|
@ -146,14 +146,12 @@ def nullify_connected_endpoints(instance, **kwargs):
|
||||
# Disassociate the Cable from its termination points
|
||||
if instance.termination_a is not None:
|
||||
logger.debug(f"Nullifying termination A for cable {instance}")
|
||||
instance.termination_a.cable = None
|
||||
instance.termination_a._cable_peer = None
|
||||
instance.termination_a.save()
|
||||
model = instance.termination_a._meta.model
|
||||
model.objects.filter(pk=instance.termination_a.pk).update(_cable_peer_type=None, _cable_peer_id=None)
|
||||
if instance.termination_b is not None:
|
||||
logger.debug(f"Nullifying termination B for cable {instance}")
|
||||
instance.termination_b.cable = None
|
||||
instance.termination_b._cable_peer = None
|
||||
instance.termination_b.save()
|
||||
model = instance.termination_b._meta.model
|
||||
model.objects.filter(pk=instance.termination_b.pk).update(_cable_peer_type=None, _cable_peer_id=None)
|
||||
|
||||
# Delete and retrace any dependent cable paths
|
||||
for cablepath in CablePath.objects.filter(path__contains=instance):
|
||||
|
@ -694,7 +694,7 @@ class InventoryItemTable(DeviceComponentTable):
|
||||
)
|
||||
cable = None # Override DeviceComponentTable
|
||||
|
||||
class Meta(DeviceComponentTable.Meta):
|
||||
class Meta(BaseTable.Meta):
|
||||
model = InventoryItem
|
||||
fields = (
|
||||
'pk', 'device', 'name', 'label', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'description',
|
||||
@ -715,7 +715,7 @@ class DeviceInventoryItemTable(InventoryItemTable):
|
||||
buttons=('edit', 'delete')
|
||||
)
|
||||
|
||||
class Meta(DeviceComponentTable.Meta):
|
||||
class Meta(BaseTable.Meta):
|
||||
model = InventoryItem
|
||||
fields = (
|
||||
'pk', 'name', 'label', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'description', 'discovered',
|
||||
|
@ -202,15 +202,22 @@ class ObjectChangeView(generic.ObjectView):
|
||||
next_change = objectchanges.filter(time__gt=instance.time).order_by('time').first()
|
||||
prev_change = objectchanges.filter(time__lt=instance.time).order_by('-time').first()
|
||||
|
||||
if instance.prechange_data and instance.postchange_data:
|
||||
if not instance.prechange_data and instance.action in ['update', 'delete'] and prev_change:
|
||||
non_atomic_change = True
|
||||
prechange_data = prev_change.postchange_data
|
||||
else:
|
||||
non_atomic_change = False
|
||||
prechange_data = instance.prechange_data
|
||||
|
||||
if prechange_data and instance.postchange_data:
|
||||
diff_added = shallow_compare_dict(
|
||||
instance.prechange_data or dict(),
|
||||
prechange_data or dict(),
|
||||
instance.postchange_data or dict(),
|
||||
exclude=['last_updated'],
|
||||
)
|
||||
diff_removed = {
|
||||
x: instance.prechange_data.get(x) for x in diff_added
|
||||
} if instance.prechange_data else {}
|
||||
x: prechange_data.get(x) for x in diff_added
|
||||
} if prechange_data else {}
|
||||
else:
|
||||
diff_added = None
|
||||
diff_removed = None
|
||||
@ -221,7 +228,8 @@ class ObjectChangeView(generic.ObjectView):
|
||||
'next_change': next_change,
|
||||
'prev_change': prev_change,
|
||||
'related_changes_table': related_changes_table,
|
||||
'related_changes_count': related_changes.count()
|
||||
'related_changes_count': related_changes.count(),
|
||||
'non_atomic_change': non_atomic_change
|
||||
}
|
||||
|
||||
|
||||
|
@ -340,16 +340,6 @@ class Prefix(PrimaryModel):
|
||||
'prefix': "Cannot create prefix with /0 mask."
|
||||
})
|
||||
|
||||
# Disallow host masks
|
||||
if self.prefix.version == 4 and self.prefix.prefixlen == 32:
|
||||
raise ValidationError({
|
||||
'prefix': "Cannot create host addresses (/32) as prefixes. Create an IPv4 address instead."
|
||||
})
|
||||
elif self.prefix.version == 6 and self.prefix.prefixlen == 128:
|
||||
raise ValidationError({
|
||||
'prefix': "Cannot create host addresses (/128) as prefixes. Create an IPv6 address instead."
|
||||
})
|
||||
|
||||
# Enforce unique IP space (if applicable)
|
||||
if (self.vrf is None and settings.ENFORCE_GLOBAL_UNIQUE) or (self.vrf and self.vrf.enforce_unique):
|
||||
duplicate_prefixes = self.get_duplicates()
|
||||
@ -471,8 +461,8 @@ class Prefix(PrimaryModel):
|
||||
child_ips = netaddr.IPSet([ip.address.ip for ip in self.get_child_ips()])
|
||||
available_ips = prefix - child_ips
|
||||
|
||||
# IPv6, pool, or IPv4 /31 sets are fully usable
|
||||
if self.family == 6 or self.is_pool or self.prefix.prefixlen == 31:
|
||||
# IPv6, pool, or IPv4 /31-/32 sets are fully usable
|
||||
if self.family == 6 or self.is_pool or (self.family == 4 and self.prefix.prefixlen >= 31):
|
||||
return available_ips
|
||||
|
||||
# For "normal" IPv4 prefixes, omit first and last addresses
|
||||
|
@ -522,7 +522,7 @@ class IPAddressView(generic.ObjectView):
|
||||
# Parent prefixes table
|
||||
parent_prefixes = Prefix.objects.restrict(request.user, 'view').filter(
|
||||
vrf=instance.vrf,
|
||||
prefix__net_contains=str(instance.address.ip)
|
||||
prefix__net_contains_or_equals=str(instance.address.ip)
|
||||
).prefetch_related(
|
||||
'site', 'role'
|
||||
)
|
||||
|
@ -16,7 +16,7 @@ from django.core.validators import URLValidator
|
||||
# Environment setup
|
||||
#
|
||||
|
||||
VERSION = '2.11.6'
|
||||
VERSION = '2.11.7'
|
||||
|
||||
# Hostname
|
||||
HOSTNAME = platform.node()
|
||||
|
@ -37,6 +37,7 @@ class SecretTable(BaseTable):
|
||||
)
|
||||
assigned_object = tables.Column(
|
||||
linkify=True,
|
||||
orderable=False,
|
||||
verbose_name='Assigned object'
|
||||
)
|
||||
role = tables.Column(
|
||||
|
@ -7,10 +7,10 @@
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<li><a href="{% url 'dcim:powerfeed_list' %}">Power Feeds</a></li>
|
||||
<li><a href="{{ object.power_panel.site.get_absolute_url }}">{{ object.power_panel.site }}</a></li>
|
||||
<li><a href="{{ object.power_panel.get_absolute_url }}">{{ object.power_panel }}</a></li>
|
||||
<li><a href="{% url 'dcim:powerfeed_list' %}?site_id={{ object.power_panel.site.pk }}">{{ object.power_panel.site }}</a></li>
|
||||
<li><a href="{% url 'dcim:powerfeed_list' %}?power_panel_id={{ object.power_panel.pk }}">{{ object.power_panel }}</a></li>
|
||||
{% if object.rack %}
|
||||
<li><a href="{{ object.rack.get_absolute_url }}">{{ object.rack }}</a></li>
|
||||
<li><a href="{% url 'dcim:powerfeed_list' %}?rack_id={{ object.rack.pk }}">{{ object.rack }}</a></li>
|
||||
{% endif %}
|
||||
<li>{{ object }}</li>
|
||||
{% endblock %}
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<li><a href="{% url 'dcim:powerpanel_list' %}">Power Panels</a></li>
|
||||
<li><a href="{{ object.site.get_absolute_url }}">{{ object.site }}</a></li>
|
||||
<li><a href="{% url 'dcim:powerpanel_list' %}?site_id={{ object.site.pk }}">{{ object.site }}</a></li>
|
||||
{% if object.location %}
|
||||
<li><a href="{{ object.location.get_absolute_url }}">{{ object.location }}</a></li>
|
||||
{% endif %}
|
||||
|
@ -128,6 +128,8 @@
|
||||
<span{% if k in diff_removed %} style="background-color: #ffdce0"{% endif %}>{{ k }}: {{ v|render_json }}</span>
|
||||
{% endspaceless %}
|
||||
{% endfor %}</pre>
|
||||
{% elif non_atomic_change %}
|
||||
Warning: Comparing non-atomic change to previous change record (<a href="{% url 'extras:objectchange' pk=prev_change.pk %}">{{ prev_change.pk }}</a>)
|
||||
{% else %}
|
||||
<span class="text-muted">None</span>
|
||||
{% endif %}
|
||||
|
@ -340,8 +340,11 @@ class MPTTColumn(tables.TemplateColumn):
|
||||
"""
|
||||
Display a nested hierarchy for MPTT-enabled models.
|
||||
"""
|
||||
template_code = """{% for i in record.get_ancestors %}<i class="mdi mdi-circle-small"></i>{% endfor %}""" \
|
||||
"""<a href="{{ record.get_absolute_url }}">{{ record.name }}</a>"""
|
||||
template_code = """
|
||||
{% load helpers %}
|
||||
{% for i in record.level|as_range %}<i class="mdi mdi-circle-small"></i>{% endfor %}
|
||||
<a href="{{ record.get_absolute_url }}">{{ record.name }}</a>
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(
|
||||
|
@ -17,7 +17,7 @@ Jinja2==3.0.1
|
||||
Markdown==3.3.4
|
||||
netaddr==0.8.0
|
||||
Pillow==8.2.0
|
||||
psycopg2-binary==2.8.6
|
||||
psycopg2-binary==2.9
|
||||
pycryptodome==3.10.1
|
||||
PyYAML==5.4.1
|
||||
svgwrite==1.4.1
|
||||
|
Reference in New Issue
Block a user