diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 0f617e8aa..d8099923f 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -8,7 +8,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v3 + - uses: actions/stale@v4 with: close-issue-message: > This issue has been automatically closed due to lack of activity. In an diff --git a/docs/media/installation/netbox_application_stack.png b/docs/media/installation/netbox_application_stack.png index e86344900..c860b964b 100644 Binary files a/docs/media/installation/netbox_application_stack.png and b/docs/media/installation/netbox_application_stack.png differ diff --git a/docs/release-notes/version-2.11.md b/docs/release-notes/version-2.11.md index 736807e2c..162bbaf13 100644 --- a/docs/release-notes/version-2.11.md +++ b/docs/release-notes/version-2.11.md @@ -1,5 +1,19 @@ # NetBox v2.11 +## v2.11.11 (FUTURE) + +### Enhancements + +* [#6883](https://github.com/netbox-community/netbox/issues/6883) - Add C21 & C22 power types + +### Bug Fixes + +* [#6740](https://github.com/netbox-community/netbox/issues/6740) - Add import button to VM interfaces list +* [#6892](https://github.com/netbox-community/netbox/issues/6892) - Fix validation of unit ranges when creating a rack reservation +* [#6902](https://github.com/netbox-community/netbox/issues/6902) - Populate device field when cloning device components + +--- + ## v2.11.10 (2021-07-28) ### Enhancements diff --git a/docs/rest-api/filtering.md b/docs/rest-api/filtering.md index 471beffee..45dfcfa36 100644 --- a/docs/rest-api/filtering.md +++ b/docs/rest-api/filtering.md @@ -69,6 +69,12 @@ Numeric based fields (ASN, VLAN ID, etc) support these lookup expressions: | `gt` | Greater than | | `gte` | Greater than or equal to | +Here is an example of a numeric field lookup expression that will return all VLANs with a VLAN ID greater than 900: + +```no-highlight +GET /api/ipam/vlans/?vid__gt=900 +``` + ### String Fields String based (char) fields (Name, Address, etc) support these lookup expressions: @@ -86,7 +92,17 @@ String based (char) fields (Name, Address, etc) support these lookup expressions | `nie` | Inverse exact match (case-insensitive) | | `empty` | Is empty (boolean) | +Here is an example of a lookup expression on a string field that will return all devices with `switch` in the name: + +```no-highlight +GET /api/dcim/devices/?name__ic=switch +``` + ### Foreign Keys & Other Fields Certain other fields, namely foreign key relationships support just the negation -expression: `n`. +expression: `n`. Here is an example of a lookup expression on a foreign key, it would return all the VLANs that don't have a VLAN Group ID of 3203: + +```no-highlight +GET /api/ipam/vlans/?group_id__n=3203 +``` diff --git a/netbox/dcim/choices.py b/netbox/dcim/choices.py index ede397dc9..1a7d72d7e 100644 --- a/netbox/dcim/choices.py +++ b/netbox/dcim/choices.py @@ -252,6 +252,7 @@ class PowerPortTypeChoices(ChoiceSet): TYPE_IEC_C14 = 'iec-60320-c14' TYPE_IEC_C16 = 'iec-60320-c16' TYPE_IEC_C20 = 'iec-60320-c20' + TYPE_IEC_C22 = 'iec-60320-c22' # IEC 60309 TYPE_IEC_PNE4H = 'iec-60309-p-n-e-4h' TYPE_IEC_PNE6H = 'iec-60309-p-n-e-6h' @@ -351,6 +352,7 @@ class PowerPortTypeChoices(ChoiceSet): (TYPE_IEC_C14, 'C14'), (TYPE_IEC_C16, 'C16'), (TYPE_IEC_C20, 'C20'), + (TYPE_IEC_C22, 'C22'), )), ('IEC 60309', ( (TYPE_IEC_PNE4H, 'P+N+E 4H'), @@ -467,6 +469,7 @@ class PowerOutletTypeChoices(ChoiceSet): TYPE_IEC_C13 = 'iec-60320-c13' TYPE_IEC_C15 = 'iec-60320-c15' TYPE_IEC_C19 = 'iec-60320-c19' + TYPE_IEC_C21 = 'iec-60320-c21' # IEC 60309 TYPE_IEC_PNE4H = 'iec-60309-p-n-e-4h' TYPE_IEC_PNE6H = 'iec-60309-p-n-e-6h' @@ -558,6 +561,7 @@ class PowerOutletTypeChoices(ChoiceSet): (TYPE_IEC_C13, 'C13'), (TYPE_IEC_C15, 'C15'), (TYPE_IEC_C19, 'C19'), + (TYPE_IEC_C21, 'C21'), )), ('IEC 60309', ( (TYPE_IEC_PNE4H, 'P+N+E 4H'), diff --git a/netbox/dcim/models/device_components.py b/netbox/dcim/models/device_components.py index bd1100870..6a81e2cf1 100644 --- a/netbox/dcim/models/device_components.py +++ b/netbox/dcim/models/device_components.py @@ -237,6 +237,8 @@ class ConsolePort(ComponentModel, CableTermination, PathEndpoint): help_text='Port speed in bits per second' ) + clone_fields = ['device', 'type', 'speed'] + class Meta: ordering = ('device', '_name') unique_together = ('device', 'name') @@ -267,6 +269,8 @@ class ConsoleServerPort(ComponentModel, CableTermination, PathEndpoint): help_text='Port speed in bits per second' ) + clone_fields = ['device', 'type', 'speed'] + class Meta: ordering = ('device', '_name') unique_together = ('device', 'name') @@ -303,6 +307,8 @@ class PowerPort(ComponentModel, CableTermination, PathEndpoint): help_text="Allocated power draw (watts)" ) + clone_fields = ['device', 'maximum_draw', 'allocated_draw'] + class Meta: ordering = ('device', '_name') unique_together = ('device', 'name') @@ -399,6 +405,8 @@ class PowerOutlet(ComponentModel, CableTermination, PathEndpoint): help_text="Phase (for three-phase feeds)" ) + clone_fields = ['device', 'type', 'power_port', 'feed_leg'] + class Meta: ordering = ('device', '_name') unique_together = ('device', 'name') @@ -525,6 +533,8 @@ class Interface(ComponentModel, BaseInterface, CableTermination, PathEndpoint): related_query_name='interface' ) + clone_fields = ['device', 'parent', 'lag', 'type', 'mgmt_only'] + class Meta: ordering = ('device', CollateAsChar('_name')) unique_together = ('device', 'name') @@ -641,6 +651,8 @@ class FrontPort(ComponentModel, CableTermination): ] ) + clone_fields = ['device', 'type'] + class Meta: ordering = ('device', '_name') unique_together = ( @@ -687,6 +699,7 @@ class RearPort(ComponentModel, CableTermination): MaxValueValidator(REARPORT_POSITIONS_MAX) ] ) + clone_fields = ['device', 'type', 'positions'] class Meta: ordering = ('device', '_name') @@ -724,6 +737,8 @@ class DeviceBay(ComponentModel): null=True ) + clone_fields = ['device'] + class Meta: ordering = ('device', '_name') unique_together = ('device', 'name') @@ -806,6 +821,8 @@ class InventoryItem(MPTTModel, ComponentModel): objects = TreeManager() + clone_fields = ['device', 'parent', 'manufacturer', 'part_id'] + class Meta: ordering = ('device__id', 'parent__id', '_name') unique_together = ('device', 'parent', 'name') diff --git a/netbox/utilities/forms/utils.py b/netbox/utilities/forms/utils.py index 503a2e8a0..90df55b9c 100644 --- a/netbox/utilities/forms/utils.py +++ b/netbox/utilities/forms/utils.py @@ -32,7 +32,10 @@ def parse_numeric_range(string, base=10): begin, end = dash_range.split('-') except ValueError: begin, end = dash_range, dash_range - begin, end = int(begin.strip(), base=base), int(end.strip(), base=base) + 1 + try: + begin, end = int(begin.strip(), base=base), int(end.strip(), base=base) + 1 + except ValueError: + raise forms.ValidationError(f'Range "{dash_range}" is invalid.') values.extend(range(begin, end)) return list(set(values)) @@ -64,7 +67,7 @@ def parse_alphanumeric_range(string): else: # Not a valid range (more than a single character) if not len(begin) == len(end) == 1: - raise forms.ValidationError('Range "{}" is invalid.'.format(dash_range)) + raise forms.ValidationError(f'Range "{dash_range}" is invalid.') for n in list(range(ord(begin), ord(end) + 1)): values.append(chr(n)) return values diff --git a/netbox/virtualization/views.py b/netbox/virtualization/views.py index 7e3025aa7..fb2020c9d 100644 --- a/netbox/virtualization/views.py +++ b/netbox/virtualization/views.py @@ -409,7 +409,7 @@ class VMInterfaceListView(generic.ObjectListView): filterset = filtersets.VMInterfaceFilterSet filterset_form = forms.VMInterfaceFilterForm table = tables.VMInterfaceTable - action_buttons = ('export',) + action_buttons = ('import', 'export') class VMInterfaceView(generic.ObjectView):