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

Release v3.0.5 #7437

Merged
merged 25 commits into from
Oct 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
19c984b
PRVB
jeremystretch Sep 29, 2021
47c3a20
Correct version number referenced for installation video
jeremystretch Sep 29, 2021
14b065c
Fixes #7373: Improve handling of mismatched server, client, and brows…
thatmattlove Sep 30, 2021
1f1a05d
Fixes #6895: Remove errant markup for null values in CSV export
jeremystretch Sep 30, 2021
a9761e8
Fixes #7397: Fix AttributeError exception when rendering export templ…
jeremystretch Sep 30, 2021
0fdd081
feat: scripts within a module can now be ordered
maximumG Sep 30, 2021
7337630
chore: introduce the script_order notion in the documentation
maximumG Sep 30, 2021
d9f178e
Fixes #7411: Fix exception in UI when adding member devices to virtua…
jeremystretch Sep 30, 2021
114500e
Fixes #7401: Pin jsonschema package to v3.2.0 to fix REST API docs re…
jeremystretch Sep 30, 2021
a5b99e7
Fixes #7412: Fix exception in UI when adding child device to device bay
jeremystretch Sep 30, 2021
d1f5988
Closes #7319: Remove migrations check from upgrade.sh to avoid mislea…
jeremystretch Oct 1, 2021
bd181ac
Merge pull request #7400 from maximumG/7387-order-scripts
jeremystretch Oct 1, 2021
ed3bc7c
Changelog for #7387
jeremystretch Oct 1, 2021
257c0af
Closes #6423: Cache rendered REST API specifications
jeremystretch Oct 1, 2021
460e3fd
Introduce a common URL for the creation of image attachments
jeremystretch Oct 1, 2021
357a5d1
Refactor image attachments panel template
jeremystretch Oct 1, 2021
f3fe3f9
Closes #6708: Add image attachment support for circuits, power panels
jeremystretch Oct 1, 2021
724997c
Closes #5925: Always show IP addresses tab under prefix view
jeremystretch Oct 1, 2021
a1f271d
Fixes #7417: Prevent exception when filtering objects list by invalid…
jeremystretch Oct 1, 2021
376c776
Fixes #7425: Housekeeping command should honor zero verbosity
jeremystretch Oct 1, 2021
1be748b
Fixes #6433: Fix bulk editing of child prefixes under aggregate view
jeremystretch Oct 1, 2021
c9c537a
Fixes #6817: Custom field columns should be removed from tables upon …
jeremystretch Oct 2, 2021
c818d63
Fixes #7427: Don't select hidden rows when selecting all in a table
thatmattlove Oct 4, 2021
b5884a5
Fixes #7215: Prevent rack elevations from overlapping when higher wid…
jeremystretch Oct 4, 2021
339bcb8
Release v3.0.5
jeremystretch Oct 4, 2021
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: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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: v3.0.4
placeholder: v3.0.5
validations:
required: true
- type: dropdown
Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/feature_request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ body:
attributes:
label: NetBox version
description: What version of NetBox are you currently running?
placeholder: v3.0.4
placeholder: v3.0.5
validations:
required: true
- type: dropdown
Expand Down
14 changes: 14 additions & 0 deletions docs/customization/custom-scripts.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,20 @@ Defining script variables is optional: You may create a script with only a `run(

Any output generated by the script during its execution will be displayed under the "output" tab in the UI.

By default, scripts within a module are ordered alphabetically in the scripts list page. To return scripts in a specific order, you can define the `script_order` variable at the end of your module. The `script_order` variable is a tuple which contains each Script class in the desired order. Any scripts that are omitted from this list will be listed last.

```python
from extras.scripts import Script

class MyCustomScript(Script):
...

class AnotherCustomScript(Script):
...

script_order = (MyCustomScript, AnotherCustomScript)
```

## Module Attributes

### `name`
Expand Down
2 changes: 1 addition & 1 deletion docs/installation/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ The following sections detail how to set up a new instance of NetBox:
5. [HTTP server](5-http-server.md)
6. [LDAP authentication](6-ldap.md) (optional)

The video below demonstrates the installation of NetBox v2.10.3 on Ubuntu 20.04 for your reference.
The video below demonstrates the installation of NetBox v3.0 on Ubuntu 20.04 for your reference.

<iframe width="560" height="315" src="https://www.youtube.com/embed/7Fpd2-q9_28" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

Expand Down
28 changes: 28 additions & 0 deletions docs/release-notes/version-3.0.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
# NetBox v3.0

## v3.0.5 (2021-10-04)

### Enhancements

* [#5925](https://github.com/netbox-community/netbox/issues/5925) - Always show IP addresses tab under prefix view
* [#6423](https://github.com/netbox-community/netbox/issues/6423) - Cache rendered REST API specifications
* [#6708](https://github.com/netbox-community/netbox/issues/6708) - Add image attachment support for circuits, power panels
* [#7387](https://github.com/netbox-community/netbox/issues/7387) - Enable arbitrary ordering of custom scripts
* [#7427](https://github.com/netbox-community/netbox/issues/7427) - Don't select hidden rows when selecting all in a table

### Bug Fixes

* [#6433](https://github.com/netbox-community/netbox/issues/6433) - Fix bulk editing of child prefixes under aggregate view
* [#6817](https://github.com/netbox-community/netbox/issues/6817) - Custom field columns should be removed from tables upon their deletion
* [#6895](https://github.com/netbox-community/netbox/issues/6895) - Remove errant markup for null values in CSV export
* [#7215](https://github.com/netbox-community/netbox/issues/7215) - Prevent rack elevations from overlapping when higher width is specified
* [#7373](https://github.com/netbox-community/netbox/issues/7373) - Fix flashing when server, client, and browser color-mode preferences are mismatched
* [#7397](https://github.com/netbox-community/netbox/issues/7397) - Fix AttributeError exception when rendering export template for devices via REST API
* [#7401](https://github.com/netbox-community/netbox/issues/7401) - Pin `jsonschema` package to v3.2.0 to fix REST API docs rendering
* [#7411](https://github.com/netbox-community/netbox/issues/7411) - Fix exception in UI when adding member devices to virtual chassis
* [#7412](https://github.com/netbox-community/netbox/issues/7412) - Fix exception in UI when adding child device to device bay
* [#7417](https://github.com/netbox-community/netbox/issues/7417) - Prevent exception when filtering objects list by invalid tag
* [#7425](https://github.com/netbox-community/netbox/issues/7425) - Housekeeping command should honor zero verbosity

---

## v3.0.4 (2021-09-29)

### Enhancements
Expand Down Expand Up @@ -30,6 +56,8 @@
* [#7374](https://github.com/netbox-community/netbox/issues/7374) - Add missing `face` parameter to API elevations request when editing device
* [#7392](https://github.com/netbox-community/netbox/issues/7392) - Fix "help" links for custom fields, other models

---

## v3.0.3 (2021-09-20)

### Enhancements
Expand Down
4 changes: 4 additions & 0 deletions netbox/circuits/models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.contrib.contenttypes.fields import GenericRelation
from django.core.exceptions import ValidationError
from django.db import models
from django.urls import reverse
Expand Down Expand Up @@ -202,6 +203,9 @@ class Circuit(PrimaryModel):
comments = models.TextField(
blank=True
)
images = GenericRelation(
to='extras.ImageAttachment'
)

# Cache associated CircuitTerminations
termination_a = models.ForeignKey(
Expand Down
2 changes: 2 additions & 0 deletions netbox/dcim/forms/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
'LocationForm',
'ManufacturerForm',
'PlatformForm',
'PopulateDeviceBayForm',
'PowerFeedForm',
'PowerOutletForm',
'PowerOutletTemplateForm',
Expand All @@ -52,6 +53,7 @@
'RegionForm',
'SiteForm',
'SiteGroupForm',
'VCMemberSelectForm',
'VirtualChassisForm',
)

Expand Down
4 changes: 4 additions & 0 deletions netbox/dcim/models/power.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.contrib.contenttypes.fields import GenericRelation
from django.core.exceptions import ValidationError
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
Expand Down Expand Up @@ -39,6 +40,9 @@ class PowerPanel(PrimaryModel):
name = models.CharField(
max_length=100
)
images = GenericRelation(
to='extras.ImageAttachment'
)

objects = RestrictedQuerySet.as_manager()

Expand Down
4 changes: 2 additions & 2 deletions netbox/dcim/tables/cables.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from django_tables2.utils import Accessor

from dcim.models import Cable
from utilities.tables import BaseTable, ChoiceFieldColumn, ColorColumn, TagColumn, ToggleColumn
from utilities.tables import BaseTable, ChoiceFieldColumn, ColorColumn, TagColumn, TemplateColumn, ToggleColumn
from .template_code import CABLE_LENGTH, CABLE_TERMINATION_PARENT

__all__ = (
Expand Down Expand Up @@ -45,7 +45,7 @@ class CableTable(BaseTable):
verbose_name='Termination B'
)
status = ChoiceFieldColumn()
length = tables.TemplateColumn(
length = TemplateColumn(
template_code=CABLE_LENGTH,
order_by='_abs_length'
)
Expand Down
8 changes: 4 additions & 4 deletions netbox/dcim/tables/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from tenancy.tables import TenantColumn
from utilities.tables import (
BaseTable, BooleanColumn, ButtonsColumn, ChoiceFieldColumn, ColorColumn, ColoredLabelColumn, LinkedCountColumn,
MarkdownColumn, TagColumn, ToggleColumn,
MarkdownColumn, TagColumn, TemplateColumn, ToggleColumn,
)
from .template_code import (
CABLETERMINATION, CONSOLEPORT_BUTTONS, CONSOLESERVERPORT_BUTTONS, DEVICE_LINK, DEVICEBAY_BUTTONS, DEVICEBAY_STATUS,
Expand Down Expand Up @@ -258,7 +258,7 @@ class CableTerminationTable(BaseTable):
orderable=False,
verbose_name='Cable Color'
)
cable_peer = tables.TemplateColumn(
cable_peer = TemplateColumn(
accessor='_cable_peer',
template_code=CABLETERMINATION,
orderable=False,
Expand All @@ -268,7 +268,7 @@ class CableTerminationTable(BaseTable):


class PathEndpointTable(CableTerminationTable):
connection = tables.TemplateColumn(
connection = TemplateColumn(
accessor='_path.last_node',
template_code=CABLETERMINATION,
verbose_name='Connection',
Expand Down Expand Up @@ -470,7 +470,7 @@ class BaseInterfaceTable(BaseTable):
verbose_name='IP Addresses'
)
untagged_vlan = tables.Column(linkify=True)
tagged_vlans = tables.TemplateColumn(
tagged_vlans = TemplateColumn(
template_code=INTERFACE_TAGGED_VLANS,
orderable=False,
verbose_name='Tagged VLANs'
Expand Down
6 changes: 1 addition & 5 deletions netbox/dcim/tables/template_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@
<i class="mdi mdi-chevron-right"></i>
{% endif %}
<a href="{{ value.get_absolute_url }}">{{ value }}</a>
{% else %}
&mdash;
{% endif %}
"""

CABLE_LENGTH = """
{% if record.length %}{{ record.length }} {{ record.get_length_unit_display }}{% else %}&mdash;{% endif %}
{% if record.length %}{{ record.length }} {{ record.get_length_unit_display }}{% endif %}
"""

CABLE_TERMINATION_PARENT = """
Expand Down Expand Up @@ -63,8 +61,6 @@
{% endfor %}
{% elif record.mode == 'tagged-all' %}
All
{% else %}
&mdash;
{% endif %}
"""

Expand Down
6 changes: 1 addition & 5 deletions netbox/dcim/urls.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django.urls import path

from extras.views import ImageAttachmentEditView, ObjectChangeLogView, ObjectJournalView
from extras.views import ObjectChangeLogView, ObjectJournalView
from ipam.views import ServiceEditView
from utilities.views import SlugRedirectView
from . import views
Expand Down Expand Up @@ -43,7 +43,6 @@
path('sites/<int:pk>/delete/', views.SiteDeleteView.as_view(), name='site_delete'),
path('sites/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='site_changelog', kwargs={'model': Site}),
path('sites/<int:pk>/journal/', ObjectJournalView.as_view(), name='site_journal', kwargs={'model': Site}),
path('sites/<int:object_id>/images/add/', ImageAttachmentEditView.as_view(), name='site_add_image', kwargs={'model': Site}),

# Locations
path('locations/', views.LocationListView.as_view(), name='location_list'),
Expand All @@ -55,7 +54,6 @@
path('locations/<int:pk>/edit/', views.LocationEditView.as_view(), name='location_edit'),
path('locations/<int:pk>/delete/', views.LocationDeleteView.as_view(), name='location_delete'),
path('locations/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='location_changelog', kwargs={'model': Location}),
path('locations/<int:object_id>/images/add/', ImageAttachmentEditView.as_view(), name='location_add_image', kwargs={'model': Location}),

# Rack roles
path('rack-roles/', views.RackRoleListView.as_view(), name='rackrole_list'),
Expand Down Expand Up @@ -92,7 +90,6 @@
path('racks/<int:pk>/delete/', views.RackDeleteView.as_view(), name='rack_delete'),
path('racks/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='rack_changelog', kwargs={'model': Rack}),
path('racks/<int:pk>/journal/', ObjectJournalView.as_view(), name='rack_journal', kwargs={'model': Rack}),
path('racks/<int:object_id>/images/add/', ImageAttachmentEditView.as_view(), name='rack_add_image', kwargs={'model': Rack}),

# Manufacturers
path('manufacturers/', views.ManufacturerListView.as_view(), name='manufacturer_list'),
Expand Down Expand Up @@ -229,7 +226,6 @@
path('devices/<int:pk>/lldp-neighbors/', views.DeviceLLDPNeighborsView.as_view(), name='device_lldp_neighbors'),
path('devices/<int:pk>/config/', views.DeviceConfigView.as_view(), name='device_config'),
path('devices/<int:device>/services/assign/', ServiceEditView.as_view(), name='device_service_assign'),
path('devices/<int:object_id>/images/add/', ImageAttachmentEditView.as_view(), name='device_add_image', kwargs={'model': Device}),

# Console ports
path('console-ports/', views.ConsolePortListView.as_view(), name='consoleport_list'),
Expand Down
62 changes: 39 additions & 23 deletions netbox/extras/management/commands/housekeeping.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,48 +18,60 @@ class Command(BaseCommand):
def handle(self, *args, **options):

# Clear expired authentication sessions (essentially replicating the `clearsessions` command)
self.stdout.write("[*] Clearing expired authentication sessions")
if options['verbosity'] >= 2:
self.stdout.write(f"\tConfigured session engine: {settings.SESSION_ENGINE}")
if options['verbosity']:
self.stdout.write("[*] Clearing expired authentication sessions")
if options['verbosity'] >= 2:
self.stdout.write(f"\tConfigured session engine: {settings.SESSION_ENGINE}")
engine = import_module(settings.SESSION_ENGINE)
try:
engine.SessionStore.clear_expired()
self.stdout.write("\tSessions cleared.", self.style.SUCCESS)
if options['verbosity']:
self.stdout.write("\tSessions cleared.", self.style.SUCCESS)
except NotImplementedError:
self.stdout.write(
f"\tThe configured session engine ({settings.SESSION_ENGINE}) does not support "
f"clearing sessions; skipping."
)
if options['verbosity']:
self.stdout.write(
f"\tThe configured session engine ({settings.SESSION_ENGINE}) does not support "
f"clearing sessions; skipping."
)

# Delete expired ObjectRecords
self.stdout.write("[*] Checking for expired changelog records")
if options['verbosity']:
self.stdout.write("[*] Checking for expired changelog records")
if settings.CHANGELOG_RETENTION:
cutoff = timezone.now() - timedelta(days=settings.CHANGELOG_RETENTION)
if options['verbosity'] >= 2:
self.stdout.write(f"Retention period: {settings.CHANGELOG_RETENTION} days")
self.stdout.write(f"\tRetention period: {settings.CHANGELOG_RETENTION} days")
self.stdout.write(f"\tCut-off time: {cutoff}")
expired_records = ObjectChange.objects.filter(time__lt=cutoff).count()
if expired_records:
self.stdout.write(f"\tDeleting {expired_records} expired records... ", self.style.WARNING, ending="")
self.stdout.flush()
if options['verbosity']:
self.stdout.write(
f"\tDeleting {expired_records} expired records... ",
self.style.WARNING,
ending=""
)
self.stdout.flush()
ObjectChange.objects.filter(time__lt=cutoff)._raw_delete(using=DEFAULT_DB_ALIAS)
self.stdout.write("Done.", self.style.WARNING)
else:
self.stdout.write("\tNo expired records found.")
else:
if options['verbosity']:
self.stdout.write("Done.", self.style.SUCCESS)
elif options['verbosity']:
self.stdout.write("\tNo expired records found.", self.style.SUCCESS)
elif options['verbosity']:
self.stdout.write(
f"\tSkipping: No retention period specified (CHANGELOG_RETENTION = {settings.CHANGELOG_RETENTION})"
)

# Check for new releases (if enabled)
self.stdout.write("[*] Checking for latest release")
if options['verbosity']:
self.stdout.write("[*] Checking for latest release")
if settings.RELEASE_CHECK_URL:
headers = {
'Accept': 'application/vnd.github.v3+json',
}

try:
self.stdout.write(f"\tFetching {settings.RELEASE_CHECK_URL}")
if options['verbosity'] >= 2:
self.stdout.write(f"\tFetching {settings.RELEASE_CHECK_URL}")
response = requests.get(
url=settings.RELEASE_CHECK_URL,
headers=headers,
Expand All @@ -73,15 +85,19 @@ def handle(self, *args, **options):
continue
releases.append((version.parse(release['tag_name']), release.get('html_url')))
latest_release = max(releases)
self.stdout.write(f"\tFound {len(response.json())} releases; {len(releases)} usable")
self.stdout.write(f"\tLatest release: {latest_release[0]}")
if options['verbosity'] >= 2:
self.stdout.write(f"\tFound {len(response.json())} releases; {len(releases)} usable")
if options['verbosity']:
self.stdout.write(f"\tLatest release: {latest_release[0]}", self.style.SUCCESS)

# Cache the most recent release
cache.set('latest_release', latest_release, None)

except requests.exceptions.RequestException as exc:
self.stdout.write(f"\tRequest error: {exc}")
self.stdout.write(f"\tRequest error: {exc}", self.style.ERROR)
else:
self.stdout.write(f"\tSkipping: RELEASE_CHECK_URL not set")
if options['verbosity']:
self.stdout.write(f"\tSkipping: RELEASE_CHECK_URL not set")

self.stdout.write("Finished.", self.style.SUCCESS)
if options['verbosity']:
self.stdout.write("Finished.", self.style.SUCCESS)
8 changes: 5 additions & 3 deletions netbox/extras/scripts.py
Original file line number Diff line number Diff line change
Expand Up @@ -470,16 +470,18 @@ def get_scripts(use_names=False):
defined name in place of the actual module name.
"""
scripts = OrderedDict()

# Iterate through all modules within the reports path. These are the user-created files in which reports are
# defined.
for importer, module_name, _ in pkgutil.iter_modules([settings.SCRIPTS_ROOT]):
module = importer.find_module(module_name).load_module(module_name)
if use_names and hasattr(module, 'name'):
module_name = module.name
module_scripts = OrderedDict()
for name, cls in inspect.getmembers(module, is_script):
module_scripts[name] = cls
script_order = getattr(module, "script_order", ())
ordered_scripts = [cls for cls in script_order if is_script(cls)]
unordered_scripts = [cls for _, cls in inspect.getmembers(module, is_script) if cls not in script_order]
for cls in [*ordered_scripts, *unordered_scripts]:
module_scripts[cls.__name__] = cls
if module_scripts:
scripts[module_name] = module_scripts

Expand Down
1 change: 1 addition & 0 deletions netbox/extras/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
kwargs={'model': models.ConfigContext}),

# Image attachments
path('image-attachments/add/', views.ImageAttachmentEditView.as_view(), name='imageattachment_add'),
path('image-attachments/<int:pk>/edit/', views.ImageAttachmentEditView.as_view(), name='imageattachment_edit'),
path('image-attachments/<int:pk>/delete/', views.ImageAttachmentDeleteView.as_view(), name='imageattachment_delete'),

Expand Down
Loading